From 2f255952b71e485559e74728afd9de120b619f83 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 13 Apr 2020 15:10:27 +0300 Subject: [PATCH 001/351] Updated to version v0.3.1 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 2f4efd536..9e29056fe 100644 --- a/version/version.go +++ b/version/version.go @@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 appMinor uint = 3 - appPatch uint = 0 + appPatch uint = 1 ) // appBuild is defined as a variable so it can be overridden during the build From 3fd647b291780acfde87955b903cc83ccfe628bc Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 13 Apr 2020 15:49:46 +0300 Subject: [PATCH 002/351] [NOD-858] Don't switch sync peer if the syncing process hasn't yet started with the current sync peer (#700) * [NOD-858] Don't switch sync peer if the syncing process hasn't yet started with the current sync peer * [NOD-858] SetShouldSendBlockLocator(false) on OnBlockLocator * [NOD-858] Rename shouldSendBlockLocator->wasBlockLocatorRequested * [NOD-858] Move panic to shouldReplaceSyncPeer --- netsync/manager.go | 46 ++++++++++++++++++++++------------ peer/peer.go | 17 +++++++++++++ server/p2p/on_block_locator.go | 1 + 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/netsync/manager.go b/netsync/manager.go index bc1cefb20..d10e4e066 100644 --- a/netsync/manager.go +++ b/netsync/manager.go @@ -157,6 +157,7 @@ type SyncManager struct { msgChan chan interface{} wg sync.WaitGroup quit chan struct{} + syncPeerLock sync.Mutex // These fields should only be accessed from the messageHandler thread rejectedTxns map[daghash.TxID]struct{} @@ -170,6 +171,8 @@ type SyncManager struct { // download/sync the blockDAG from. When syncing is already running, it // simply returns. It also examines the candidates for any which are no longer // candidates and removes them as needed. +// +// This function MUST be called with the sync peer lock held. func (sm *SyncManager) startSync() { // Return now if we're already syncing. if sm.syncPeer != nil { @@ -189,6 +192,7 @@ func (sm *SyncManager) startSync() { // TODO(davec): Use a better algorithm to choose the sync peer. // For now, just pick the first available candidate. syncPeer = peer + break } // Start syncing from the sync peer if one was selected. @@ -294,8 +298,8 @@ func (sm *SyncManager) handleNewPeerMsg(peer *peerpkg.Peer) { } // Start syncing by choosing the best candidate if needed. - if isSyncCandidate && sm.syncPeer == nil { - sm.startSync() + if isSyncCandidate { + sm.restartSyncIfNeeded() } } @@ -337,7 +341,7 @@ func (sm *SyncManager) stopSyncFromPeer(peer *peerpkg.Peer) { // sync peer. if sm.syncPeer == peer { sm.syncPeer = nil - sm.startSync() + sm.restartSyncIfNeeded() } } @@ -427,24 +431,34 @@ func (sm *SyncManager) current() bool { // restartSyncIfNeeded finds a new sync candidate if we're not expecting any // blocks from the current one. func (sm *SyncManager) restartSyncIfNeeded() { - if sm.syncPeer != nil { - syncPeerState, exists := sm.peerStates[sm.syncPeer] - if exists { - isWaitingForBlocks := func() bool { - syncPeerState.requestQueueMtx.Lock() - defer syncPeerState.requestQueueMtx.Unlock() - return len(syncPeerState.requestedBlocks) != 0 || len(syncPeerState.requestQueues[wire.InvTypeSyncBlock].queue) != 0 - }() - if isWaitingForBlocks { - return - } - } + sm.syncPeerLock.Lock() + defer sm.syncPeerLock.Unlock() + + if !sm.shouldReplaceSyncPeer() { + return } sm.syncPeer = nil sm.startSync() } +func (sm *SyncManager) shouldReplaceSyncPeer() bool { + if sm.syncPeer == nil { + return true + } + + syncPeerState, exists := sm.peerStates[sm.syncPeer] + if !exists { + panic(errors.Errorf("no peer state for sync peer %s", sm.syncPeer)) + } + + syncPeerState.requestQueueMtx.Lock() + defer syncPeerState.requestQueueMtx.Unlock() + return len(syncPeerState.requestedBlocks) == 0 && + len(syncPeerState.requestQueues[wire.InvTypeSyncBlock].queue) == 0 && + !sm.syncPeer.WasBlockLocatorRequested() +} + // handleBlockMsg handles block messages from all peers. func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) { peer := bmsg.peer @@ -905,7 +919,7 @@ func (sm *SyncManager) handleSelectedTipMsg(msg *selectedTipMsg) { return } peer.SetSelectedTipHash(selectedTipHash) - sm.startSync() + sm.restartSyncIfNeeded() } // messageHandler is the main handler for the sync manager. It must be run as a diff --git a/peer/peer.go b/peer/peer.go index 6074aa794..a9559d684 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -414,6 +414,8 @@ type Peer struct { prevGetBlockInvsLow *daghash.Hash prevGetBlockInvsHigh *daghash.Hash + wasBlockLocatorRequested bool + // These fields keep track of statistics for the peer and are protected // by the statsMtx mutex. statsMtx sync.RWMutex @@ -435,6 +437,20 @@ type Peer struct { quit chan struct{} } +// WasBlockLocatorRequested returns whether the node +// is expecting to get a block locator from this +// peer. +func (p *Peer) WasBlockLocatorRequested() bool { + return p.wasBlockLocatorRequested +} + +// SetWasBlockLocatorRequested sets whether the node +// is expecting to get a block locator from this +// peer. +func (p *Peer) SetWasBlockLocatorRequested(wasBlockLocatorRequested bool) { + p.wasBlockLocatorRequested = wasBlockLocatorRequested +} + // String returns the peer's address and directionality as a human-readable // string. // @@ -775,6 +791,7 @@ func (p *Peer) PushAddrMsg(addresses []*wire.NetAddress, subnetworkID *subnetwor // // This function is safe for concurrent access. func (p *Peer) PushGetBlockLocatorMsg(highHash, lowHash *daghash.Hash) { + p.SetWasBlockLocatorRequested(true) msg := wire.NewMsgGetBlockLocator(highHash, lowHash) p.QueueMessage(msg, nil) } diff --git a/server/p2p/on_block_locator.go b/server/p2p/on_block_locator.go index d043ffbb8..6934b16e9 100644 --- a/server/p2p/on_block_locator.go +++ b/server/p2p/on_block_locator.go @@ -8,6 +8,7 @@ import ( // OnBlockLocator is invoked when a peer receives a locator kaspa // message. func (sp *Peer) OnBlockLocator(_ *peer.Peer, msg *wire.MsgBlockLocator) { + sp.SetWasBlockLocatorRequested(false) // Find the highest known shared block between the peers, and asks // the block and its future from the peer. If the block is not // found, create a lower resolution block locator and send it to From c88869778d7fd10360895a954e980f40bff061e8 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 16 Apr 2020 15:03:41 +0300 Subject: [PATCH 003/351] [NOD-869] Add a print after os.Exit(1) to see if it is ever called (#701) --- util/panics/panics.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/panics/panics.go b/util/panics/panics.go index 4f04e2e75..a99d3d5d0 100644 --- a/util/panics/panics.go +++ b/util/panics/panics.go @@ -24,6 +24,7 @@ func HandlePanic(log *logs.Logger, goroutineStackTrace []byte) { log.Criticalf("Goroutine stack trace: %s", goroutineStackTrace) } log.Criticalf("Stack trace: %s", debug.Stack()) + log.Backend().Close() close(panicHandlerDone) }() @@ -34,8 +35,9 @@ func HandlePanic(log *logs.Logger, goroutineStackTrace []byte) { fmt.Fprintln(os.Stderr, "Couldn't handle a fatal error. Exiting...") case <-panicHandlerDone: } - log.Criticalf("Exiting") + fmt.Print("Exiting...") os.Exit(1) + fmt.Print("After os.Exit(1)") } // GoroutineWrapperFunc returns a goroutine wrapper function that handles panics and writes them to the log. From 5f3fb0bf9f7f5cfc5df7efde171a0c4fae2c6edd Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 11 Aug 2020 12:04:54 +0300 Subject: [PATCH 004/351] [NOD-1238] Fix acceptance index never being initialized. (#859) --- app/app.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/app.go b/app/app.go index 5f8ebed2d..a0b3fc970 100644 --- a/app/app.go +++ b/app/app.go @@ -168,6 +168,7 @@ func setupIndexes(cfg *config.Config) (blockdag.IndexManager, *indexers.Acceptan var acceptanceIndex *indexers.AcceptanceIndex if cfg.AcceptanceIndex { log.Info("acceptance index is enabled") + acceptanceIndex = indexers.NewAcceptanceIndex() indexes = append(indexes, acceptanceIndex) } From 72b5832f30f236d7e23effced3fd1b488bb76632 Mon Sep 17 00:00:00 2001 From: oudeis Date: Mon, 9 Nov 2020 07:07:30 +0000 Subject: [PATCH 005/351] Update to version 0.8.0 --- version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version/version.go b/version/version.go index c0cbdd3b1..612ccc8b3 100644 --- a/version/version.go +++ b/version/version.go @@ -10,8 +10,8 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 - appMinor uint = 7 - appPatch uint = 2 + appMinor uint = 8 + appPatch uint = 0 ) // appBuild is defined as a variable so it can be overridden during the build From 2282e36196432a9de63a351725174fb85b2d5f8c Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 9 Nov 2020 10:52:57 +0200 Subject: [PATCH 006/351] [NOD-1522] Add IsEqual to SubnetworkID (#1012) * [NOD-1519] Add IsEqual to SubnetworkID * [NOD-1522] Added comment --- domain/consensus/utils/subnetworks/compare.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/domain/consensus/utils/subnetworks/compare.go b/domain/consensus/utils/subnetworks/compare.go index 12cda20da..af1a06358 100644 --- a/domain/consensus/utils/subnetworks/compare.go +++ b/domain/consensus/utils/subnetworks/compare.go @@ -21,3 +21,14 @@ func cmp(a, b externalapi.DomainSubnetworkID) int { func Less(a, b externalapi.DomainSubnetworkID) bool { return cmp(a, b) < 0 } + +// IsEqual returns true if a and b are equal or both nil +func IsEqual(a, b *externalapi.DomainSubnetworkID) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + return *a == *b +} From 6db337c8c53dcd580825723b56e8f0a932a2420e Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 9 Nov 2020 12:02:42 +0200 Subject: [PATCH 007/351] [NOD-1519] Add TestAPI for BuildBlockWithParents (#1011) * [NOD-1519] Separate BlockBuilder and BlockProcessor * [NOD-1519] Wire blockBuilder properly + implement buildBlockWithParents * [NOD-1519] Added testapi package, TestConsensus interface, and TestConsensus factory * [NOD-1519] Add comments * [NOD-1519] Separate TestBlockBuilder out of BlockBuilder * [NOD-1519] TestBlockBuilder should also implement BlockBuilder * [NOD-1519] Add NewTestConsensus to factory interface --- domain/consensus/consensus.go | 23 +- domain/consensus/factory.go | 43 +++- .../consensus/model/externalapi/consensus.go | 21 ++ .../model/interface_processes_blockbuilder.go | 15 ++ .../interface_processes_blockprocessor.go | 2 - ...terface_processes_consensusstatemanager.go | 1 + .../consensus/model/testapi/test_consensus.go | 11 + .../processes/blockbuilder/block_builder.go | 210 ++++++++++++++++++ .../consensus/processes/blockbuilder/log.go | 7 + .../blockbuilder/test_block_builder.go | 100 +++++++++ .../blockprocessor/blockprocessor.go | 11 - .../processes/blockprocessor/buildblock.go | 150 ------------- .../calculate_past_utxo.go | 4 +- .../resolve_block_status.go | 2 +- .../consensusstatemanager/update_virtual.go | 2 +- domain/consensus/test_consensus.go | 17 ++ domain/domain.go | 7 +- .../blocktemplatebuilder.go | 10 +- domain/miningmanager/factory.go | 6 +- domain/miningmanager/mempool/mempool.go | 5 +- 20 files changed, 440 insertions(+), 207 deletions(-) create mode 100644 domain/consensus/model/externalapi/consensus.go create mode 100644 domain/consensus/model/interface_processes_blockbuilder.go create mode 100644 domain/consensus/model/testapi/test_consensus.go create mode 100644 domain/consensus/processes/blockbuilder/block_builder.go create mode 100644 domain/consensus/processes/blockbuilder/log.go create mode 100644 domain/consensus/processes/blockbuilder/test_block_builder.go delete mode 100644 domain/consensus/processes/blockprocessor/buildblock.go create mode 100644 domain/consensus/test_consensus.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index f19720bca..ca5a8a3a9 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -5,30 +5,11 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// Consensus maintains the current core state of the node -type Consensus interface { - BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) - ValidateAndInsertBlock(block *externalapi.DomainBlock) error - ValidateTransactionAndPopulateWithConsensusData(transaction *externalapi.DomainTransaction) error - - GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) - GetBlockHeader(blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) - GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) - - GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) - GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) - GetPruningPointUTXOSet() ([]byte, error) - SetPruningPointUTXOSet(serializedUTXOSet []byte) error - GetVirtualSelectedParent() (*externalapi.DomainBlock, error) - CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) - FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) - GetSyncInfo() (*externalapi.SyncInfo, error) -} - type consensus struct { databaseContext model.DBReader blockProcessor model.BlockProcessor + blockBuilder model.BlockBuilder consensusStateManager model.ConsensusStateManager transactionValidator model.TransactionValidator syncManager model.SyncManager @@ -46,7 +27,7 @@ type consensus struct { func (s *consensus) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { - return s.blockProcessor.BuildBlock(coinbaseData, transactions) + return s.blockBuilder.BuildBlock(coinbaseData, transactions) } // ValidateAndInsertBlock validates the given block and, if valid, applies it diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index a2e0d6fe7..f5138e078 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -16,6 +16,8 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/datastructures/utxodiffstore" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/processes/blockbuilder" "github.com/kaspanet/kaspad/domain/consensus/processes/blockprocessor" "github.com/kaspanet/kaspad/domain/consensus/processes/blockvalidator" "github.com/kaspanet/kaspad/domain/consensus/processes/coinbasemanager" @@ -37,13 +39,19 @@ import ( // Factory instantiates new Consensuses type Factory interface { - NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (Consensus, error) + NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) + NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (testapi.TestConsensus, error) } type factory struct{} +// NewFactory creates a new Consensus factory +func NewFactory() Factory { + return &factory{} +} + // NewConsensus instantiates a new Consensus -func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (Consensus, error) { +func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) { // Data Structures acceptanceDataStore := acceptancedatastore.New() blockStore := blockstore.New() @@ -193,6 +201,19 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockHeaderStore, headerTipsStore) + blockBuilder := blockbuilder.New( + dbManager, + difficultyManager, + pastMedianTimeManager, + coinbaseManager, + consensusStateManager, + ghostdagManager, + acceptanceDataStore, + blockRelationStore, + multisetStore, + ghostdagDataStore, + ) + blockProcessor := blockprocessor.New( dagParams, dbManager, @@ -225,6 +246,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat databaseContext: dbManager, blockProcessor: blockProcessor, + blockBuilder: blockBuilder, consensusStateManager: consensusStateManager, transactionValidator: transactionValidator, syncManager: syncManager, @@ -252,7 +274,18 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat return c, nil } -// NewFactory creates a new Consensus factory -func NewFactory() Factory { - return &factory{} +func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) ( + testapi.TestConsensus, error) { + + consensusAsInterface, err := f.NewConsensus(dagParams, db) + if err != nil { + return nil, err + } + + consensusAsImplementation := consensusAsInterface.(*consensus) + + return &testConsensus{ + consensus: consensusAsImplementation, + testBlockBuilder: blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder), + }, nil } diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go new file mode 100644 index 000000000..2dabcb928 --- /dev/null +++ b/domain/consensus/model/externalapi/consensus.go @@ -0,0 +1,21 @@ +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 + ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error + + GetBlock(blockHash *DomainHash) (*DomainBlock, error) + GetBlockHeader(blockHash *DomainHash) (*DomainBlockHeader, error) + GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error) + + GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error) + GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) + GetPruningPointUTXOSet() ([]byte, error) + SetPruningPointUTXOSet(serializedUTXOSet []byte) error + GetVirtualSelectedParent() (*DomainBlock, error) + CreateBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) + FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error) + GetSyncInfo() (*SyncInfo, error) +} diff --git a/domain/consensus/model/interface_processes_blockbuilder.go b/domain/consensus/model/interface_processes_blockbuilder.go new file mode 100644 index 000000000..469c176ae --- /dev/null +++ b/domain/consensus/model/interface_processes_blockbuilder.go @@ -0,0 +1,15 @@ +package model + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// BlockBuilder is responsible for creating blocks from the current state +type BlockBuilder interface { + BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) +} + +// TestBlockBuilder adds to the main BlockBuilder methods required by tests +type TestBlockBuilder interface { + BlockBuilder + BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) +} diff --git a/domain/consensus/model/interface_processes_blockprocessor.go b/domain/consensus/model/interface_processes_blockprocessor.go index ee2c1dffb..0f7df8090 100644 --- a/domain/consensus/model/interface_processes_blockprocessor.go +++ b/domain/consensus/model/interface_processes_blockprocessor.go @@ -3,8 +3,6 @@ package model import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockProcessor is responsible for processing incoming blocks -// and creating blocks from the current state type BlockProcessor interface { - BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) ValidateAndInsertBlock(block *externalapi.DomainBlock) error } diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index cc36e856f..5f4dc783e 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -9,4 +9,5 @@ type ConsensusStateManager interface { SetPruningPointUTXOSet(serializedUTXOSet []byte) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) + CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (*UTXODiff, AcceptanceData, Multiset, error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go new file mode 100644 index 000000000..ce291126d --- /dev/null +++ b/domain/consensus/model/testapi/test_consensus.go @@ -0,0 +1,11 @@ +package testapi + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// TestConsensus wraps the Consensus interface with some methods that are needed by tests only +type TestConsensus interface { + externalapi.Consensus + + BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) +} diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go new file mode 100644 index 000000000..66f4cfab3 --- /dev/null +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -0,0 +1,210 @@ +package blockbuilder + +import ( + "sort" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/kaspanet/kaspad/util/mstime" +) + +type blockBuilder struct { + databaseContext model.DBManager + + difficultyManager model.DifficultyManager + pastMedianTimeManager model.PastMedianTimeManager + coinbaseManager model.CoinbaseManager + consensusStateManager model.ConsensusStateManager + ghostdagManager model.GHOSTDAGManager + + acceptanceDataStore model.AcceptanceDataStore + blockRelationStore model.BlockRelationStore + multisetStore model.MultisetStore + ghostdagDataStore model.GHOSTDAGDataStore +} + +// New creates a new instance of a BlockBuilder +func New( + databaseContext model.DBManager, + + difficultyManager model.DifficultyManager, + pastMedianTimeManager model.PastMedianTimeManager, + coinbaseManager model.CoinbaseManager, + consensusStateManager model.ConsensusStateManager, + ghostdagManager model.GHOSTDAGManager, + + acceptanceDataStore model.AcceptanceDataStore, + blockRelationStore model.BlockRelationStore, + multisetStore model.MultisetStore, + ghostdagDataStore model.GHOSTDAGDataStore, +) model.BlockBuilder { + + return &blockBuilder{ + databaseContext: databaseContext, + difficultyManager: difficultyManager, + pastMedianTimeManager: pastMedianTimeManager, + coinbaseManager: coinbaseManager, + consensusStateManager: consensusStateManager, + ghostdagManager: ghostdagManager, + acceptanceDataStore: acceptanceDataStore, + blockRelationStore: blockRelationStore, + multisetStore: multisetStore, + ghostdagDataStore: ghostdagDataStore, + } +} + +// BuildBlock builds a block over the current state, with the given +// coinbaseData and the given transactions +func (bb *blockBuilder) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + + onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlock") + defer onEnd() + + return bb.buildBlock(coinbaseData, transactions) +} + +func (bb *blockBuilder) buildBlock(coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + + coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData) + if err != nil { + return nil, err + } + transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...) + + header, err := bb.buildHeader(transactionsWithCoinbase) + if err != nil { + return nil, err + } + + return &externalapi.DomainBlock{ + Header: header, + Transactions: transactionsWithCoinbase, + }, nil +} + +func (bb *blockBuilder) newBlockCoinbaseTransaction( + coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) { + + return bb.coinbaseManager.ExpectedCoinbaseTransaction(model.VirtualBlockHash, coinbaseData) +} + +func (bb blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) { + parentHashes, err := bb.newBlockParentHashes() + if err != nil { + return nil, err + } + virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + timeInMilliseconds, err := bb.newBlockTime(virtualGHOSTDAGData) + if err != nil { + return nil, err + } + bits, err := bb.newBlockDifficulty(virtualGHOSTDAGData) + if err != nil { + return nil, err + } + hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions) + acceptedIDMerkleRoot, err := bb.newBlockAcceptedIDMerkleRoot() + if err != nil { + return nil, err + } + utxoCommitment, err := bb.newBlockUTXOCommitment() + if err != nil { + return nil, err + } + + return &externalapi.DomainBlockHeader{ + Version: constants.BlockVersion, + ParentHashes: parentHashes, + HashMerkleRoot: *hashMerkleRoot, + AcceptedIDMerkleRoot: *acceptedIDMerkleRoot, + UTXOCommitment: *utxoCommitment, + TimeInMilliseconds: timeInMilliseconds, + Bits: bits, + }, nil +} + +func (bb blockBuilder) newBlockParentHashes() ([]*externalapi.DomainHash, error) { + virtualBlockRelations, err := bb.blockRelationStore.BlockRelation(bb.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + + return virtualBlockRelations.Parents, nil +} + +func (bb blockBuilder) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (int64, error) { + // The timestamp for the block must not be before the median timestamp + // of the last several blocks. Thus, choose the maximum between the + // current time and one second after the past median time. The current + // timestamp is truncated to a millisecond boundary before comparison since a + // block timestamp does not supported a precision greater than one + // millisecond. + newTimestamp := mstime.Now().UnixMilliseconds() + 1 + minTimestamp, err := bb.pastMedianTimeManager.PastMedianTime(virtualGHOSTDAGData.SelectedParent) + if err != nil { + return 0, err + } + if newTimestamp < minTimestamp { + newTimestamp = minTimestamp + } + return newTimestamp, nil +} + +func (bb blockBuilder) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) { + virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash) + if err != nil { + return 0, err + } + return bb.difficultyManager.RequiredDifficulty(virtualGHOSTDAGData.SelectedParent) +} + +func (bb blockBuilder) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { + return merkle.CalculateHashMerkleRoot(transactions) +} + +func (bb blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, error) { + newBlockAcceptanceData, err := bb.acceptanceDataStore.Get(bb.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + + return bb.calculateAcceptedIDMerkleRoot(newBlockAcceptanceData) +} + +func (bb blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.AcceptanceData) (*externalapi.DomainHash, error) { + var acceptedTransactions []*externalapi.DomainTransaction + for _, blockAcceptanceData := range acceptanceData { + for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData { + if !transactionAcceptance.IsAccepted { + continue + } + acceptedTransactions = append(acceptedTransactions, transactionAcceptance.Transaction) + } + } + sort.Slice(acceptedTransactions, func(i, j int) bool { + acceptedTransactionIID := consensusserialization.TransactionID(acceptedTransactions[i]) + acceptedTransactionJID := consensusserialization.TransactionID(acceptedTransactions[j]) + return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID) + }) + + return merkle.CalculateIDMerkleRoot(acceptedTransactions), nil +} + +func (bb blockBuilder) newBlockUTXOCommitment() (*externalapi.DomainHash, error) { + newBlockMultiset, err := bb.multisetStore.Get(bb.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + newBlockUTXOCommitment := newBlockMultiset.Hash() + return newBlockUTXOCommitment, nil +} diff --git a/domain/consensus/processes/blockbuilder/log.go b/domain/consensus/processes/blockbuilder/log.go new file mode 100644 index 000000000..c7af295e2 --- /dev/null +++ b/domain/consensus/processes/blockbuilder/log.go @@ -0,0 +1,7 @@ +package blockbuilder + +import ( + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +var log, _ = logger.Get(logger.SubsystemTags.BDAG) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go new file mode 100644 index 000000000..1690709b4 --- /dev/null +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -0,0 +1,100 @@ +package blockbuilder + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +type testBlockBuilder struct { + *blockBuilder +} + +var tempBlockHash = &externalapi.DomainHash{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + +// NewTestBlockBuilder creates an instance of a TestBlockBuilder +func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder) model.TestBlockBuilder { + return &testBlockBuilder{blockBuilder: baseBlockBuilder.(*blockBuilder)} +} + +func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + + onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockWithParents") + defer onEnd() + + return bb.buildBlockWithParents(parentHashes, coinbaseData, transactions) +} + +func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, + transactions []*externalapi.DomainTransaction, acceptanceData model.AcceptanceData, multiset model.Multiset) ( + *externalapi.DomainBlockHeader, error) { + + ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash) + if err != nil { + return nil, err + } + timeInMilliseconds, err := bb.newBlockTime(ghostdagData) + if err != nil { + return nil, err + } + bits, err := bb.newBlockDifficulty(ghostdagData) + if err != nil { + return nil, err + } + hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions) + acceptedIDMerkleRoot, err := bb.calculateAcceptedIDMerkleRoot(acceptanceData) + if err != nil { + return nil, err + } + utxoCommitment := multiset.Hash() + + return &externalapi.DomainBlockHeader{ + Version: constants.BlockVersion, + ParentHashes: parentHashes, + HashMerkleRoot: *hashMerkleRoot, + AcceptedIDMerkleRoot: *acceptedIDMerkleRoot, + UTXOCommitment: *utxoCommitment, + TimeInMilliseconds: timeInMilliseconds, + Bits: bits, + }, nil +} + +func (bb *testBlockBuilder) buildBlockWithParents( + parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + + bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) + defer bb.blockRelationStore.Discard() + + err := bb.ghostdagManager.GHOSTDAG(tempBlockHash) + if err != nil { + return nil, err + } + defer bb.ghostdagDataStore.Discard() + + _, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) + if err != nil { + return nil, err + } + bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData) + defer bb.acceptanceDataStore.Discard() + + coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData) + if err != nil { + return nil, err + } + transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...) + + header, err := bb.buildHeaderWithParents(parentHashes, transactions, acceptanceData, multiset) + if err != nil { + return nil, err + } + + return &externalapi.DomainBlock{ + Header: header, + Transactions: transactionsWithCoinbase, + }, nil +} diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index 1775de19c..805892a28 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -116,17 +116,6 @@ func New( } } -// BuildBlock builds a block over the current state, with the given -// coinbaseData and the given transactions -func (bp *blockProcessor) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { - - onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlock") - defer onEnd() - - return bp.buildBlock(coinbaseData, transactions) -} - // ValidateAndInsertBlock validates the given block and, if valid, applies it // to the current state func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) error { diff --git a/domain/consensus/processes/blockprocessor/buildblock.go b/domain/consensus/processes/blockprocessor/buildblock.go deleted file mode 100644 index bf56b13d5..000000000 --- a/domain/consensus/processes/blockprocessor/buildblock.go +++ /dev/null @@ -1,150 +0,0 @@ -package blockprocessor - -import ( - "sort" - - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" - "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" - "github.com/kaspanet/kaspad/util/mstime" -) - -func (bp *blockProcessor) buildBlock(coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { - - coinbase, err := bp.newBlockCoinbaseTransaction(coinbaseData) - if err != nil { - return nil, err - } - transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...) - - header, err := bp.buildHeader(transactionsWithCoinbase) - if err != nil { - return nil, err - } - - return &externalapi.DomainBlock{ - Header: header, - Transactions: transactionsWithCoinbase, - }, nil -} - -func (bp *blockProcessor) newBlockCoinbaseTransaction( - coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) { - - return bp.coinbaseManager.ExpectedCoinbaseTransaction(model.VirtualBlockHash, coinbaseData) -} - -func (bp *blockProcessor) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) { - parentHashes, err := bp.newBlockParentHashes() - if err != nil { - return nil, err - } - virtualGHOSTDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - timeInMilliseconds, err := bp.newBlockTime(virtualGHOSTDAGData) - if err != nil { - return nil, err - } - bits, err := bp.newBlockDifficulty(virtualGHOSTDAGData) - if err != nil { - return nil, err - } - hashMerkleRoot := bp.newBlockHashMerkleRoot(transactions) - acceptedIDMerkleRoot, err := bp.newBlockAcceptedIDMerkleRoot() - if err != nil { - return nil, err - } - utxoCommitment, err := bp.newBlockUTXOCommitment() - if err != nil { - return nil, err - } - - return &externalapi.DomainBlockHeader{ - Version: constants.BlockVersion, - ParentHashes: parentHashes, - HashMerkleRoot: *hashMerkleRoot, - AcceptedIDMerkleRoot: *acceptedIDMerkleRoot, - UTXOCommitment: *utxoCommitment, - TimeInMilliseconds: timeInMilliseconds, - Bits: bits, - }, nil -} - -func (bp *blockProcessor) newBlockParentHashes() ([]*externalapi.DomainHash, error) { - virtualBlockRelations, err := bp.blockRelationStore.BlockRelation(bp.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - - return virtualBlockRelations.Parents, nil -} - -func (bp *blockProcessor) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (int64, error) { - // The timestamp for the block must not be before the median timestamp - // of the last several blocks. Thus, choose the maximum between the - // current time and one second after the past median time. The current - // timestamp is truncated to a millisecond boundary before comparison since a - // block timestamp does not supported a precision greater than one - // millisecond. - newTimestamp := mstime.Now().UnixMilliseconds() + 1 - minTimestamp, err := bp.pastMedianTimeManager.PastMedianTime(virtualGHOSTDAGData.SelectedParent) - if err != nil { - return 0, err - } - if newTimestamp < minTimestamp { - newTimestamp = minTimestamp - } - return newTimestamp, nil -} - -func (bp *blockProcessor) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) { - virtualGHOSTDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash) - if err != nil { - return 0, err - } - return bp.difficultyManager.RequiredDifficulty(virtualGHOSTDAGData.SelectedParent) -} - -func (bp *blockProcessor) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { - return merkle.CalculateHashMerkleRoot(transactions) -} - -func (bp *blockProcessor) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, error) { - newBlockAcceptanceData, err := bp.acceptanceDataStore.Get(bp.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - - var acceptedTransactions []*externalapi.DomainTransaction - for _, blockAcceptanceData := range newBlockAcceptanceData { - for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData { - if !transactionAcceptance.IsAccepted { - continue - } - acceptedTransactions = append(acceptedTransactions, transactionAcceptance.Transaction) - } - } - sort.Slice(acceptedTransactions, func(i, j int) bool { - acceptedTransactionIID := consensusserialization.TransactionID(acceptedTransactions[i]) - acceptedTransactionJID := consensusserialization.TransactionID(acceptedTransactions[j]) - return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID) - }) - - return merkle.CalculateIDMerkleRoot(acceptedTransactions), nil -} - -func (bp *blockProcessor) newBlockUTXOCommitment() (*externalapi.DomainHash, error) { - newBlockMultiset, err := bp.multisetStore.Get(bp.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - newBlockUTXOCommitment := newBlockMultiset.Hash() - return newBlockUTXOCommitment, nil -} diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 27f81b4cd..5b42bd2ac 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -12,7 +12,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" ) -func (csm *consensusStateManager) calculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( +func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( *model.UTXODiff, model.AcceptanceData, model.Multiset, error) { blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash) @@ -167,7 +167,7 @@ func (csm *consensusStateManager) checkTransactionMass( } func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (model.ReadOnlyUTXOSetIterator, error) { - diff, _, _, err := csm.calculatePastUTXOAndAcceptanceData(blockHash) + diff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 27620c0f5..f184f6333 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -63,7 +63,7 @@ func (csm *consensusStateManager) getUnverifiedChainBlocksAndSelectedParentStatu } func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { - pastUTXODiff, acceptanceData, multiset, err := csm.calculatePastUTXOAndAcceptanceData(blockHash) + pastUTXODiff, acceptanceData, multiset, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) if err != nil { return 0, err } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 6cb288170..39541096c 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -23,7 +23,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain return err } - virtualUTXODiff, _, _, err := csm.calculatePastUTXOAndAcceptanceData(model.VirtualBlockHash) + virtualUTXODiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash) if err != nil { return err } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go new file mode 100644 index 000000000..5f38622f8 --- /dev/null +++ b/domain/consensus/test_consensus.go @@ -0,0 +1,17 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +type testConsensus struct { + *consensus + testBlockBuilder model.TestBlockBuilder +} + +func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + + return tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) +} diff --git a/domain/domain.go b/domain/domain.go index e8319e211..1565a9ef2 100644 --- a/domain/domain.go +++ b/domain/domain.go @@ -2,6 +2,7 @@ package domain import ( "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/domain/miningmanager" @@ -11,15 +12,15 @@ import ( // Domain provides a reference to the domain's external aps type Domain interface { MiningManager() miningmanager.MiningManager - Consensus() consensus.Consensus + Consensus() externalapi.Consensus } type domain struct { miningManager miningmanager.MiningManager - consensus consensus.Consensus + consensus externalapi.Consensus } -func (d domain) Consensus() consensus.Consensus { +func (d domain) Consensus() externalapi.Consensus { return d.consensus } diff --git a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go index be0f1eecb..3e22f59b3 100644 --- a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go +++ b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go @@ -1,15 +1,15 @@ package blocktemplatebuilder import ( - "github.com/kaspanet/kaspad/domain/consensus" + "math" + "sort" + consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" miningmanagerapi "github.com/kaspanet/kaspad/domain/miningmanager/model" "github.com/kaspanet/kaspad/util" "github.com/pkg/errors" - "math" - "sort" ) type candidateTx struct { @@ -26,13 +26,13 @@ type candidateTx struct { // blockTemplateBuilder creates block templates for a miner to consume type blockTemplateBuilder struct { - consensus consensus.Consensus + consensus consensusexternalapi.Consensus mempool miningmanagerapi.Mempool policy policy } // New creates a new blockTemplateBuilder -func New(consensus consensus.Consensus, mempool miningmanagerapi.Mempool, blockMaxMass uint64) miningmanagerapi.BlockTemplateBuilder { +func New(consensus consensusexternalapi.Consensus, mempool miningmanagerapi.Mempool, blockMaxMass uint64) miningmanagerapi.BlockTemplateBuilder { return &blockTemplateBuilder{ consensus: consensus, mempool: mempool, diff --git a/domain/miningmanager/factory.go b/domain/miningmanager/factory.go index 4590e46cf..30ad455e2 100644 --- a/domain/miningmanager/factory.go +++ b/domain/miningmanager/factory.go @@ -1,20 +1,20 @@ package miningmanager import ( - "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/miningmanager/blocktemplatebuilder" mempoolpkg "github.com/kaspanet/kaspad/domain/miningmanager/mempool" ) // Factory instantiates new mining managers type Factory interface { - NewMiningManager(consensus consensus.Consensus, blockMaxMass uint64) MiningManager + NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64) MiningManager } type factory struct{} // NewMiningManager instantiate a new mining manager -func (f *factory) NewMiningManager(consensus consensus.Consensus, blockMaxMass uint64) MiningManager { +func (f *factory) NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64) MiningManager { mempool := mempoolpkg.New(consensus) blockTemplateBuilder := blocktemplatebuilder.New(consensus, mempool, blockMaxMass) diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index ef66ca5f1..d048c3bd4 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -12,7 +12,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - "github.com/kaspanet/kaspad/domain/consensus" consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" @@ -75,7 +74,7 @@ type mempool struct { orphansByPrev map[consensusexternalapi.DomainOutpoint]map[consensusexternalapi.DomainTransactionID]*consensusexternalapi.DomainTransaction mempoolUTXOSet *mempoolUTXOSet - consensus consensus.Consensus + consensus consensusexternalapi.Consensus // nextExpireScan is the time after which the orphan pool will be // scanned in order to evict orphans. This is NOT a hard deadline as @@ -89,7 +88,7 @@ type mempool struct { // New returns a new memory pool for validating and storing standalone // transactions until they are mined into a block. -func New(consensus consensus.Consensus) miningmanagermodel.Mempool { +func New(consensus consensusexternalapi.Consensus) miningmanagermodel.Mempool { policy := policy{ MaxTxVersion: 0, AcceptNonStd: false, From e7a61c7edf61e4cdd12bb12e4228af4ae1e6da98 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 9 Nov 2020 16:21:09 +0200 Subject: [PATCH 008/351] [NOD-1524] Add lock to consensus (#1014) --- domain/consensus/consensus.go | 45 ++++++++++++++++++++++++++++++ domain/consensus/factory.go | 3 ++ domain/consensus/test_consensus.go | 4 +++ 3 files changed, 52 insertions(+) diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index ca5a8a3a9..2d4f51275 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -1,11 +1,14 @@ package consensus import ( + "sync" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) type consensus struct { + lock *sync.RWMutex databaseContext model.DBReader blockProcessor model.BlockProcessor @@ -27,18 +30,27 @@ type consensus struct { func (s *consensus) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.blockBuilder.BuildBlock(coinbaseData, transactions) } // ValidateAndInsertBlock validates the given block and, if valid, applies it // to the current state func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock) error { + s.lock.Lock() + defer s.lock.Unlock() + return s.blockProcessor.ValidateAndInsertBlock(block) } // ValidateTransactionAndPopulateWithConsensusData validates the given transaction // and populates it with any missing consensus data func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction *externalapi.DomainTransaction) error { + s.lock.RLock() + defer s.lock.RUnlock() + err := s.transactionValidator.ValidateTransactionInIsolation(transaction) if err != nil { return err @@ -63,14 +75,23 @@ func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction } func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.blockStore.Block(s.databaseContext, blockHash) } func (s *consensus) GetBlockHeader(blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.blockHeaderStore.BlockHeader(s.databaseContext, blockHash) } func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) { + s.lock.RLock() + defer s.lock.RUnlock() + blockInfo := &externalapi.BlockInfo{} exists, err := s.blockStatusStore.Exists(s.databaseContext, blockHash) @@ -98,22 +119,37 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap } func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.syncManager.GetHashesBetween(lowHash, highHash) } func (s *consensus) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.syncManager.GetMissingBlockBodyHashes(highHash) } func (s *consensus) GetPruningPointUTXOSet() ([]byte, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.pruningStore.PruningPointSerializedUTXOSet(s.databaseContext) } func (s *consensus) SetPruningPointUTXOSet(serializedUTXOSet []byte) error { + s.lock.RLock() + defer s.lock.RUnlock() + return s.consensusStateManager.SetPruningPointUTXOSet(serializedUTXOSet) } func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) { + s.lock.RLock() + defer s.lock.RUnlock() + virtualGHOSTDAGData, err := s.ghostdagDataStore.Get(s.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err @@ -122,13 +158,22 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) } func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.syncManager.CreateBlockLocator(lowHash, highHash) } func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator) } func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { + s.lock.RLock() + defer s.lock.RUnlock() + return s.syncManager.GetSyncInfo() } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index f5138e078..8f76b8fe2 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,6 +1,8 @@ package consensus import ( + "sync" + consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore" "github.com/kaspanet/kaspad/domain/consensus/datastructures/blockheaderstore" @@ -243,6 +245,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat headerTipsStore) c := &consensus{ + lock: &sync.RWMutex{}, databaseContext: dbManager, blockProcessor: blockProcessor, diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 5f38622f8..22c3eb80f 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -13,5 +13,9 @@ type testConsensus struct { func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + // Require write lock because BuildBlockWithParents stages temporary data + tc.lock.Lock() + defer tc.lock.Unlock() + return tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) } From 32da4440badc86812746247a74b990c54535efb7 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 9 Nov 2020 07:15:16 -0800 Subject: [PATCH 009/351] [NOD-1495] Disallow non native transactions (#988) * [NOD-1495] Disallow non native transactions * [NOD-1495] Use deserializeUTXOSetBytes * [NOD-1495] Delete checkNoNonNativeTransactions * [NOD-1495] Invert condition in checkTransactionPayload Co-authored-by: Mike Zak --- .../pruningstore/pruningstore.go | 8 ++++- domain/consensus/factory.go | 1 + .../blockvalidator/block_body_in_isolation.go | 18 ++++-------- .../future_covering_set.go | 29 ------------------- .../transaction_in_isolation.go | 17 +++++++++-- .../transactionvalidator.go | 20 ++++++++----- domain/consensus/ruleerrors/rule_error.go | 1 + .../utils/consensusserialization/common.go | 4 --- 8 files changed, 41 insertions(+), 57 deletions(-) diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index d1188fda5..b310b6268 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -91,7 +91,13 @@ func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader) if ps.serializedUTXOSetStaging != nil { return ps.serializedUTXOSetStaging, nil } - return dbContext.Get(pruningSerializedUTXOSetkey) + + dbPruningPointUTXOSetBytes, err := dbContext.Get(pruningSerializedUTXOSetkey) + if err != nil { + return nil, err + } + + return ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes) } func (ps *pruningStore) serializePruningPoint(pruningPoint *externalapi.DomainHash) ([]byte, error) { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 8f76b8fe2..830a51fcc 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -96,6 +96,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTraversalManager, blockHeaderStore) transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity, + dagParams.EnableNonNativeSubnetworks, dbManager, pastMedianTimeManager, ghostdagDataStore) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 9f4e5a154..635d5ef77 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -46,6 +46,11 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa return err } + err = v.checkBlockTransactionOrder(block) + if err != nil { + return err + } + err = v.checkTransactionsInIsolation(block) if err != nil { return err @@ -122,19 +127,6 @@ func (v *blockValidator) checkBlockTransactionOrder(block *externalapi.DomainBlo return nil } -func (v *blockValidator) checkNoNonNativeTransactions(block *externalapi.DomainBlock) error { - // Disallow non-native/coinbase subnetworks in networks that don't allow them - if !v.enableNonNativeSubnetworks { - for _, tx := range block.Transactions { - if !(tx.SubnetworkID == subnetworks.SubnetworkIDNative || - tx.SubnetworkID == subnetworks.SubnetworkIDCoinbase) { - return errors.Wrapf(ruleerrors.ErrInvalidSubnetwork, "non-native/coinbase subnetworks are not allowed") - } - } - } - return nil -} - func (v *blockValidator) checkTransactionsInIsolation(block *externalapi.DomainBlock) error { for _, tx := range block.Transactions { err := v.transactionValidator.ValidateTransactionInIsolation(tx) diff --git a/domain/consensus/processes/reachabilitymanager/future_covering_set.go b/domain/consensus/processes/reachabilitymanager/future_covering_set.go index a3c3fcaef..cfee01075 100644 --- a/domain/consensus/processes/reachabilitymanager/future_covering_set.go +++ b/domain/consensus/processes/reachabilitymanager/future_covering_set.go @@ -4,21 +4,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// futureCoveringTreeNodeSet represents a collection of blocks in the future of -// a certain block. Once a block B is added to the DAG, every block A_i in -// B's selected parent anticone must register B in its futureCoveringTreeNodeSet. This allows -// to relatively quickly (O(log(|futureCoveringTreeNodeSet|))) query whether B -// is a descendent (is in the "future") of any block that previously -// registered it. -// -// Note that futureCoveringTreeNodeSet is meant to be queried only if B is not -// a reachability tree descendant of the block in question, as reachability -// tree queries are always O(1). -// -// See insertNode, hasAncestorOf, and isInPast for further -// details. -type futureCoveringTreeNodeSet orderedTreeNodeSet - // insertToFutureCoveringSet inserts the given block into this node's FutureCoveringSet // while keeping it ordered by interval. // If a block B ∈ node.FutureCoveringSet exists such that its interval @@ -116,17 +101,3 @@ func (rt *reachabilityManager) futureCoveringSetHasAncestorOf(this, other *exter candidate := futureCoveringSet[ancestorIndex] return rt.IsReachabilityTreeAncestorOf(candidate, other) } - -// futureCoveringSetString returns a string representation of the intervals in this futureCoveringSet. -func (rt *reachabilityManager) futureCoveringSetString(futureCoveringSet []*externalapi.DomainHash) (string, error) { - intervalsString := "" - for _, node := range futureCoveringSet { - nodeInterval, err := rt.interval(node) - if err != nil { - return "", err - } - - intervalsString += intervalString(nodeInterval) - } - return intervalsString, nil -} diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index bd5c16efc..58617ffc6 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -39,6 +39,12 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do if err != nil { return err } + + err = v.checkTransactionPayload(tx) + if err != nil { + return err + } + err = v.checkNativeTransactionPayload(tx) if err != nil { return err @@ -165,7 +171,14 @@ func (v *transactionValidator) checkNativeTransactionPayload(tx *externalapi.Dom return nil } -func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.DomainTransaction, subnetworkID *externalapi.DomainSubnetworkID) error { +func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.DomainTransaction, + subnetworkID *externalapi.DomainSubnetworkID) error { + if !v.enableNonNativeSubnetworks && tx.SubnetworkID != subnetworks.SubnetworkIDNative && + tx.SubnetworkID != subnetworks.SubnetworkIDCoinbase { + return errors.Wrapf(ruleerrors.ErrSubnetworksDisabled, "transaction has non native or coinbase "+ + "subnetwork ID") + } + // If we are a partial node, only transactions on built in subnetworks // or our own subnetwork may have a payload isLocalNodeFull := subnetworkID == nil @@ -179,7 +192,7 @@ func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.Domain } func (v *transactionValidator) checkTransactionPayload(tx *externalapi.DomainTransaction) error { - if tx.Payload != nil { + if tx.Payload == nil { return errors.Wrapf(ruleerrors.ErrInvalidPayload, "nil payload is not allowed") } diff --git a/domain/consensus/processes/transactionvalidator/transactionvalidator.go b/domain/consensus/processes/transactionvalidator/transactionvalidator.go index 3decec5a4..41c338b97 100644 --- a/domain/consensus/processes/transactionvalidator/transactionvalidator.go +++ b/domain/consensus/processes/transactionvalidator/transactionvalidator.go @@ -7,20 +7,24 @@ import ( // transactionValidator exposes a set of validation classes, after which // it's possible to determine whether either a transaction is valid type transactionValidator struct { - blockCoinbaseMaturity uint64 - databaseContext model.DBReader - pastMedianTimeManager model.PastMedianTimeManager - ghostdagDataStore model.GHOSTDAGDataStore + blockCoinbaseMaturity uint64 + databaseContext model.DBReader + pastMedianTimeManager model.PastMedianTimeManager + ghostdagDataStore model.GHOSTDAGDataStore + enableNonNativeSubnetworks bool } // New instantiates a new TransactionValidator func New(blockCoinbaseMaturity uint64, + enableNonNativeSubnetworks bool, databaseContext model.DBReader, pastMedianTimeManager model.PastMedianTimeManager, ghostdagDataStore model.GHOSTDAGDataStore) model.TransactionValidator { - return &transactionValidator{blockCoinbaseMaturity: blockCoinbaseMaturity, - databaseContext: databaseContext, - pastMedianTimeManager: pastMedianTimeManager, - ghostdagDataStore: ghostdagDataStore, + return &transactionValidator{ + blockCoinbaseMaturity: blockCoinbaseMaturity, + enableNonNativeSubnetworks: enableNonNativeSubnetworks, + databaseContext: databaseContext, + pastMedianTimeManager: pastMedianTimeManager, + ghostdagDataStore: ghostdagDataStore, } } diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 30c67e774..69f8f2fae 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -228,6 +228,7 @@ var ( ErrKnownInvalid = newRuleError("ErrKnownInvalid") + ErrSubnetworksDisabled = newRuleError("ErrSubnetworksDisabled") ErrBadPruningPointUTXOSet = newRuleError("ErrBadPruningPointUTXOSet") ErrMissingBlockHeaderInIBD = newRuleError("ErrMissingBlockHeaderInIBD") diff --git a/domain/consensus/utils/consensusserialization/common.go b/domain/consensus/utils/consensusserialization/common.go index edd27a7db..d6d499618 100644 --- a/domain/consensus/utils/consensusserialization/common.go +++ b/domain/consensus/utils/consensusserialization/common.go @@ -13,10 +13,6 @@ var ( // littleEndian is a convenience variable since binary.LittleEndian is // quite long. littleEndian = binary.LittleEndian - - // bigEndian is a convenience variable since binary.BigEndian is quite - // long. - bigEndian = binary.BigEndian ) // errNoEncodingForType signifies that there's no encoding for the given type. From 31c526443037612a39c69fdfdd7ae63e4c8e17a4 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 10 Nov 2020 04:43:18 -0800 Subject: [PATCH 010/351] [NOD-1527] Allow to process headers while in missing utxo set sync state (#1018) * [NOD-1527] Allow to process headers while in missing utxo set sync state * [NOD-1527] Add isHeaderOnlyBlock function --- .../blockprocessor/validateandinsertblock.go | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index f94353538..89c7ff8f0 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -15,20 +15,25 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) hash := consensusserialization.HeaderHash(block.Header) if mode.State == externalapi.SyncStateMissingUTXOSet { - headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint() - if err != nil { - return err - } + if isHeaderOnlyBlock(block) { + // Allow processing headers while in state SyncStateMissingUTXOSet + mode.State = externalapi.SyncStateHeadersFirst + } else { + headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint() + if err != nil { + return err + } - if *hash != *headerTipsPruningPoint { - return errors.Errorf("cannot insert blocks other than the header pruning point "+ - "while in %s mode", mode.State) - } + if *hash != *headerTipsPruningPoint { + return errors.Errorf("cannot insert blocks other than the header pruning point "+ + "while in %s mode", mode.State) + } - mode.State = externalapi.SyncStateMissingBlockBodies + mode.State = externalapi.SyncStateMissingBlockBodies + } } - if mode.State == externalapi.SyncStateHeadersFirst && len(block.Transactions) != 0 { + if mode.State == externalapi.SyncStateHeadersFirst && !isHeaderOnlyBlock(block) { mode.State = externalapi.SyncStateNormal log.Warnf("block %s contains transactions while validating in header only mode", hash) } @@ -138,6 +143,10 @@ func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *e return bp.reachabilityManager.UpdateReindexRoot(headersSelectedTip) } +func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool { + return len(block.Transactions) == 0 +} + func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode *externalapi.SyncInfo) error { exists, err := bp.blockStatusStore.Exists(bp.databaseContext, hash) if err != nil { From 23c1ea6c314b0a16b435431446c374682618eb3a Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 10 Nov 2020 06:14:51 -0800 Subject: [PATCH 011/351] [NOD-1525] Implement headers first ibd (#1017) * [NOD-1525] Implement headers first IBD * [NOD-1525] Fix proto translators * [NOD-1525] Register missing flows * [NOD-1525] Rename SyncStateNormal->SyncStateRelay, simplifiy IBD peer selection code and get rid of panic in FinishIBD * [NOD-1525] Remove redundant methods from interface --- app/appmessage/domainconverters.go | 10 +- app/appmessage/message.go | 59 +- app/appmessage/p2p_ibdrootnotfound.go | 22 + app/appmessage/p2p_msgblock.go | 4 +- app/appmessage/p2p_msgblock_test.go | 2 +- ...p_blockheader.go => p2p_msgblockheader.go} | 24 +- ...der_test.go => p2p_msgblockheader_test.go} | 12 +- app/appmessage/p2p_msgdoneheaders.go | 22 + app/appmessage/p2p_msgdoneibdblocks.go | 22 - .../p2p_msgibdrootutxosetandblock.go | 23 + app/appmessage/p2p_msgrequestheaders.go | 34 + ..._test.go => p2p_msgrequestheaders_test.go} | 8 +- app/appmessage/p2p_msgrequestibdblocks.go | 24 +- .../p2p_msgrequestibdrootutxosetandblock.go | 26 + app/appmessage/p2p_msgrequestnextheaders.go | 22 + app/appmessage/p2p_msgrequestnextibdblocks.go | 22 - app/appmessage/p2p_msgrequestrelayblocks.go | 4 +- app/protocol/flowcontext/ibd.go | 42 +- .../flows/blockrelay/handle_relay_invs.go | 2 +- .../flows/ibd/handle_ibd_block_requests.go | 49 + ...bd_blocks.go => handle_request_headers.go} | 52 +- ...dle_request_ibd_root_utxo_set_and_block.go | 65 + app/protocol/flows/ibd/ibd.go | 183 +- app/protocol/protocol.go | 30 +- app/protocol/protocolerrors/protocolerrors.go | 16 +- domain/consensus/consensus.go | 21 +- .../consensus/model/externalapi/consensus.go | 2 +- domain/consensus/model/externalapi/sync.go | 10 +- .../blockprocessor/validateandinsertblock.go | 6 +- .../calculate_past_utxo.go | 3 + .../processes/reachabilitymanager/tree.go | 3 + .../processes/syncmanager/syncinfo.go | 2 +- domain/consensus/ruleerrors/rule_error.go | 2 + .../grpcserver/protowire/messages.pb.go | 3420 +++++++++-------- .../grpcserver/protowire/messages.proto | 51 +- .../server/grpcserver/protowire/p2p_block.go | 48 +- .../protowire/p2p_done_ibd_blocks.go | 6 +- .../server/grpcserver/protowire/p2p_header.go | 73 + .../grpcserver/protowire/p2p_ibd_block.go | 2 +- .../protowire/p2p_ibd_root_not_found.go | 11 + .../p2p_ibd_root_utxo_set_and_block.go | 19 + .../protowire/p2p_request_headers.go | 28 + .../protowire/p2p_request_ibd_blocks.go | 35 +- ...p2p_request_ibd_root_utxo_set_and_block.go | 18 + .../protowire/p2p_request_next_headers.go | 11 + .../protowire/p2p_request_next_ibd_blocks.go | 11 - .../protowire/p2p_request_relay_blocks.go | 8 +- .../protowire/rpc_get_block_template.go | 2 +- .../protowire/rpc_notify_block_added.go | 2 +- .../grpcserver/protowire/rpc_submit_block.go | 2 +- .../server/grpcserver/protowire/wire.go | 49 +- 51 files changed, 2822 insertions(+), 1802 deletions(-) create mode 100644 app/appmessage/p2p_ibdrootnotfound.go rename app/appmessage/{p2p_blockheader.go => p2p_msgblockheader.go} (84%) rename app/appmessage/{p2p_blockheader_test.go => p2p_msgblockheader_test.go} (88%) create mode 100644 app/appmessage/p2p_msgdoneheaders.go delete mode 100644 app/appmessage/p2p_msgdoneibdblocks.go create mode 100644 app/appmessage/p2p_msgibdrootutxosetandblock.go create mode 100644 app/appmessage/p2p_msgrequestheaders.go rename app/appmessage/{p2p_msgrequestibdblocks_test.go => p2p_msgrequestheaders_test.go} (78%) create mode 100644 app/appmessage/p2p_msgrequestibdrootutxosetandblock.go create mode 100644 app/appmessage/p2p_msgrequestnextheaders.go delete mode 100644 app/appmessage/p2p_msgrequestnextibdblocks.go create mode 100644 app/protocol/flows/ibd/handle_ibd_block_requests.go rename app/protocol/flows/ibd/{handle_request_ibd_blocks.go => handle_request_headers.go} (53%) create mode 100644 app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_headers.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_headers.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_blocks.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index f49ae453c..6d91961dc 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -17,9 +17,9 @@ func DomainBlockToMsgBlock(domainBlock *externalapi.DomainBlock) *MsgBlock { } } -// DomainBlockHeaderToBlockHeader converts an externalapi.DomainBlockHeader to BlockHeader -func DomainBlockHeaderToBlockHeader(domainBlockHeader *externalapi.DomainBlockHeader) *BlockHeader { - return &BlockHeader{ +// DomainBlockHeaderToBlockHeader converts an externalapi.DomainBlockHeader to MsgBlockHeader +func DomainBlockHeaderToBlockHeader(domainBlockHeader *externalapi.DomainBlockHeader) *MsgBlockHeader { + return &MsgBlockHeader{ Version: domainBlockHeader.Version, ParentHashes: domainBlockHeader.ParentHashes, HashMerkleRoot: &domainBlockHeader.HashMerkleRoot, @@ -44,8 +44,8 @@ func MsgBlockToDomainBlock(msgBlock *MsgBlock) *externalapi.DomainBlock { } } -// BlockHeaderToDomainBlockHeader converts a BlockHeader to externalapi.DomainBlockHeader -func BlockHeaderToDomainBlockHeader(blockHeader *BlockHeader) *externalapi.DomainBlockHeader { +// BlockHeaderToDomainBlockHeader converts a MsgBlockHeader to externalapi.DomainBlockHeader +func BlockHeaderToDomainBlockHeader(blockHeader *MsgBlockHeader) *externalapi.DomainBlockHeader { return &externalapi.DomainBlockHeader{ Version: blockHeader.Version, ParentHashes: blockHeader.ParentHashes, diff --git a/app/appmessage/message.go b/app/appmessage/message.go index a9eb54902..9108242f0 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -34,7 +34,7 @@ const ( CmdVerAck CmdRequestAddresses CmdAddresses - CmdRequestIBDBlocks + CmdRequestHeaders CmdBlock CmdTx CmdPing @@ -48,10 +48,15 @@ const ( CmdInvTransaction CmdRequestTransactions CmdIBDBlock - CmdRequestNextIBDBlocks - CmdDoneIBDBlocks + CmdDoneHeaders CmdTransactionNotFound CmdReject + CmdHeader + CmdRequestNextHeaders + CmdRequestIBDRootUTXOSetAndBlock + CmdIBDRootUTXOSetAndBlock + CmdRequestIBDBlocks + CmdIBDRootNotFound // rpc CmdGetCurrentNetworkRequestMessage @@ -107,28 +112,32 @@ const ( // ProtocolMessageCommandToString maps all MessageCommands to their string representation var ProtocolMessageCommandToString = map[MessageCommand]string{ - CmdVersion: "Version", - CmdVerAck: "VerAck", - CmdRequestAddresses: "RequestAddresses", - CmdAddresses: "Addresses", - CmdRequestIBDBlocks: "RequestBlocks", - CmdBlock: "Block", - CmdTx: "Tx", - CmdPing: "Ping", - CmdPong: "Pong", - CmdRequestBlockLocator: "RequestBlockLocator", - CmdBlockLocator: "BlockLocator", - CmdSelectedTip: "SelectedTip", - CmdRequestSelectedTip: "RequestSelectedTip", - CmdInvRelayBlock: "InvRelayBlock", - CmdRequestRelayBlocks: "RequestRelayBlocks", - CmdInvTransaction: "InvTransaction", - CmdRequestTransactions: "RequestTransactions", - CmdIBDBlock: "IBDBlock", - CmdRequestNextIBDBlocks: "RequestNextIBDBlocks", - CmdDoneIBDBlocks: "DoneIBDBlocks", - CmdTransactionNotFound: "TransactionNotFound", - CmdReject: "Reject", + CmdVersion: "Version", + CmdVerAck: "VerAck", + CmdRequestAddresses: "RequestAddresses", + CmdAddresses: "Addresses", + CmdRequestHeaders: "RequestBlocks", + CmdBlock: "Block", + CmdTx: "Tx", + CmdPing: "Ping", + CmdPong: "Pong", + CmdRequestBlockLocator: "RequestBlockLocator", + CmdBlockLocator: "BlockLocator", + CmdSelectedTip: "SelectedTip", + CmdRequestSelectedTip: "RequestSelectedTip", + CmdInvRelayBlock: "InvRelayBlock", + CmdRequestRelayBlocks: "RequestRelayBlocks", + CmdInvTransaction: "InvTransaction", + CmdRequestTransactions: "RequestTransactions", + CmdIBDBlock: "IBDBlock", + CmdDoneHeaders: "DoneIBDBlocks", + CmdTransactionNotFound: "TransactionNotFound", + CmdReject: "Reject", + CmdHeader: "Header", + CmdRequestNextHeaders: "RequestNextHeaders", + CmdRequestIBDRootUTXOSetAndBlock: "RequestPruningUTXOSetAndBlock", + CmdIBDRootUTXOSetAndBlock: "IBDRootUTXOSetAndBlock", + CmdIBDRootNotFound: "IBDRootNotFound", } // RPCMessageCommandToString maps all MessageCommands to their string representation diff --git a/app/appmessage/p2p_ibdrootnotfound.go b/app/appmessage/p2p_ibdrootnotfound.go new file mode 100644 index 000000000..d667a3de1 --- /dev/null +++ b/app/appmessage/p2p_ibdrootnotfound.go @@ -0,0 +1,22 @@ +package appmessage + +// MsgIBDRootNotFound implements the Message interface and represents a kaspa +// IBDRootNotFound message. It is used to notify the IBD root that was requested +// by other peer was not found. +// +// This message has no payload. +type MsgIBDRootNotFound struct { + baseMessage +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgIBDRootNotFound) Command() MessageCommand { + return CmdDoneHeaders +} + +// NewMsgIBDRootNotFound returns a new kaspa IBDRootNotFound message that conforms to the +// Message interface. +func NewMsgIBDRootNotFound() *MsgDoneHeaders { + return &MsgDoneHeaders{} +} diff --git a/app/appmessage/p2p_msgblock.go b/app/appmessage/p2p_msgblock.go index 8df74735f..5d8d3de53 100644 --- a/app/appmessage/p2p_msgblock.go +++ b/app/appmessage/p2p_msgblock.go @@ -40,7 +40,7 @@ type TxLoc struct { // response to a getdata message (MsgGetData) for a given block hash. type MsgBlock struct { baseMessage - Header BlockHeader + Header MsgBlockHeader Transactions []*MsgTx } @@ -79,7 +79,7 @@ func (msg *MsgBlock) ConvertToPartial(subnetworkID *externalapi.DomainSubnetwork // NewMsgBlock returns a new kaspa block message that conforms to the // Message interface. See MsgBlock for details. -func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock { +func NewMsgBlock(blockHeader *MsgBlockHeader) *MsgBlock { return &MsgBlock{ Header: *blockHeader, Transactions: make([]*MsgTx, 0, defaultTransactionAlloc), diff --git a/app/appmessage/p2p_msgblock_test.go b/app/appmessage/p2p_msgblock_test.go index 2751c9e60..39d02fca9 100644 --- a/app/appmessage/p2p_msgblock_test.go +++ b/app/appmessage/p2p_msgblock_test.go @@ -129,7 +129,7 @@ func TestConvertToPartial(t *testing.T) { // blockOne is the first block in the mainnet block DAG. var blockOne = MsgBlock{ - Header: BlockHeader{ + Header: MsgBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}, HashMerkleRoot: mainnetGenesisMerkleRoot, diff --git a/app/appmessage/p2p_blockheader.go b/app/appmessage/p2p_msgblockheader.go similarity index 84% rename from app/appmessage/p2p_blockheader.go rename to app/appmessage/p2p_msgblockheader.go index 44af00df0..203ba7f16 100644 --- a/app/appmessage/p2p_blockheader.go +++ b/app/appmessage/p2p_msgblockheader.go @@ -31,9 +31,11 @@ const MaxNumParentBlocks = 255 // BaseBlockHeaderPayload + up to MaxNumParentBlocks hashes of parent blocks const MaxBlockHeaderPayload = BaseBlockHeaderPayload + (MaxNumParentBlocks * externalapi.DomainHashSize) -// BlockHeader defines information about a block and is used in the kaspa +// MsgBlockHeader defines information about a block and is used in the kaspa // block (MsgBlock) and headers (MsgHeader) messages. -type BlockHeader struct { +type MsgBlockHeader struct { + baseMessage + // Version of the block. This is not the same as the protocol version. Version int32 @@ -61,7 +63,7 @@ type BlockHeader struct { } // NumParentBlocks return the number of entries in ParentHashes -func (h *BlockHeader) NumParentBlocks() byte { +func (h *MsgBlockHeader) NumParentBlocks() byte { numParents := len(h.ParentHashes) if numParents > math.MaxUint8 { panic(errors.Errorf("number of parents is %d, which is more than one byte can fit", numParents)) @@ -70,24 +72,30 @@ func (h *BlockHeader) NumParentBlocks() byte { } // BlockHash computes the block identifier hash for the given block header. -func (h *BlockHeader) BlockHash() *externalapi.DomainHash { +func (h *MsgBlockHeader) BlockHash() *externalapi.DomainHash { return consensusserialization.HeaderHash(BlockHeaderToDomainBlockHeader(h)) } // IsGenesis returns true iff this block is a genesis block -func (h *BlockHeader) IsGenesis() bool { +func (h *MsgBlockHeader) IsGenesis() bool { return h.NumParentBlocks() == 0 } -// NewBlockHeader returns a new BlockHeader using the provided version, previous +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (h *MsgBlockHeader) Command() MessageCommand { + return CmdHeader +} + +// NewBlockHeader returns a new MsgBlockHeader using the provided version, previous // block hash, hash merkle root, accepted ID merkle root, difficulty bits, and nonce used to generate the // block with defaults or calclulated values for the remaining fields. func NewBlockHeader(version int32, parentHashes []*externalapi.DomainHash, hashMerkleRoot *externalapi.DomainHash, - acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce uint64) *BlockHeader { + acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce uint64) *MsgBlockHeader { // Limit the timestamp to one millisecond precision since the protocol // doesn't support better. - return &BlockHeader{ + return &MsgBlockHeader{ Version: version, ParentHashes: parentHashes, HashMerkleRoot: hashMerkleRoot, diff --git a/app/appmessage/p2p_blockheader_test.go b/app/appmessage/p2p_msgblockheader_test.go similarity index 88% rename from app/appmessage/p2p_blockheader_test.go rename to app/appmessage/p2p_msgblockheader_test.go index 08a17dbc9..ebc4bc973 100644 --- a/app/appmessage/p2p_blockheader_test.go +++ b/app/appmessage/p2p_msgblockheader_test.go @@ -14,7 +14,7 @@ import ( "github.com/kaspanet/kaspad/util/random" ) -// TestBlockHeader tests the BlockHeader API. +// TestBlockHeader tests the MsgBlockHeader API. func TestBlockHeader(t *testing.T) { nonce, err := random.Uint64() if err != nil { @@ -52,7 +52,7 @@ func TestIsGenesis(t *testing.T) { bits := uint32(0x1d00ffff) timestamp := mstime.UnixMilliseconds(0x495fab29000) - baseBlockHdr := &BlockHeader{ + baseBlockHdr := &MsgBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}, HashMerkleRoot: mainnetGenesisMerkleRoot, @@ -60,7 +60,7 @@ func TestIsGenesis(t *testing.T) { Bits: bits, Nonce: nonce, } - genesisBlockHdr := &BlockHeader{ + genesisBlockHdr := &MsgBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{}, HashMerkleRoot: mainnetGenesisMerkleRoot, @@ -70,8 +70,8 @@ func TestIsGenesis(t *testing.T) { } tests := []struct { - in *BlockHeader // Block header to encode - isGenesis bool // Expected result for call of .IsGenesis + in *MsgBlockHeader // Block header to encode + isGenesis bool // Expected result for call of .IsGenesis }{ {genesisBlockHdr, true}, {baseBlockHdr, false}, @@ -81,7 +81,7 @@ func TestIsGenesis(t *testing.T) { for i, test := range tests { isGenesis := test.in.IsGenesis() if isGenesis != test.isGenesis { - t.Errorf("BlockHeader.IsGenesis: #%d got: %t, want: %t", + t.Errorf("MsgBlockHeader.IsGenesis: #%d got: %t, want: %t", i, isGenesis, test.isGenesis) } } diff --git a/app/appmessage/p2p_msgdoneheaders.go b/app/appmessage/p2p_msgdoneheaders.go new file mode 100644 index 000000000..d55733264 --- /dev/null +++ b/app/appmessage/p2p_msgdoneheaders.go @@ -0,0 +1,22 @@ +package appmessage + +// MsgDoneHeaders implements the Message interface and represents a kaspa +// DoneHeaders message. It is used to notify the IBD syncing peer that the +// syncer sent all the requested headers. +// +// This message has no payload. +type MsgDoneHeaders struct { + baseMessage +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgDoneHeaders) Command() MessageCommand { + return CmdDoneHeaders +} + +// NewMsgDoneHeaders returns a new kaspa DoneIBDBlocks message that conforms to the +// Message interface. +func NewMsgDoneHeaders() *MsgDoneHeaders { + return &MsgDoneHeaders{} +} diff --git a/app/appmessage/p2p_msgdoneibdblocks.go b/app/appmessage/p2p_msgdoneibdblocks.go deleted file mode 100644 index e8d0983f7..000000000 --- a/app/appmessage/p2p_msgdoneibdblocks.go +++ /dev/null @@ -1,22 +0,0 @@ -package appmessage - -// MsgDoneIBDBlocks implements the Message interface and represents a kaspa -// DoneIBDBlocks message. It is used to notify the IBD syncing peer that the -// syncer sent all the requested blocks. -// -// This message has no payload. -type MsgDoneIBDBlocks struct { - baseMessage -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgDoneIBDBlocks) Command() MessageCommand { - return CmdDoneIBDBlocks -} - -// NewMsgDoneIBDBlocks returns a new kaspa DoneIBDBlocks message that conforms to the -// Message interface. -func NewMsgDoneIBDBlocks() *MsgDoneIBDBlocks { - return &MsgDoneIBDBlocks{} -} diff --git a/app/appmessage/p2p_msgibdrootutxosetandblock.go b/app/appmessage/p2p_msgibdrootutxosetandblock.go new file mode 100644 index 000000000..556827216 --- /dev/null +++ b/app/appmessage/p2p_msgibdrootutxosetandblock.go @@ -0,0 +1,23 @@ +package appmessage + +// MsgIBDRootUTXOSetAndBlock implements the Message interface and represents a kaspa +// IBDRootUTXOSetAndBlock message. It is used to answer RequestIBDRootUTXOSetAndBlock messages. +type MsgIBDRootUTXOSetAndBlock struct { + baseMessage + UTXOSet []byte + Block *MsgBlock +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgIBDRootUTXOSetAndBlock) Command() MessageCommand { + return CmdRequestIBDRootUTXOSetAndBlock +} + +// NewMsgIBDRootUTXOSetAndBlock returns a new MsgIBDRootUTXOSetAndBlock. +func NewMsgIBDRootUTXOSetAndBlock(utxoSet []byte, block *MsgBlock) *MsgIBDRootUTXOSetAndBlock { + return &MsgIBDRootUTXOSetAndBlock{ + UTXOSet: utxoSet, + Block: block, + } +} diff --git a/app/appmessage/p2p_msgrequestheaders.go b/app/appmessage/p2p_msgrequestheaders.go new file mode 100644 index 000000000..6ccba5069 --- /dev/null +++ b/app/appmessage/p2p_msgrequestheaders.go @@ -0,0 +1,34 @@ +// Copyright (c) 2013-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgRequestHeaders implements the Message interface and represents a kaspa +// RequestHeaders message. It is used to request a list of blocks starting after the +// low hash and until the high hash. +type MsgRequestHeaders struct { + baseMessage + LowHash *externalapi.DomainHash + HighHash *externalapi.DomainHash +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgRequestHeaders) Command() MessageCommand { + return CmdRequestHeaders +} + +// NewMsgRequstHeaders returns a new kaspa RequestHeaders message that conforms to the +// Message interface using the passed parameters and defaults for the remaining +// fields. +func NewMsgRequstHeaders(lowHash, highHash *externalapi.DomainHash) *MsgRequestHeaders { + return &MsgRequestHeaders{ + LowHash: lowHash, + HighHash: highHash, + } +} diff --git a/app/appmessage/p2p_msgrequestibdblocks_test.go b/app/appmessage/p2p_msgrequestheaders_test.go similarity index 78% rename from app/appmessage/p2p_msgrequestibdblocks_test.go rename to app/appmessage/p2p_msgrequestheaders_test.go index b69589f1b..1d475b9d2 100644 --- a/app/appmessage/p2p_msgrequestibdblocks_test.go +++ b/app/appmessage/p2p_msgrequestheaders_test.go @@ -10,7 +10,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) -// TestRequstIBDBlocks tests the MsgRequestIBDBlocks API. +// TestRequstIBDBlocks tests the MsgRequestHeaders API. func TestRequstIBDBlocks(t *testing.T) { hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" lowHash, err := hashes.FromString(hashStr) @@ -25,16 +25,16 @@ func TestRequstIBDBlocks(t *testing.T) { } // Ensure we get the same data back out. - msg := NewMsgRequstIBDBlocks(lowHash, highHash) + msg := NewMsgRequstHeaders(lowHash, highHash) if *msg.HighHash != *highHash { - t.Errorf("NewMsgRequstIBDBlocks: wrong high hash - got %v, want %v", + t.Errorf("NewMsgRequstHeaders: wrong high hash - got %v, want %v", msg.HighHash, highHash) } // Ensure the command is expected value. wantCmd := MessageCommand(4) if cmd := msg.Command(); cmd != wantCmd { - t.Errorf("NewMsgRequstIBDBlocks: wrong command - got %v want %v", + t.Errorf("NewMsgRequstHeaders: wrong command - got %v want %v", cmd, wantCmd) } } diff --git a/app/appmessage/p2p_msgrequestibdblocks.go b/app/appmessage/p2p_msgrequestibdblocks.go index 7535cfc6a..848490716 100644 --- a/app/appmessage/p2p_msgrequestibdblocks.go +++ b/app/appmessage/p2p_msgrequestibdblocks.go @@ -1,20 +1,19 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - package appmessage import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) +// MaxRequestIBDBlocksHashes is the maximum number of hashes that can +// be in a single RequestIBDBlocks message. +const MaxRequestIBDBlocksHashes = MaxInvPerMsg + // MsgRequestIBDBlocks implements the Message interface and represents a kaspa -// RequestIBDBlocks message. It is used to request a list of blocks starting after the -// low hash and until the high hash. +// RequestIBDBlocks message. It is used to request blocks as part of the IBD +// protocol. type MsgRequestIBDBlocks struct { baseMessage - LowHash *externalapi.DomainHash - HighHash *externalapi.DomainHash + Hashes []*externalapi.DomainHash } // Command returns the protocol command string for the message. This is part @@ -23,12 +22,9 @@ func (msg *MsgRequestIBDBlocks) Command() MessageCommand { return CmdRequestIBDBlocks } -// NewMsgRequstIBDBlocks returns a new kaspa RequestIBDBlocks message that conforms to the -// Message interface using the passed parameters and defaults for the remaining -// fields. -func NewMsgRequstIBDBlocks(lowHash, highHash *externalapi.DomainHash) *MsgRequestIBDBlocks { +// NewMsgRequestIBDBlocks returns a new MsgRequestIBDBlocks. +func NewMsgRequestIBDBlocks(hashes []*externalapi.DomainHash) *MsgRequestIBDBlocks { return &MsgRequestIBDBlocks{ - LowHash: lowHash, - HighHash: highHash, + Hashes: hashes, } } diff --git a/app/appmessage/p2p_msgrequestibdrootutxosetandblock.go b/app/appmessage/p2p_msgrequestibdrootutxosetandblock.go new file mode 100644 index 000000000..1a828775b --- /dev/null +++ b/app/appmessage/p2p_msgrequestibdrootutxosetandblock.go @@ -0,0 +1,26 @@ +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgRequestIBDRootUTXOSetAndBlock implements the Message interface and represents a kaspa +// RequestIBDRootUTXOSetAndBlock message. It is used to request the UTXO set and block body +// of the IBD root block. +type MsgRequestIBDRootUTXOSetAndBlock struct { + baseMessage + IBDRoot *externalapi.DomainHash +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgRequestIBDRootUTXOSetAndBlock) Command() MessageCommand { + return CmdRequestIBDRootUTXOSetAndBlock +} + +// NewMsgRequestIBDRootUTXOSetAndBlock returns a new MsgRequestIBDRootUTXOSetAndBlock. +func NewMsgRequestIBDRootUTXOSetAndBlock(ibdRoot *externalapi.DomainHash) *MsgRequestIBDRootUTXOSetAndBlock { + return &MsgRequestIBDRootUTXOSetAndBlock{ + IBDRoot: ibdRoot, + } +} diff --git a/app/appmessage/p2p_msgrequestnextheaders.go b/app/appmessage/p2p_msgrequestnextheaders.go new file mode 100644 index 000000000..22687f12c --- /dev/null +++ b/app/appmessage/p2p_msgrequestnextheaders.go @@ -0,0 +1,22 @@ +package appmessage + +// MsgRequestNextHeaders implements the Message interface and represents a kaspa +// RequestNextHeaders message. It is used to notify the IBD syncer peer to send +// more headers. +// +// This message has no payload. +type MsgRequestNextHeaders struct { + baseMessage +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgRequestNextHeaders) Command() MessageCommand { + return CmdRequestNextHeaders +} + +// NewMsgRequestNextHeaders returns a new kaspa RequestNextHeaders message that conforms to the +// Message interface. +func NewMsgRequestNextHeaders() *MsgRequestNextHeaders { + return &MsgRequestNextHeaders{} +} diff --git a/app/appmessage/p2p_msgrequestnextibdblocks.go b/app/appmessage/p2p_msgrequestnextibdblocks.go deleted file mode 100644 index 9b3a4c13c..000000000 --- a/app/appmessage/p2p_msgrequestnextibdblocks.go +++ /dev/null @@ -1,22 +0,0 @@ -package appmessage - -// MsgRequestNextIBDBlocks implements the Message interface and represents a kaspa -// RequestNextIBDBlocks message. It is used to notify the IBD syncer peer to send -// more blocks. -// -// This message has no payload. -type MsgRequestNextIBDBlocks struct { - baseMessage -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgRequestNextIBDBlocks) Command() MessageCommand { - return CmdRequestNextIBDBlocks -} - -// NewMsgRequestNextIBDBlocks returns a new kaspa RequestNextIBDBlocks message that conforms to the -// Message interface. -func NewMsgRequestNextIBDBlocks() *MsgRequestNextIBDBlocks { - return &MsgRequestNextIBDBlocks{} -} diff --git a/app/appmessage/p2p_msgrequestrelayblocks.go b/app/appmessage/p2p_msgrequestrelayblocks.go index 34a4e7d4a..9f6bb246f 100644 --- a/app/appmessage/p2p_msgrequestrelayblocks.go +++ b/app/appmessage/p2p_msgrequestrelayblocks.go @@ -4,9 +4,9 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// MsgRequestRelayBlocksHashes is the maximum number of hashes that can +// MaxRequestRelayBlocksHashes is the maximum number of hashes that can // be in a single RequestRelayBlocks message. -const MsgRequestRelayBlocksHashes = MaxInvPerMsg +const MaxRequestRelayBlocksHashes = MaxInvPerMsg // MsgRequestRelayBlocks implements the Message interface and represents a kaspa // RequestRelayBlocks message. It is used to request blocks as part of the block diff --git a/app/protocol/flowcontext/ibd.go b/app/protocol/flowcontext/ibd.go index 2e669a746..e81f14109 100644 --- a/app/protocol/flowcontext/ibd.go +++ b/app/protocol/flowcontext/ibd.go @@ -1,6 +1,7 @@ package flowcontext import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "sync/atomic" "time" @@ -19,7 +20,16 @@ func (f *FlowContext) StartIBDIfRequired() error { return nil } - peer, err := f.selectPeerForIBD() + syncInfo, err := f.domain.Consensus().GetSyncInfo() + if err != nil { + return err + } + + if syncInfo.State == externalapi.SyncStateRelay { + return nil + } + + peer, err := f.selectPeerForIBD(syncInfo) if err != nil { return err } @@ -42,20 +52,32 @@ func (f *FlowContext) IsInIBD() bool { // selectPeerForIBD returns the first peer whose selected tip // hash is not in our DAG -func (f *FlowContext) selectPeerForIBD() (*peerpkg.Peer, error) { +func (f *FlowContext) selectPeerForIBD(syncInfo *externalapi.SyncInfo) (*peerpkg.Peer, error) { f.peersMutex.RLock() defer f.peersMutex.RUnlock() - for _, peer := range f.peers { - peerSelectedTipHash := peer.SelectedTipHash() - blockInfo, err := f.domain.Consensus().GetBlockInfo(peerSelectedTipHash) - if err != nil { - return nil, err - } - if !blockInfo.Exists { - return peer, nil + if syncInfo.State == externalapi.SyncStateHeadersFirst { + for _, peer := range f.peers { + peerSelectedTipHash := peer.SelectedTipHash() + blockInfo, err := f.domain.Consensus().GetBlockInfo(peerSelectedTipHash) + if err != nil { + return nil, err + } + + if syncInfo.State == externalapi.SyncStateHeadersFirst { + if !blockInfo.Exists { + return peer, nil + } + } else { + if blockInfo.Exists && blockInfo.BlockStatus == externalapi.StatusHeaderOnly && + blockInfo.IsBlockInHeaderPruningPointFuture { + return peer, nil + } + } } + return nil, nil } + return nil, nil } diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 248e2ff25..c73153989 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -114,7 +114,7 @@ func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) } func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) error { - numHashesToRequest := mathUtil.MinInt(appmessage.MsgRequestRelayBlocksHashes, requestQueue.len()) + numHashesToRequest := mathUtil.MinInt(appmessage.MaxRequestRelayBlocksHashes, requestQueue.len()) hashesToRequest := requestQueue.dequeue(numHashesToRequest) pendingBlocks := map[externalapi.DomainHash]struct{}{} diff --git a/app/protocol/flows/ibd/handle_ibd_block_requests.go b/app/protocol/flows/ibd/handle_ibd_block_requests.go new file mode 100644 index 000000000..df232787c --- /dev/null +++ b/app/protocol/flows/ibd/handle_ibd_block_requests.go @@ -0,0 +1,49 @@ +package ibd + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/pkg/errors" +) + +// HandleIBDBlockRequestsContext is the interface for the context needed for the HandleIBDBlockRequests flow. +type HandleIBDBlockRequestsContext interface { + Domain() domain.Domain +} + +// HandleIBDBlockRequests listens to appmessage.MsgRequestRelayBlocks messages and sends +// their corresponding blocks to the requesting peer. +func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute *router.Route, + outgoingRoute *router.Route) error { + + for { + message, err := incomingRoute.Dequeue() + if err != nil { + return err + } + msgRequestIBDBlocks := message.(*appmessage.MsgRequestIBDBlocks) + for _, hash := range msgRequestIBDBlocks.Hashes { + // Fetch the block from the database. + blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash) + if err != nil { + return err + } + if !blockInfo.Exists { + return protocolerrors.Errorf(true, "block %s not found", hash) + } + block, err := context.Domain().Consensus().GetBlock(hash) + if err != nil { + return errors.Wrapf(err, "unable to fetch requested block hash %s", hash) + } + + // TODO (Partial nodes): Convert block to partial block if needed + + err = outgoingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(block)) + if err != nil { + return err + } + } + } +} diff --git a/app/protocol/flows/ibd/handle_request_ibd_blocks.go b/app/protocol/flows/ibd/handle_request_headers.go similarity index 53% rename from app/protocol/flows/ibd/handle_request_ibd_blocks.go rename to app/protocol/flows/ibd/handle_request_headers.go index 8fdee2a28..cadfa2b84 100644 --- a/app/protocol/flows/ibd/handle_request_ibd_blocks.go +++ b/app/protocol/flows/ibd/handle_request_headers.go @@ -11,7 +11,7 @@ import ( const ibdBatchSize = router.DefaultMaxMessages -// RequestIBDBlocksContext is the interface for the context needed for the HandleRequestIBDBlocks flow. +// RequestIBDBlocksContext is the interface for the context needed for the HandleRequestHeaders flow. type RequestIBDBlocksContext interface { Domain() domain.Domain } @@ -21,8 +21,8 @@ type handleRequestBlocksFlow struct { incomingRoute, outgoingRoute *router.Route } -// HandleRequestIBDBlocks handles getBlocks messages -func HandleRequestIBDBlocks(context RequestIBDBlocksContext, incomingRoute *router.Route, outgoingRoute *router.Route) error { +// HandleRequestHeaders handles RequestHeaders messages +func HandleRequestHeaders(context RequestIBDBlocksContext, incomingRoute *router.Route, outgoingRoute *router.Route) error { flow := &handleRequestBlocksFlow{ RequestIBDBlocksContext: context, incomingRoute: incomingRoute, @@ -33,24 +33,24 @@ func HandleRequestIBDBlocks(context RequestIBDBlocksContext, incomingRoute *rout func (flow *handleRequestBlocksFlow) start() error { for { - lowHash, highHash, err := receiveRequestIBDBlocks(flow.incomingRoute) + lowHash, highHash, err := receiveRequestHeaders(flow.incomingRoute) if err != nil { return err } - msgIBDBlocks, err := flow.buildMsgIBDBlocks(lowHash, highHash) + msgHeaders, err := flow.buildMsgBlockHeaders(lowHash, highHash) if err != nil { return err } - for offset := 0; offset < len(msgIBDBlocks); offset += ibdBatchSize { + for offset := 0; offset < len(msgHeaders); offset += ibdBatchSize { end := offset + ibdBatchSize - if end > len(msgIBDBlocks) { - end = len(msgIBDBlocks) + if end > len(msgHeaders) { + end = len(msgHeaders) } - blocksToSend := msgIBDBlocks[offset:end] - err = flow.sendMsgIBDBlocks(blocksToSend) + blocksToSend := msgHeaders[offset:end] + err = flow.sendHeaders(blocksToSend) if err != nil { return nil } @@ -66,56 +66,56 @@ func (flow *handleRequestBlocksFlow) start() error { return err } - if _, ok := message.(*appmessage.MsgRequestNextIBDBlocks); !ok { + if _, ok := message.(*appmessage.MsgRequestNextHeaders); !ok { return protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdRequestNextIBDBlocks, message.Command()) + "expected: %s, got: %s", appmessage.CmdRequestNextHeaders, message.Command()) } } - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneIBDBlocks()) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { return err } } } -func receiveRequestIBDBlocks(incomingRoute *router.Route) (lowHash *externalapi.DomainHash, +func receiveRequestHeaders(incomingRoute *router.Route) (lowHash *externalapi.DomainHash, highHash *externalapi.DomainHash, err error) { message, err := incomingRoute.Dequeue() if err != nil { return nil, nil, err } - msgRequestIBDBlocks := message.(*appmessage.MsgRequestIBDBlocks) + msgRequestIBDBlocks := message.(*appmessage.MsgRequestHeaders) return msgRequestIBDBlocks.LowHash, msgRequestIBDBlocks.HighHash, nil } -func (flow *handleRequestBlocksFlow) buildMsgIBDBlocks(lowHash *externalapi.DomainHash, - highHash *externalapi.DomainHash) ([]*appmessage.MsgIBDBlock, error) { +func (flow *handleRequestBlocksFlow) buildMsgBlockHeaders(lowHash *externalapi.DomainHash, + highHash *externalapi.DomainHash) ([]*appmessage.MsgBlockHeader, error) { blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash) if err != nil { return nil, err } - const maxHashesInMsgIBDBlocks = appmessage.MaxInvPerMsg - if len(blockHashes) > maxHashesInMsgIBDBlocks { - blockHashes = blockHashes[:maxHashesInMsgIBDBlocks] + const maxHeaders = appmessage.MaxInvPerMsg + if len(blockHashes) > maxHeaders { + blockHashes = blockHashes[:maxHeaders] } - msgIBDBlocks := make([]*appmessage.MsgIBDBlock, len(blockHashes)) + msgBlockHeaders := make([]*appmessage.MsgBlockHeader, len(blockHashes)) for i, blockHash := range blockHashes { - block, err := flow.Domain().Consensus().GetBlock(blockHash) + header, err := flow.Domain().Consensus().GetBlockHeader(blockHash) if err != nil { return nil, err } - msgIBDBlocks[i] = appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(block)) + msgBlockHeaders[i] = appmessage.DomainBlockHeaderToBlockHeader(header) } - return msgIBDBlocks, nil + return msgBlockHeaders, nil } -func (flow *handleRequestBlocksFlow) sendMsgIBDBlocks(msgIBDBlocks []*appmessage.MsgIBDBlock) error { - for _, msgIBDBlock := range msgIBDBlocks { +func (flow *handleRequestBlocksFlow) sendHeaders(headers []*appmessage.MsgBlockHeader) error { + for _, msgIBDBlock := range headers { err := flow.outgoingRoute.Enqueue(msgIBDBlock) if err != nil { return err diff --git a/app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go b/app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go new file mode 100644 index 000000000..8298e7e52 --- /dev/null +++ b/app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go @@ -0,0 +1,65 @@ +package ibd + +import ( + "errors" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleRequestIBDRootUTXOSetAndBlockContext is the interface for the context needed for the HandleRequestIBDRootUTXOSetAndBlock flow. +type HandleRequestIBDRootUTXOSetAndBlockContext interface { + Domain() domain.Domain +} + +type handleRequestIBDRootUTXOSetAndBlockFlow struct { + HandleRequestIBDRootUTXOSetAndBlockContext + incomingRoute, outgoingRoute *router.Route +} + +// HandleRequestIBDRootUTXOSetAndBlock listens to appmessage.MsgRequestIBDRootUTXOSetAndBlock messages and sends +// the IBD root UTXO set and block body. +func HandleRequestIBDRootUTXOSetAndBlock(context HandleRequestIBDRootUTXOSetAndBlockContext, incomingRoute, + outgoingRoute *router.Route) error { + flow := &handleRequestIBDRootUTXOSetAndBlockFlow{ + HandleRequestIBDRootUTXOSetAndBlockContext: context, + incomingRoute: incomingRoute, + outgoingRoute: outgoingRoute, + } + + return flow.start() +} + +func (flow *handleRequestIBDRootUTXOSetAndBlockFlow) start() error { + for { + message, err := flow.incomingRoute.Dequeue() + if err != nil { + return err + } + msgRequestIBDRootUTXOSetAndBlock := message.(*appmessage.MsgRequestIBDRootUTXOSetAndBlock) + + utxoSet, err := flow.Domain().Consensus().GetPruningPointUTXOSet(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) + if err != nil { + if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) { + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootNotFound()) + if err != nil { + return err + } + + continue + } + } + + block, err := flow.Domain().Consensus().GetBlock(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) + if err != nil { + return err + } + + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootUTXOSetAndBlock(utxoSet, + appmessage.DomainBlockToMsgBlock(block))) + if err != nil { + return err + } + } +} diff --git a/app/protocol/flows/ibd/ibd.go b/app/protocol/flows/ibd/ibd.go index bac01639b..79053b5fd 100644 --- a/app/protocol/flows/ibd/ibd.go +++ b/app/protocol/flows/ibd/ibd.go @@ -53,8 +53,53 @@ func (flow *handleIBDFlow) start() error { func (flow *handleIBDFlow) runIBD() error { flow.peer.WaitForIBDStart() - defer flow.FinishIBD() + err := flow.ibdLoop() + if err != nil { + finishIBDErr := flow.FinishIBD() + if finishIBDErr != nil { + return finishIBDErr + } + return err + } + return flow.FinishIBD() +} +func (flow *handleIBDFlow) ibdLoop() error { + for { + syncInfo, err := flow.Domain().Consensus().GetSyncInfo() + if err != nil { + return err + } + + switch syncInfo.State { + case externalapi.SyncStateHeadersFirst: + err := flow.syncHeaders() + if err != nil { + return err + } + case externalapi.SyncStateMissingUTXOSet: + found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash) + if err != nil { + return err + } + + if !found { + return nil + } + case externalapi.SyncStateMissingBlockBodies: + err := flow.syncMissingBlockBodies() + if err != nil { + return err + } + case externalapi.SyncStateRelay: + return nil + default: + return errors.Errorf("unexpected state %s", syncInfo.State) + } + } +} + +func (flow *handleIBDFlow) syncHeaders() error { peerSelectedTipHash := flow.peer.SelectedTipHash() log.Debugf("Trying to find highest shared chain block with peer %s with selected tip %s", flow.peer, peerSelectedTipHash) highestSharedBlockHash, err := flow.findHighestSharedBlockHash(peerSelectedTipHash) @@ -64,7 +109,104 @@ func (flow *handleIBDFlow) runIBD() error { log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) - return flow.downloadBlocks(highestSharedBlockHash, peerSelectedTipHash) + return flow.downloadHeaders(highestSharedBlockHash, peerSelectedTipHash) +} + +func (flow *handleIBDFlow) syncMissingBlockBodies() error { + hashes, err := flow.Domain().Consensus().GetMissingBlockBodyHashes(flow.peer.SelectedTipHash()) + if err != nil { + return err + } + + for offset := 0; offset < len(hashes); offset += appmessage.MaxRequestIBDBlocksHashes { + var hashesToRequest []*externalapi.DomainHash + if offset+appmessage.MaxRequestIBDBlocksHashes < len(hashes) { + hashesToRequest = hashes[offset : offset+appmessage.MaxRequestIBDBlocksHashes] + } else { + hashesToRequest = hashes[offset:] + } + + err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDBlocks(hashesToRequest)) + if err != nil { + return err + } + + for _, expectedHash := range hashesToRequest { + message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) + if err != nil { + return err + } + + msgIBDBlock, ok := message.(*appmessage.MsgIBDBlock) + if !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDBlock, message.Command()) + } + + block := appmessage.MsgBlockToDomainBlock(msgIBDBlock.MsgBlock) + blockHash := consensusserialization.BlockHash(block) + if *expectedHash != *blockHash { + return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash) + } + + err = flow.Domain().Consensus().ValidateAndInsertBlock(block) + if err != nil { + return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash) + } + } + } + + return nil +} + +func (flow *handleIBDFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (bool, error) { + err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash)) + if err != nil { + return false, err + } + + utxoSet, block, found, err := flow.receiveIBDRootUTXOSetAndBlock() + if err != nil { + return false, err + } + + if !found { + return false, nil + } + + err = flow.Domain().Consensus().ValidateAndInsertBlock(block) + if err != nil { + blockHash := consensusserialization.BlockHash(block) + return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "got invalid block %s during IBD", blockHash) + } + + err = flow.Domain().Consensus().SetPruningPointUTXOSet(utxoSet) + if err != nil { + return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set") + } + + return true, nil +} + +func (flow *handleIBDFlow) receiveIBDRootUTXOSetAndBlock() ([]byte, *externalapi.DomainBlock, bool, error) { + message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) + if err != nil { + return nil, nil, false, err + } + + switch message := message.(type) { + case *appmessage.MsgIBDRootUTXOSetAndBlock: + return message.UTXOSet, + appmessage.MsgBlockToDomainBlock(message.Block), true, nil + case *appmessage.MsgIBDRootNotFound: + return nil, nil, false, nil + default: + return nil, nil, false, + protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s or %s, got: %s", + appmessage.CmdIBDRootUTXOSetAndBlock, appmessage.CmdIBDRootNotFound, message.Command(), + ) + } } func (flow *handleIBDFlow) findHighestSharedBlockHash(peerSelectedTipHash *externalapi.DomainHash) (lowHash *externalapi.DomainHash, @@ -123,17 +265,17 @@ func (flow *handleIBDFlow) receiveBlockLocator() (blockLocatorHashes []*external return msgBlockLocator.BlockLocatorHashes, nil } -func (flow *handleIBDFlow) downloadBlocks(highestSharedBlockHash *externalapi.DomainHash, +func (flow *handleIBDFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash, peerSelectedTipHash *externalapi.DomainHash) error { - err := flow.sendGetBlocks(highestSharedBlockHash, peerSelectedTipHash) + err := flow.sendRequestHeaders(highestSharedBlockHash, peerSelectedTipHash) if err != nil { return err } blocksReceived := 0 for { - msgIBDBlock, doneIBD, err := flow.receiveIBDBlock() + msgBlockHeader, doneIBD, err := flow.receiveHeader() if err != nil { return err } @@ -142,14 +284,14 @@ func (flow *handleIBDFlow) downloadBlocks(highestSharedBlockHash *externalapi.Do return nil } - err = flow.processIBDBlock(msgIBDBlock) + err = flow.processHeader(msgBlockHeader) if err != nil { return err } blocksReceived++ if blocksReceived%ibdBatchSize == 0 { - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextIBDBlocks()) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextHeaders()) if err != nil { return err } @@ -157,47 +299,52 @@ func (flow *handleIBDFlow) downloadBlocks(highestSharedBlockHash *externalapi.Do } } -func (flow *handleIBDFlow) sendGetBlocks(highestSharedBlockHash *externalapi.DomainHash, +func (flow *handleIBDFlow) sendRequestHeaders(highestSharedBlockHash *externalapi.DomainHash, peerSelectedTipHash *externalapi.DomainHash) error { - msgGetBlockInvs := appmessage.NewMsgRequstIBDBlocks(highestSharedBlockHash, peerSelectedTipHash) + msgGetBlockInvs := appmessage.NewMsgRequstHeaders(highestSharedBlockHash, peerSelectedTipHash) return flow.outgoingRoute.Enqueue(msgGetBlockInvs) } -func (flow *handleIBDFlow) receiveIBDBlock() (msgIBDBlock *appmessage.MsgIBDBlock, doneIBD bool, err error) { +func (flow *handleIBDFlow) receiveHeader() (msgIBDBlock *appmessage.MsgBlockHeader, doneIBD bool, err error) { message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) if err != nil { return nil, false, err } switch message := message.(type) { - case *appmessage.MsgIBDBlock: + case *appmessage.MsgBlockHeader: return message, false, nil - case *appmessage.MsgDoneIBDBlocks: + case *appmessage.MsgDoneHeaders: return nil, true, nil default: return nil, false, protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdIBDBlock, message.Command()) + "expected: %s or %s, got: %s", appmessage.CmdHeader, appmessage.CmdDoneHeaders, message.Command()) } } -func (flow *handleIBDFlow) processIBDBlock(msgIBDBlock *appmessage.MsgIBDBlock) error { - block := appmessage.MsgBlockToDomainBlock(msgIBDBlock.MsgBlock) +func (flow *handleIBDFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHeader) error { + header := appmessage.BlockHeaderToDomainBlockHeader(msgBlockHeader) + block := &externalapi.DomainBlock{ + Header: header, + Transactions: nil, + } + blockHash := consensusserialization.BlockHash(block) blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockHash) if err != nil { return err } if blockInfo.Exists { - log.Debugf("IBD block %s is already in the DAG. Skipping...", blockHash) + log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash) return nil } err = flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { if !errors.As(err, &ruleerrors.RuleError{}) { - return errors.Wrapf(err, "failed to process block %s during IBD", blockHash) + return errors.Wrapf(err, "failed to process header %s during IBD", blockHash) } - log.Infof("Rejected block %s from %s during IBD: %s", blockHash, flow.peer, err) + log.Infof("Rejected block header %s from %s during IBD: %s", blockHash, flow.peer, err) return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) } diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 67fc5bf5e..b8c095c2f 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -180,33 +180,51 @@ func (m *Manager) registerIBDFlows(router *routerpkg.Router, isStopping *uint32, return []*flow{ m.registerFlow("HandleIBD", router, []appmessage.MessageCommand{appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, - appmessage.CmdDoneIBDBlocks}, isStopping, errChan, + appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return ibd.HandleIBD(m.context, incomingRoute, outgoingRoute, peer) }, ), - m.registerFlow("RequestSelectedTip", router, []appmessage.MessageCommand{appmessage.CmdSelectedTip}, isStopping, errChan, + m.registerFlow("RequestSelectedTip", router, + []appmessage.MessageCommand{appmessage.CmdSelectedTip}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return selectedtip.RequestSelectedTip(m.context, incomingRoute, outgoingRoute, peer) }, ), - m.registerFlow("HandleRequestSelectedTip", router, []appmessage.MessageCommand{appmessage.CmdRequestSelectedTip}, isStopping, errChan, + m.registerFlow("HandleRequestSelectedTip", router, + []appmessage.MessageCommand{appmessage.CmdRequestSelectedTip}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return selectedtip.HandleRequestSelectedTip(m.context, incomingRoute, outgoingRoute) }, ), - m.registerFlow("HandleRequestBlockLocator", router, []appmessage.MessageCommand{appmessage.CmdRequestBlockLocator}, isStopping, errChan, + m.registerFlow("HandleRequestBlockLocator", router, + []appmessage.MessageCommand{appmessage.CmdRequestBlockLocator}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return ibd.HandleRequestBlockLocator(m.context, incomingRoute, outgoingRoute) }, ), - m.registerFlow("HandleRequestIBDBlocks", router, []appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks, appmessage.CmdRequestNextIBDBlocks}, isStopping, errChan, + m.registerFlow("HandleRequestHeaders", router, + []appmessage.MessageCommand{appmessage.CmdRequestHeaders, appmessage.CmdRequestNextHeaders}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return ibd.HandleRequestIBDBlocks(m.context, incomingRoute, outgoingRoute) + return ibd.HandleRequestHeaders(m.context, incomingRoute, outgoingRoute) + }, + ), + + m.registerFlow("HandleRequestIBDRootUTXOSetAndBlock", router, + []appmessage.MessageCommand{appmessage.CmdRequestIBDRootUTXOSetAndBlock}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return ibd.HandleRequestIBDRootUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute) + }, + ), + + m.registerFlow("HandleIBDBlockRequests", router, + []appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return ibd.HandleIBDBlockRequests(m.context, incomingRoute, outgoingRoute) }, ), } diff --git a/app/protocol/protocolerrors/protocolerrors.go b/app/protocol/protocolerrors/protocolerrors.go index 562fe4313..0c42934cb 100644 --- a/app/protocol/protocolerrors/protocolerrors.go +++ b/app/protocol/protocolerrors/protocolerrors.go @@ -1,6 +1,9 @@ package protocolerrors -import "github.com/pkg/errors" +import ( + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/pkg/errors" +) // ProtocolError is an error that signifies a violation // of the peer-to-peer protocol @@ -50,3 +53,14 @@ func Wrapf(shouldBan bool, err error, format string, args ...interface{}) error Cause: errors.Wrapf(err, format, args...), } } + +// ConvertToBanningProtocolErrorIfRuleError converts the given error to +// a banning protocol error if it's a rule error, and otherwise keep it +// as is. +func ConvertToBanningProtocolErrorIfRuleError(err error, format string, args ...interface{}) error { + if !errors.As(err, &ruleerrors.RuleError{}) { + return err + } + + return Wrapf(true, err, format, args...) +} diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 2d4f51275..b93ca8e87 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -5,6 +5,8 @@ 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/pkg/errors" ) type consensus struct { @@ -132,11 +134,26 @@ func (s *consensus) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) return s.syncManager.GetMissingBlockBodyHashes(highHash) } -func (s *consensus) GetPruningPointUTXOSet() ([]byte, error) { +func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi.DomainHash) ([]byte, error) { s.lock.RLock() defer s.lock.RUnlock() - return s.pruningStore.PruningPointSerializedUTXOSet(s.databaseContext) + pruningPointHash, err := s.pruningStore.PruningPoint(s.databaseContext) + if err != nil { + return nil, err + } + + if *expectedPruningPointHash != *pruningPointHash { + return nil, errors.Wrapf(ruleerrors.ErrWrongPruningPointHash, "expected pruning point %s but got %s", + expectedPruningPointHash, + pruningPointHash) + } + + serializedUTXOSet, err := s.pruningStore.PruningPointSerializedUTXOSet(s.databaseContext) + if err != nil { + return nil, err + } + return serializedUTXOSet, nil } func (s *consensus) SetPruningPointUTXOSet(serializedUTXOSet []byte) error { diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 2dabcb928..598316ac4 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -12,7 +12,7 @@ type Consensus interface { GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error) GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) - GetPruningPointUTXOSet() ([]byte, error) + GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error) SetPruningPointUTXOSet(serializedUTXOSet []byte) error GetVirtualSelectedParent() (*DomainBlock, error) CreateBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index 9b23d2389..d69db5fab 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -1,9 +1,11 @@ package externalapi +import "fmt" + // Each of the following represent one of the possible sync // states of the consensus const ( - SyncStateNormal SyncState = iota + SyncStateRelay SyncState = iota SyncStateMissingGenesis SyncStateHeadersFirst SyncStateMissingUTXOSet @@ -15,8 +17,8 @@ type SyncState uint8 func (s SyncState) String() string { switch s { - case SyncStateNormal: - return "SyncStateNormal" + case SyncStateRelay: + return "SyncStateRelay" case SyncStateHeadersFirst: return "SyncStateHeadersFirst" case SyncStateMissingUTXOSet: @@ -25,7 +27,7 @@ func (s SyncState) String() string { return "SyncStateMissingBlockBodies" } - return "" + return fmt.Sprintf("", s) } // SyncInfo holds info about the current sync state of the consensus diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 89c7ff8f0..b4f217874 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -34,7 +34,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } if mode.State == externalapi.SyncStateHeadersFirst && !isHeaderOnlyBlock(block) { - mode.State = externalapi.SyncStateNormal + mode.State = externalapi.SyncStateRelay log.Warnf("block %s contains transactions while validating in header only mode", hash) } @@ -97,7 +97,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) if err != nil { return err } - } else if mode.State == externalapi.SyncStateNormal { + } else if mode.State == externalapi.SyncStateRelay { // Attempt to add the block to the virtual err = bp.consensusStateManager.AddBlockToVirtual(hash) if err != nil { @@ -118,7 +118,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } } - if mode.State == externalapi.SyncStateNormal { + if mode.State == externalapi.SyncStateRelay { // Trigger pruning, which will check if the pruning point changed and delete the data if it did. err = bp.pruningManager.FindNextPruningPoint() if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 5b42bd2ac..4c267bde9 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -52,6 +52,9 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH utxoDiffs = append(utxoDiffs, utxoDiff) nextBlockHash, err = csm.utxoDiffStore.UTXODiffChild(csm.databaseContext, nextBlockHash) + if err != nil { + return nil, err + } } // apply the diffs in reverse order diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 16975f398..6a40ec47c 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -629,6 +629,9 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces currentInterval.Start, currentInterval.End-slackReachabilityIntervalForReclaiming, )) + if err != nil { + return err + } currentParent, err := rt.parent(current) if err != nil { diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 85547a4b9..64437aba9 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -70,7 +70,7 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { return externalapi.SyncStateMissingBlockBodies, nil } - return externalapi.SyncStateNormal, nil + return externalapi.SyncStateRelay, nil } func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, error) { diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 69f8f2fae..d24623dba 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -234,6 +234,8 @@ var ( ErrMissingBlockHeaderInIBD = newRuleError("ErrMissingBlockHeaderInIBD") ErrMalformedUTXO = newRuleError("ErrMalformedUTXO") + + ErrWrongPruningPointHash = newRuleError("ErrWrongPruningPointHash") ) // RuleError identifies a rule violation. It is used to indicate that diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 2be58fc1b..2dbc3ad32 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -2,17 +2,16 @@ // versions: // protoc-gen-go v1.25.0 // protoc v3.12.3 -// source: dbobjects.proto +// source: messages.proto package protowire import ( - reflect "reflect" - sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( @@ -38,9 +37,9 @@ type KaspadMessage struct { // *KaspadMessage_RequestBlockLocator // *KaspadMessage_BlockLocator // *KaspadMessage_RequestAddresses - // *KaspadMessage_RequestIBDBlocks - // *KaspadMessage_RequestNextIBDBlocks - // *KaspadMessage_DoneIBDBlocks + // *KaspadMessage_RequestHeaders + // *KaspadMessage_RequestNextHeaders + // *KaspadMessage_DoneHeaders // *KaspadMessage_RequestRelayBlocks // *KaspadMessage_RequestSelectedTip // *KaspadMessage_RequestTransactions @@ -54,6 +53,11 @@ type KaspadMessage struct { // *KaspadMessage_Version // *KaspadMessage_TransactionNotFound // *KaspadMessage_Reject + // *KaspadMessage_BlockHeader + // *KaspadMessage_RequestIBDRootUTXOSetAndBlock + // *KaspadMessage_IbdRootUTXOSetAndBlock + // *KaspadMessage_RequestIBDBlocks + // *KaspadMessage_IbdRootNotFound // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -186,23 +190,23 @@ func (x *KaspadMessage) GetRequestAddresses() *RequestAddressesMessage { return nil } -func (x *KaspadMessage) GetRequestIBDBlocks() *RequestIBDBlocksMessage { - if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDBlocks); ok { - return x.RequestIBDBlocks +func (x *KaspadMessage) GetRequestHeaders() *RequestHeadersMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestHeaders); ok { + return x.RequestHeaders } return nil } -func (x *KaspadMessage) GetRequestNextIBDBlocks() *RequestNextIBDBlocksMessage { - if x, ok := x.GetPayload().(*KaspadMessage_RequestNextIBDBlocks); ok { - return x.RequestNextIBDBlocks +func (x *KaspadMessage) GetRequestNextHeaders() *RequestNextHeadersMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestNextHeaders); ok { + return x.RequestNextHeaders } return nil } -func (x *KaspadMessage) GetDoneIBDBlocks() *DoneIBDBlocksMessage { - if x, ok := x.GetPayload().(*KaspadMessage_DoneIBDBlocks); ok { - return x.DoneIBDBlocks +func (x *KaspadMessage) GetDoneHeaders() *DoneHeadersMessage { + if x, ok := x.GetPayload().(*KaspadMessage_DoneHeaders); ok { + return x.DoneHeaders } return nil } @@ -298,6 +302,41 @@ func (x *KaspadMessage) GetReject() *RejectMessage { return nil } +func (x *KaspadMessage) GetBlockHeader() *BlockHeaderMessage { + if x, ok := x.GetPayload().(*KaspadMessage_BlockHeader); ok { + return x.BlockHeader + } + return nil +} + +func (x *KaspadMessage) GetRequestIBDRootUTXOSetAndBlock() *RequestIBDRootUTXOSetAndBlockMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDRootUTXOSetAndBlock); ok { + return x.RequestIBDRootUTXOSetAndBlock + } + return nil +} + +func (x *KaspadMessage) GetIbdRootUTXOSetAndBlock() *IBDRootUTXOSetAndBlockMessage { + if x, ok := x.GetPayload().(*KaspadMessage_IbdRootUTXOSetAndBlock); ok { + return x.IbdRootUTXOSetAndBlock + } + return nil +} + +func (x *KaspadMessage) GetRequestIBDBlocks() *RequestIBDBlocksMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDBlocks); ok { + return x.RequestIBDBlocks + } + return nil +} + +func (x *KaspadMessage) GetIbdRootNotFound() *IBDRootNotFoundMessage { + if x, ok := x.GetPayload().(*KaspadMessage_IbdRootNotFound); ok { + return x.IbdRootNotFound + } + return nil +} + func (x *KaspadMessage) GetGetCurrentNetworkRequest() *GetCurrentNetworkRequestMessage { if x, ok := x.GetPayload().(*KaspadMessage_GetCurrentNetworkRequest); ok { return x.GetCurrentNetworkRequest @@ -662,16 +701,16 @@ type KaspadMessage_RequestAddresses struct { RequestAddresses *RequestAddressesMessage `protobuf:"bytes,6,opt,name=requestAddresses,proto3,oneof"` } -type KaspadMessage_RequestIBDBlocks struct { - RequestIBDBlocks *RequestIBDBlocksMessage `protobuf:"bytes,7,opt,name=requestIBDBlocks,proto3,oneof"` +type KaspadMessage_RequestHeaders struct { + RequestHeaders *RequestHeadersMessage `protobuf:"bytes,7,opt,name=requestHeaders,proto3,oneof"` } -type KaspadMessage_RequestNextIBDBlocks struct { - RequestNextIBDBlocks *RequestNextIBDBlocksMessage `protobuf:"bytes,8,opt,name=requestNextIBDBlocks,proto3,oneof"` +type KaspadMessage_RequestNextHeaders struct { + RequestNextHeaders *RequestNextHeadersMessage `protobuf:"bytes,8,opt,name=requestNextHeaders,proto3,oneof"` } -type KaspadMessage_DoneIBDBlocks struct { - DoneIBDBlocks *DoneIBDBlocksMessage `protobuf:"bytes,9,opt,name=DoneIBDBlocks,proto3,oneof"` +type KaspadMessage_DoneHeaders struct { + DoneHeaders *DoneHeadersMessage `protobuf:"bytes,9,opt,name=DoneHeaders,proto3,oneof"` } type KaspadMessage_RequestRelayBlocks struct { @@ -726,6 +765,26 @@ type KaspadMessage_Reject struct { Reject *RejectMessage `protobuf:"bytes,22,opt,name=reject,proto3,oneof"` } +type KaspadMessage_BlockHeader struct { + BlockHeader *BlockHeaderMessage `protobuf:"bytes,23,opt,name=blockHeader,proto3,oneof"` +} + +type KaspadMessage_RequestIBDRootUTXOSetAndBlock struct { + RequestIBDRootUTXOSetAndBlock *RequestIBDRootUTXOSetAndBlockMessage `protobuf:"bytes,24,opt,name=requestIBDRootUTXOSetAndBlock,proto3,oneof"` +} + +type KaspadMessage_IbdRootUTXOSetAndBlock struct { + IbdRootUTXOSetAndBlock *IBDRootUTXOSetAndBlockMessage `protobuf:"bytes,25,opt,name=ibdRootUTXOSetAndBlock,proto3,oneof"` +} + +type KaspadMessage_RequestIBDBlocks struct { + RequestIBDBlocks *RequestIBDBlocksMessage `protobuf:"bytes,26,opt,name=requestIBDBlocks,proto3,oneof"` +} + +type KaspadMessage_IbdRootNotFound struct { + IbdRootNotFound *IBDRootNotFoundMessage `protobuf:"bytes,27,opt,name=ibdRootNotFound,proto3,oneof"` +} + type KaspadMessage_GetCurrentNetworkRequest struct { GetCurrentNetworkRequest *GetCurrentNetworkRequestMessage `protobuf:"bytes,1001,opt,name=getCurrentNetworkRequest,proto3,oneof"` } @@ -930,11 +989,11 @@ func (*KaspadMessage_BlockLocator) isKaspadMessage_Payload() {} func (*KaspadMessage_RequestAddresses) isKaspadMessage_Payload() {} -func (*KaspadMessage_RequestIBDBlocks) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestHeaders) isKaspadMessage_Payload() {} -func (*KaspadMessage_RequestNextIBDBlocks) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestNextHeaders) isKaspadMessage_Payload() {} -func (*KaspadMessage_DoneIBDBlocks) isKaspadMessage_Payload() {} +func (*KaspadMessage_DoneHeaders) isKaspadMessage_Payload() {} func (*KaspadMessage_RequestRelayBlocks) isKaspadMessage_Payload() {} @@ -962,6 +1021,16 @@ func (*KaspadMessage_TransactionNotFound) isKaspadMessage_Payload() {} func (*KaspadMessage_Reject) isKaspadMessage_Payload() {} +func (*KaspadMessage_BlockHeader) isKaspadMessage_Payload() {} + +func (*KaspadMessage_RequestIBDRootUTXOSetAndBlock) isKaspadMessage_Payload() {} + +func (*KaspadMessage_IbdRootUTXOSetAndBlock) isKaspadMessage_Payload() {} + +func (*KaspadMessage_RequestIBDBlocks) isKaspadMessage_Payload() {} + +func (*KaspadMessage_IbdRootNotFound) isKaspadMessage_Payload() {} + func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkResponse) isKaspadMessage_Payload() {} @@ -1626,7 +1695,7 @@ type BlockMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Header *BlockHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + Header *BlockHeaderMessage `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` Transactions []*TransactionMessage `protobuf:"bytes,2,rep,name=transactions,proto3" json:"transactions,omitempty"` } @@ -1662,7 +1731,7 @@ func (*BlockMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{10} } -func (x *BlockMessage) GetHeader() *BlockHeader { +func (x *BlockMessage) GetHeader() *BlockHeaderMessage { if x != nil { return x.Header } @@ -1676,7 +1745,7 @@ func (x *BlockMessage) GetTransactions() []*TransactionMessage { return nil } -type BlockHeader struct { +type BlockHeaderMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1691,8 +1760,8 @@ type BlockHeader struct { Nonce uint64 `protobuf:"varint,8,opt,name=nonce,proto3" json:"nonce,omitempty"` } -func (x *BlockHeader) Reset() { - *x = BlockHeader{} +func (x *BlockHeaderMessage) Reset() { + *x = BlockHeaderMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1700,13 +1769,13 @@ func (x *BlockHeader) Reset() { } } -func (x *BlockHeader) String() string { +func (x *BlockHeaderMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*BlockHeader) ProtoMessage() {} +func (*BlockHeaderMessage) ProtoMessage() {} -func (x *BlockHeader) ProtoReflect() protoreflect.Message { +func (x *BlockHeaderMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1718,61 +1787,61 @@ func (x *BlockHeader) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use BlockHeader.ProtoReflect.Descriptor instead. -func (*BlockHeader) Descriptor() ([]byte, []int) { +// Deprecated: Use BlockHeaderMessage.ProtoReflect.Descriptor instead. +func (*BlockHeaderMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{11} } -func (x *BlockHeader) GetVersion() int32 { +func (x *BlockHeaderMessage) GetVersion() int32 { if x != nil { return x.Version } return 0 } -func (x *BlockHeader) GetParentHashes() []*Hash { +func (x *BlockHeaderMessage) GetParentHashes() []*Hash { if x != nil { return x.ParentHashes } return nil } -func (x *BlockHeader) GetHashMerkleRoot() *Hash { +func (x *BlockHeaderMessage) GetHashMerkleRoot() *Hash { if x != nil { return x.HashMerkleRoot } return nil } -func (x *BlockHeader) GetAcceptedIDMerkleRoot() *Hash { +func (x *BlockHeaderMessage) GetAcceptedIDMerkleRoot() *Hash { if x != nil { return x.AcceptedIDMerkleRoot } return nil } -func (x *BlockHeader) GetUtxoCommitment() *Hash { +func (x *BlockHeaderMessage) GetUtxoCommitment() *Hash { if x != nil { return x.UtxoCommitment } return nil } -func (x *BlockHeader) GetTimestamp() int64 { +func (x *BlockHeaderMessage) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *BlockHeader) GetBits() uint32 { +func (x *BlockHeaderMessage) GetBits() uint32 { if x != nil { return x.Bits } return 0 } -func (x *BlockHeader) GetNonce() uint64 { +func (x *BlockHeaderMessage) GetNonce() uint64 { if x != nil { return x.Nonce } @@ -1931,7 +2000,7 @@ func (x *BlockLocatorMessage) GetHashes() []*Hash { } // GetBlocksMessage start -type RequestIBDBlocksMessage struct { +type RequestHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1940,8 +2009,8 @@ type RequestIBDBlocksMessage struct { HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` } -func (x *RequestIBDBlocksMessage) Reset() { - *x = RequestIBDBlocksMessage{} +func (x *RequestHeadersMessage) Reset() { + *x = RequestHeadersMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1949,13 +2018,13 @@ func (x *RequestIBDBlocksMessage) Reset() { } } -func (x *RequestIBDBlocksMessage) String() string { +func (x *RequestHeadersMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RequestIBDBlocksMessage) ProtoMessage() {} +func (*RequestHeadersMessage) ProtoMessage() {} -func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { +func (x *RequestHeadersMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1967,19 +2036,19 @@ func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. -func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use RequestHeadersMessage.ProtoReflect.Descriptor instead. +func (*RequestHeadersMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{15} } -func (x *RequestIBDBlocksMessage) GetLowHash() *Hash { +func (x *RequestHeadersMessage) GetLowHash() *Hash { if x != nil { return x.LowHash } return nil } -func (x *RequestIBDBlocksMessage) GetHighHash() *Hash { +func (x *RequestHeadersMessage) GetHighHash() *Hash { if x != nil { return x.HighHash } @@ -1987,14 +2056,14 @@ func (x *RequestIBDBlocksMessage) GetHighHash() *Hash { } // RequestNextIBDBlocksMessage start -type RequestNextIBDBlocksMessage struct { +type RequestNextHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *RequestNextIBDBlocksMessage) Reset() { - *x = RequestNextIBDBlocksMessage{} +func (x *RequestNextHeadersMessage) Reset() { + *x = RequestNextHeadersMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2002,13 +2071,13 @@ func (x *RequestNextIBDBlocksMessage) Reset() { } } -func (x *RequestNextIBDBlocksMessage) String() string { +func (x *RequestNextHeadersMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RequestNextIBDBlocksMessage) ProtoMessage() {} +func (*RequestNextHeadersMessage) ProtoMessage() {} -func (x *RequestNextIBDBlocksMessage) ProtoReflect() protoreflect.Message { +func (x *RequestNextHeadersMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2020,20 +2089,20 @@ func (x *RequestNextIBDBlocksMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use RequestNextIBDBlocksMessage.ProtoReflect.Descriptor instead. -func (*RequestNextIBDBlocksMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use RequestNextHeadersMessage.ProtoReflect.Descriptor instead. +func (*RequestNextHeadersMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{16} } // DoneIBDBlocksMessage start -type DoneIBDBlocksMessage struct { +type DoneHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *DoneIBDBlocksMessage) Reset() { - *x = DoneIBDBlocksMessage{} +func (x *DoneHeadersMessage) Reset() { + *x = DoneHeadersMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2041,13 +2110,13 @@ func (x *DoneIBDBlocksMessage) Reset() { } } -func (x *DoneIBDBlocksMessage) String() string { +func (x *DoneHeadersMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DoneIBDBlocksMessage) ProtoMessage() {} +func (*DoneHeadersMessage) ProtoMessage() {} -func (x *DoneIBDBlocksMessage) ProtoReflect() protoreflect.Message { +func (x *DoneHeadersMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2059,12 +2128,12 @@ func (x *DoneIBDBlocksMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DoneIBDBlocksMessage.ProtoReflect.Descriptor instead. -func (*DoneIBDBlocksMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use DoneHeadersMessage.ProtoReflect.Descriptor instead. +func (*DoneHeadersMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{17} } -// GetRelayBlocksMessage start +// RequestRelayBlocksMessage start type RequestRelayBlocksMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2694,6 +2763,197 @@ func (x *RejectMessage) GetReason() string { return "" } +// RequestIBDRootUTXOSetAndBlockMessage start +type RequestIBDRootUTXOSetAndBlockMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IbdRoot *Hash `protobuf:"bytes,1,opt,name=ibdRoot,proto3" json:"ibdRoot,omitempty"` +} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { + *x = RequestIBDRootUTXOSetAndBlockMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestIBDRootUTXOSetAndBlockMessage) ProtoMessage() {} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestIBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. +func (*RequestIBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{30} +} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { + if x != nil { + return x.IbdRoot + } + return nil +} + +// IBDRootUTXOSetAndBlockMessage start +type IBDRootUTXOSetAndBlockMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UtxoSet []byte `protobuf:"bytes,1,opt,name=utxoSet,proto3" json:"utxoSet,omitempty"` + Block *BlockMessage `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` +} + +func (x *IBDRootUTXOSetAndBlockMessage) Reset() { + *x = IBDRootUTXOSetAndBlockMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IBDRootUTXOSetAndBlockMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IBDRootUTXOSetAndBlockMessage) ProtoMessage() {} + +func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. +func (*IBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{31} +} + +func (x *IBDRootUTXOSetAndBlockMessage) GetUtxoSet() []byte { + if x != nil { + return x.UtxoSet + } + return nil +} + +func (x *IBDRootUTXOSetAndBlockMessage) GetBlock() *BlockMessage { + if x != nil { + return x.Block + } + return nil +} + +// RequestIBDBlocksMessage start +type RequestIBDBlocksMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` +} + +func (x *RequestIBDBlocksMessage) Reset() { + *x = RequestIBDBlocksMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestIBDBlocksMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestIBDBlocksMessage) ProtoMessage() {} + +func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. +func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{32} +} + +func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { + if x != nil { + return x.Hashes + } + return nil +} + +// IBDRootNotFoundMessage start +type IBDRootNotFoundMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *IBDRootNotFoundMessage) Reset() { + *x = IBDRootNotFoundMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IBDRootNotFoundMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IBDRootNotFoundMessage) ProtoMessage() {} + +func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. +func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{33} +} + type RPCError struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2705,7 +2965,7 @@ type RPCError struct { func (x *RPCError) Reset() { *x = RPCError{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[30] + mi := &file_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2718,7 +2978,7 @@ func (x *RPCError) String() string { func (*RPCError) ProtoMessage() {} func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[30] + mi := &file_messages_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2731,7 +2991,7 @@ func (x *RPCError) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCError.ProtoReflect.Descriptor instead. func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{30} + return file_messages_proto_rawDescGZIP(), []int{34} } func (x *RPCError) GetMessage() string { @@ -2750,7 +3010,7 @@ type GetCurrentNetworkRequestMessage struct { func (x *GetCurrentNetworkRequestMessage) Reset() { *x = GetCurrentNetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[31] + mi := &file_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2763,7 +3023,7 @@ func (x *GetCurrentNetworkRequestMessage) String() string { func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[31] + mi := &file_messages_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2776,7 +3036,7 @@ func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{31} + return file_messages_proto_rawDescGZIP(), []int{35} } type GetCurrentNetworkResponseMessage struct { @@ -2791,7 +3051,7 @@ type GetCurrentNetworkResponseMessage struct { func (x *GetCurrentNetworkResponseMessage) Reset() { *x = GetCurrentNetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2804,7 +3064,7 @@ func (x *GetCurrentNetworkResponseMessage) String() string { func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2817,7 +3077,7 @@ func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{32} + return file_messages_proto_rawDescGZIP(), []int{36} } func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { @@ -2845,7 +3105,7 @@ type SubmitBlockRequestMessage struct { func (x *SubmitBlockRequestMessage) Reset() { *x = SubmitBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2858,7 +3118,7 @@ func (x *SubmitBlockRequestMessage) String() string { func (*SubmitBlockRequestMessage) ProtoMessage() {} func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2871,7 +3131,7 @@ func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{33} + return file_messages_proto_rawDescGZIP(), []int{37} } func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { @@ -2892,7 +3152,7 @@ type SubmitBlockResponseMessage struct { func (x *SubmitBlockResponseMessage) Reset() { *x = SubmitBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2905,7 +3165,7 @@ func (x *SubmitBlockResponseMessage) String() string { func (*SubmitBlockResponseMessage) ProtoMessage() {} func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2918,7 +3178,7 @@ func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} + return file_messages_proto_rawDescGZIP(), []int{38} } func (x *SubmitBlockResponseMessage) GetError() *RPCError { @@ -2939,7 +3199,7 @@ type GetBlockTemplateRequestMessage struct { func (x *GetBlockTemplateRequestMessage) Reset() { *x = GetBlockTemplateRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2952,7 +3212,7 @@ func (x *GetBlockTemplateRequestMessage) String() string { func (*GetBlockTemplateRequestMessage) ProtoMessage() {} func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2965,7 +3225,7 @@ func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{35} + return file_messages_proto_rawDescGZIP(), []int{39} } func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { @@ -2987,7 +3247,7 @@ type GetBlockTemplateResponseMessage struct { func (x *GetBlockTemplateResponseMessage) Reset() { *x = GetBlockTemplateResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3000,7 +3260,7 @@ func (x *GetBlockTemplateResponseMessage) String() string { func (*GetBlockTemplateResponseMessage) ProtoMessage() {} func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3013,7 +3273,7 @@ func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} + return file_messages_proto_rawDescGZIP(), []int{40} } func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { @@ -3039,7 +3299,7 @@ type NotifyBlockAddedRequestMessage struct { func (x *NotifyBlockAddedRequestMessage) Reset() { *x = NotifyBlockAddedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3052,7 +3312,7 @@ func (x *NotifyBlockAddedRequestMessage) String() string { func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3065,7 +3325,7 @@ func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} + return file_messages_proto_rawDescGZIP(), []int{41} } type NotifyBlockAddedResponseMessage struct { @@ -3079,7 +3339,7 @@ type NotifyBlockAddedResponseMessage struct { func (x *NotifyBlockAddedResponseMessage) Reset() { *x = NotifyBlockAddedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3092,7 +3352,7 @@ func (x *NotifyBlockAddedResponseMessage) String() string { func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3105,7 +3365,7 @@ func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} + return file_messages_proto_rawDescGZIP(), []int{42} } func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { @@ -3126,7 +3386,7 @@ type BlockAddedNotificationMessage struct { func (x *BlockAddedNotificationMessage) Reset() { *x = BlockAddedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3139,7 +3399,7 @@ func (x *BlockAddedNotificationMessage) String() string { func (*BlockAddedNotificationMessage) ProtoMessage() {} func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3152,7 +3412,7 @@ func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} + return file_messages_proto_rawDescGZIP(), []int{43} } func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { @@ -3171,7 +3431,7 @@ type GetPeerAddressesRequestMessage struct { func (x *GetPeerAddressesRequestMessage) Reset() { *x = GetPeerAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3184,7 +3444,7 @@ func (x *GetPeerAddressesRequestMessage) String() string { func (*GetPeerAddressesRequestMessage) ProtoMessage() {} func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3197,7 +3457,7 @@ func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} + return file_messages_proto_rawDescGZIP(), []int{44} } type GetPeerAddressesResponseMessage struct { @@ -3212,7 +3472,7 @@ type GetPeerAddressesResponseMessage struct { func (x *GetPeerAddressesResponseMessage) Reset() { *x = GetPeerAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3225,7 +3485,7 @@ func (x *GetPeerAddressesResponseMessage) String() string { func (*GetPeerAddressesResponseMessage) ProtoMessage() {} func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3238,7 +3498,7 @@ func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} + return file_messages_proto_rawDescGZIP(), []int{45} } func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { @@ -3266,7 +3526,7 @@ type GetPeerAddressesKnownAddressMessage struct { func (x *GetPeerAddressesKnownAddressMessage) Reset() { *x = GetPeerAddressesKnownAddressMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3279,7 +3539,7 @@ func (x *GetPeerAddressesKnownAddressMessage) String() string { func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3292,7 +3552,7 @@ func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} + return file_messages_proto_rawDescGZIP(), []int{46} } func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { @@ -3311,7 +3571,7 @@ type GetSelectedTipHashRequestMessage struct { func (x *GetSelectedTipHashRequestMessage) Reset() { *x = GetSelectedTipHashRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3324,7 +3584,7 @@ func (x *GetSelectedTipHashRequestMessage) String() string { func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3337,7 +3597,7 @@ func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} + return file_messages_proto_rawDescGZIP(), []int{47} } type GetSelectedTipHashResponseMessage struct { @@ -3352,7 +3612,7 @@ type GetSelectedTipHashResponseMessage struct { func (x *GetSelectedTipHashResponseMessage) Reset() { *x = GetSelectedTipHashResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3365,7 +3625,7 @@ func (x *GetSelectedTipHashResponseMessage) String() string { func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3378,7 +3638,7 @@ func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} + return file_messages_proto_rawDescGZIP(), []int{48} } func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { @@ -3408,7 +3668,7 @@ type MempoolEntry struct { func (x *MempoolEntry) Reset() { *x = MempoolEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3421,7 +3681,7 @@ func (x *MempoolEntry) String() string { func (*MempoolEntry) ProtoMessage() {} func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3434,7 +3694,7 @@ func (x *MempoolEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} + return file_messages_proto_rawDescGZIP(), []int{49} } func (x *MempoolEntry) GetFee() uint64 { @@ -3462,7 +3722,7 @@ type GetMempoolEntryRequestMessage struct { func (x *GetMempoolEntryRequestMessage) Reset() { *x = GetMempoolEntryRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3475,7 +3735,7 @@ func (x *GetMempoolEntryRequestMessage) String() string { func (*GetMempoolEntryRequestMessage) ProtoMessage() {} func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3488,7 +3748,7 @@ func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} + return file_messages_proto_rawDescGZIP(), []int{50} } func (x *GetMempoolEntryRequestMessage) GetTxId() string { @@ -3510,7 +3770,7 @@ type GetMempoolEntryResponseMessage struct { func (x *GetMempoolEntryResponseMessage) Reset() { *x = GetMempoolEntryResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3523,7 +3783,7 @@ func (x *GetMempoolEntryResponseMessage) String() string { func (*GetMempoolEntryResponseMessage) ProtoMessage() {} func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3536,7 +3796,7 @@ func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} + return file_messages_proto_rawDescGZIP(), []int{51} } func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { @@ -3562,7 +3822,7 @@ type GetMempoolEntriesRequestMessage struct { func (x *GetMempoolEntriesRequestMessage) Reset() { *x = GetMempoolEntriesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3575,7 +3835,7 @@ func (x *GetMempoolEntriesRequestMessage) String() string { func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3588,7 +3848,7 @@ func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} + return file_messages_proto_rawDescGZIP(), []int{52} } type GetMempoolEntriesResponseMessage struct { @@ -3603,7 +3863,7 @@ type GetMempoolEntriesResponseMessage struct { func (x *GetMempoolEntriesResponseMessage) Reset() { *x = GetMempoolEntriesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3616,7 +3876,7 @@ func (x *GetMempoolEntriesResponseMessage) String() string { func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3629,7 +3889,7 @@ func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} + return file_messages_proto_rawDescGZIP(), []int{53} } func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { @@ -3655,7 +3915,7 @@ type GetConnectedPeerInfoRequestMessage struct { func (x *GetConnectedPeerInfoRequestMessage) Reset() { *x = GetConnectedPeerInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3668,7 +3928,7 @@ func (x *GetConnectedPeerInfoRequestMessage) String() string { func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3681,7 +3941,7 @@ func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} + return file_messages_proto_rawDescGZIP(), []int{54} } type GetConnectedPeerInfoResponseMessage struct { @@ -3696,7 +3956,7 @@ type GetConnectedPeerInfoResponseMessage struct { func (x *GetConnectedPeerInfoResponseMessage) Reset() { *x = GetConnectedPeerInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3709,7 +3969,7 @@ func (x *GetConnectedPeerInfoResponseMessage) String() string { func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3722,7 +3982,7 @@ func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} + return file_messages_proto_rawDescGZIP(), []int{55} } func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { @@ -3759,7 +4019,7 @@ type GetConnectedPeerInfoMessage struct { func (x *GetConnectedPeerInfoMessage) Reset() { *x = GetConnectedPeerInfoMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3772,7 +4032,7 @@ func (x *GetConnectedPeerInfoMessage) String() string { func (*GetConnectedPeerInfoMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3785,7 +4045,7 @@ func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} + return file_messages_proto_rawDescGZIP(), []int{56} } func (x *GetConnectedPeerInfoMessage) GetId() string { @@ -3870,7 +4130,7 @@ type AddPeerRequestMessage struct { func (x *AddPeerRequestMessage) Reset() { *x = AddPeerRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3883,7 +4143,7 @@ func (x *AddPeerRequestMessage) String() string { func (*AddPeerRequestMessage) ProtoMessage() {} func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3896,7 +4156,7 @@ func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} + return file_messages_proto_rawDescGZIP(), []int{57} } func (x *AddPeerRequestMessage) GetAddress() string { @@ -3924,7 +4184,7 @@ type AddPeerResponseMessage struct { func (x *AddPeerResponseMessage) Reset() { *x = AddPeerResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3937,7 +4197,7 @@ func (x *AddPeerResponseMessage) String() string { func (*AddPeerResponseMessage) ProtoMessage() {} func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3950,7 +4210,7 @@ func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} + return file_messages_proto_rawDescGZIP(), []int{58} } func (x *AddPeerResponseMessage) GetError() *RPCError { @@ -3971,7 +4231,7 @@ type SubmitTransactionRequestMessage struct { func (x *SubmitTransactionRequestMessage) Reset() { *x = SubmitTransactionRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3984,7 +4244,7 @@ func (x *SubmitTransactionRequestMessage) String() string { func (*SubmitTransactionRequestMessage) ProtoMessage() {} func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3997,7 +4257,7 @@ func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} + return file_messages_proto_rawDescGZIP(), []int{59} } func (x *SubmitTransactionRequestMessage) GetTransactionMessage() *TransactionMessage { @@ -4019,7 +4279,7 @@ type SubmitTransactionResponseMessage struct { func (x *SubmitTransactionResponseMessage) Reset() { *x = SubmitTransactionResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4032,7 +4292,7 @@ func (x *SubmitTransactionResponseMessage) String() string { func (*SubmitTransactionResponseMessage) ProtoMessage() {} func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4045,7 +4305,7 @@ func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} + return file_messages_proto_rawDescGZIP(), []int{60} } func (x *SubmitTransactionResponseMessage) GetTxId() string { @@ -4071,7 +4331,7 @@ type NotifyChainChangedRequestMessage struct { func (x *NotifyChainChangedRequestMessage) Reset() { *x = NotifyChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4084,7 +4344,7 @@ func (x *NotifyChainChangedRequestMessage) String() string { func (*NotifyChainChangedRequestMessage) ProtoMessage() {} func (x *NotifyChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4097,7 +4357,7 @@ func (x *NotifyChainChangedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyChainChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} + return file_messages_proto_rawDescGZIP(), []int{61} } type NotifyChainChangedResponseMessage struct { @@ -4111,7 +4371,7 @@ type NotifyChainChangedResponseMessage struct { func (x *NotifyChainChangedResponseMessage) Reset() { *x = NotifyChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4124,7 +4384,7 @@ func (x *NotifyChainChangedResponseMessage) String() string { func (*NotifyChainChangedResponseMessage) ProtoMessage() {} func (x *NotifyChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4137,7 +4397,7 @@ func (x *NotifyChainChangedResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use NotifyChainChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} + return file_messages_proto_rawDescGZIP(), []int{62} } func (x *NotifyChainChangedResponseMessage) GetError() *RPCError { @@ -4159,7 +4419,7 @@ type ChainChangedNotificationMessage struct { func (x *ChainChangedNotificationMessage) Reset() { *x = ChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4172,7 +4432,7 @@ func (x *ChainChangedNotificationMessage) String() string { func (*ChainChangedNotificationMessage) ProtoMessage() {} func (x *ChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4185,7 +4445,7 @@ func (x *ChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*ChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} + return file_messages_proto_rawDescGZIP(), []int{63} } func (x *ChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { @@ -4214,7 +4474,7 @@ type ChainBlock struct { func (x *ChainBlock) Reset() { *x = ChainBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4227,7 +4487,7 @@ func (x *ChainBlock) String() string { func (*ChainBlock) ProtoMessage() {} func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4240,7 +4500,7 @@ func (x *ChainBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} + return file_messages_proto_rawDescGZIP(), []int{64} } func (x *ChainBlock) GetHash() string { @@ -4269,7 +4529,7 @@ type AcceptedBlock struct { func (x *AcceptedBlock) Reset() { *x = AcceptedBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4282,7 +4542,7 @@ func (x *AcceptedBlock) String() string { func (*AcceptedBlock) ProtoMessage() {} func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4295,7 +4555,7 @@ func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} + return file_messages_proto_rawDescGZIP(), []int{65} } func (x *AcceptedBlock) GetHash() string { @@ -4325,7 +4585,7 @@ type GetBlockRequestMessage struct { func (x *GetBlockRequestMessage) Reset() { *x = GetBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4338,7 +4598,7 @@ func (x *GetBlockRequestMessage) String() string { func (*GetBlockRequestMessage) ProtoMessage() {} func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4351,7 +4611,7 @@ func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} + return file_messages_proto_rawDescGZIP(), []int{66} } func (x *GetBlockRequestMessage) GetHash() string { @@ -4388,7 +4648,7 @@ type GetBlockResponseMessage struct { func (x *GetBlockResponseMessage) Reset() { *x = GetBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4401,7 +4661,7 @@ func (x *GetBlockResponseMessage) String() string { func (*GetBlockResponseMessage) ProtoMessage() {} func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4414,7 +4674,7 @@ func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} + return file_messages_proto_rawDescGZIP(), []int{67} } func (x *GetBlockResponseMessage) GetBlockHash() string { @@ -4462,7 +4722,7 @@ type BlockVerboseData struct { func (x *BlockVerboseData) Reset() { *x = BlockVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4475,7 +4735,7 @@ func (x *BlockVerboseData) String() string { func (*BlockVerboseData) ProtoMessage() {} func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4488,7 +4748,7 @@ func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} + return file_messages_proto_rawDescGZIP(), []int{68} } func (x *BlockVerboseData) GetHash() string { @@ -4613,7 +4873,7 @@ type TransactionVerboseData struct { func (x *TransactionVerboseData) Reset() { *x = TransactionVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4626,7 +4886,7 @@ func (x *TransactionVerboseData) String() string { func (*TransactionVerboseData) ProtoMessage() {} func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4639,7 +4899,7 @@ func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} + return file_messages_proto_rawDescGZIP(), []int{69} } func (x *TransactionVerboseData) GetTxId() string { @@ -4754,7 +5014,7 @@ type TransactionVerboseInput struct { func (x *TransactionVerboseInput) Reset() { *x = TransactionVerboseInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4767,7 +5027,7 @@ func (x *TransactionVerboseInput) String() string { func (*TransactionVerboseInput) ProtoMessage() {} func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4780,7 +5040,7 @@ func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} + return file_messages_proto_rawDescGZIP(), []int{70} } func (x *TransactionVerboseInput) GetTxId() string { @@ -4823,7 +5083,7 @@ type ScriptSig struct { func (x *ScriptSig) Reset() { *x = ScriptSig{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4836,7 +5096,7 @@ func (x *ScriptSig) String() string { func (*ScriptSig) ProtoMessage() {} func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4849,7 +5109,7 @@ func (x *ScriptSig) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} + return file_messages_proto_rawDescGZIP(), []int{71} } func (x *ScriptSig) GetAsm() string { @@ -4879,7 +5139,7 @@ type TransactionVerboseOutput struct { func (x *TransactionVerboseOutput) Reset() { *x = TransactionVerboseOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4892,7 +5152,7 @@ func (x *TransactionVerboseOutput) String() string { func (*TransactionVerboseOutput) ProtoMessage() {} func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4905,7 +5165,7 @@ func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} + return file_messages_proto_rawDescGZIP(), []int{72} } func (x *TransactionVerboseOutput) GetValue() uint64 { @@ -4943,7 +5203,7 @@ type ScriptPubKeyResult struct { func (x *ScriptPubKeyResult) Reset() { *x = ScriptPubKeyResult{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4956,7 +5216,7 @@ func (x *ScriptPubKeyResult) String() string { func (*ScriptPubKeyResult) ProtoMessage() {} func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4969,7 +5229,7 @@ func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptPubKeyResult.ProtoReflect.Descriptor instead. func (*ScriptPubKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} + return file_messages_proto_rawDescGZIP(), []int{73} } func (x *ScriptPubKeyResult) GetAsm() string { @@ -5011,7 +5271,7 @@ type GetSubnetworkRequestMessage struct { func (x *GetSubnetworkRequestMessage) Reset() { *x = GetSubnetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5024,7 +5284,7 @@ func (x *GetSubnetworkRequestMessage) String() string { func (*GetSubnetworkRequestMessage) ProtoMessage() {} func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5037,7 +5297,7 @@ func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} + return file_messages_proto_rawDescGZIP(), []int{74} } func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { @@ -5059,7 +5319,7 @@ type GetSubnetworkResponseMessage struct { func (x *GetSubnetworkResponseMessage) Reset() { *x = GetSubnetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5072,7 +5332,7 @@ func (x *GetSubnetworkResponseMessage) String() string { func (*GetSubnetworkResponseMessage) ProtoMessage() {} func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5085,7 +5345,7 @@ func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} + return file_messages_proto_rawDescGZIP(), []int{75} } func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { @@ -5114,7 +5374,7 @@ type GetChainFromBlockRequestMessage struct { func (x *GetChainFromBlockRequestMessage) Reset() { *x = GetChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5127,7 +5387,7 @@ func (x *GetChainFromBlockRequestMessage) String() string { func (*GetChainFromBlockRequestMessage) ProtoMessage() {} func (x *GetChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5140,7 +5400,7 @@ func (x *GetChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} + return file_messages_proto_rawDescGZIP(), []int{76} } func (x *GetChainFromBlockRequestMessage) GetStartHash() string { @@ -5171,7 +5431,7 @@ type GetChainFromBlockResponseMessage struct { func (x *GetChainFromBlockResponseMessage) Reset() { *x = GetChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5184,7 +5444,7 @@ func (x *GetChainFromBlockResponseMessage) String() string { func (*GetChainFromBlockResponseMessage) ProtoMessage() {} func (x *GetChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5197,7 +5457,7 @@ func (x *GetChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} + return file_messages_proto_rawDescGZIP(), []int{77} } func (x *GetChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { @@ -5242,7 +5502,7 @@ type GetBlocksRequestMessage struct { func (x *GetBlocksRequestMessage) Reset() { *x = GetBlocksRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5255,7 +5515,7 @@ func (x *GetBlocksRequestMessage) String() string { func (*GetBlocksRequestMessage) ProtoMessage() {} func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5268,7 +5528,7 @@ func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} + return file_messages_proto_rawDescGZIP(), []int{78} } func (x *GetBlocksRequestMessage) GetLowHash() string { @@ -5313,7 +5573,7 @@ type GetBlocksResponseMessage struct { func (x *GetBlocksResponseMessage) Reset() { *x = GetBlocksResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5326,7 +5586,7 @@ func (x *GetBlocksResponseMessage) String() string { func (*GetBlocksResponseMessage) ProtoMessage() {} func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5339,7 +5599,7 @@ func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} + return file_messages_proto_rawDescGZIP(), []int{79} } func (x *GetBlocksResponseMessage) GetBlockHashes() []string { @@ -5379,7 +5639,7 @@ type GetBlockCountRequestMessage struct { func (x *GetBlockCountRequestMessage) Reset() { *x = GetBlockCountRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5392,7 +5652,7 @@ func (x *GetBlockCountRequestMessage) String() string { func (*GetBlockCountRequestMessage) ProtoMessage() {} func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5405,7 +5665,7 @@ func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} + return file_messages_proto_rawDescGZIP(), []int{80} } type GetBlockCountResponseMessage struct { @@ -5420,7 +5680,7 @@ type GetBlockCountResponseMessage struct { func (x *GetBlockCountResponseMessage) Reset() { *x = GetBlockCountResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5433,7 +5693,7 @@ func (x *GetBlockCountResponseMessage) String() string { func (*GetBlockCountResponseMessage) ProtoMessage() {} func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5446,7 +5706,7 @@ func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} + return file_messages_proto_rawDescGZIP(), []int{81} } func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { @@ -5472,7 +5732,7 @@ type GetBlockDagInfoRequestMessage struct { func (x *GetBlockDagInfoRequestMessage) Reset() { *x = GetBlockDagInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5485,7 +5745,7 @@ func (x *GetBlockDagInfoRequestMessage) String() string { func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5498,7 +5758,7 @@ func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} + return file_messages_proto_rawDescGZIP(), []int{82} } type GetBlockDagInfoResponseMessage struct { @@ -5518,7 +5778,7 @@ type GetBlockDagInfoResponseMessage struct { func (x *GetBlockDagInfoResponseMessage) Reset() { *x = GetBlockDagInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5531,7 +5791,7 @@ func (x *GetBlockDagInfoResponseMessage) String() string { func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5544,7 +5804,7 @@ func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} + return file_messages_proto_rawDescGZIP(), []int{83} } func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { @@ -5607,7 +5867,7 @@ type ResolveFinalityConflictRequestMessage struct { func (x *ResolveFinalityConflictRequestMessage) Reset() { *x = ResolveFinalityConflictRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5620,7 +5880,7 @@ func (x *ResolveFinalityConflictRequestMessage) String() string { func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5633,7 +5893,7 @@ func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} + return file_messages_proto_rawDescGZIP(), []int{84} } func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { @@ -5654,7 +5914,7 @@ type ResolveFinalityConflictResponseMessage struct { func (x *ResolveFinalityConflictResponseMessage) Reset() { *x = ResolveFinalityConflictResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5667,7 +5927,7 @@ func (x *ResolveFinalityConflictResponseMessage) String() string { func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5680,7 +5940,7 @@ func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} + return file_messages_proto_rawDescGZIP(), []int{85} } func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { @@ -5699,7 +5959,7 @@ type NotifyFinalityConflictsRequestMessage struct { func (x *NotifyFinalityConflictsRequestMessage) Reset() { *x = NotifyFinalityConflictsRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5712,7 +5972,7 @@ func (x *NotifyFinalityConflictsRequestMessage) String() string { func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5725,7 +5985,7 @@ func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} + return file_messages_proto_rawDescGZIP(), []int{86} } type NotifyFinalityConflictsResponseMessage struct { @@ -5739,7 +5999,7 @@ type NotifyFinalityConflictsResponseMessage struct { func (x *NotifyFinalityConflictsResponseMessage) Reset() { *x = NotifyFinalityConflictsResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5752,7 +6012,7 @@ func (x *NotifyFinalityConflictsResponseMessage) String() string { func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5765,7 +6025,7 @@ func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} + return file_messages_proto_rawDescGZIP(), []int{87} } func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { @@ -5786,7 +6046,7 @@ type FinalityConflictNotificationMessage struct { func (x *FinalityConflictNotificationMessage) Reset() { *x = FinalityConflictNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5799,7 +6059,7 @@ func (x *FinalityConflictNotificationMessage) String() string { func (*FinalityConflictNotificationMessage) ProtoMessage() {} func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5812,7 +6072,7 @@ func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} + return file_messages_proto_rawDescGZIP(), []int{88} } func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { @@ -5833,7 +6093,7 @@ type FinalityConflictResolvedNotificationMessage struct { func (x *FinalityConflictResolvedNotificationMessage) Reset() { *x = FinalityConflictResolvedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5846,7 +6106,7 @@ func (x *FinalityConflictResolvedNotificationMessage) String() string { func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5859,7 +6119,7 @@ func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflec // Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} + return file_messages_proto_rawDescGZIP(), []int{89} } func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { @@ -5878,7 +6138,7 @@ type ShutDownRequestMessage struct { func (x *ShutDownRequestMessage) Reset() { *x = ShutDownRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5891,7 +6151,7 @@ func (x *ShutDownRequestMessage) String() string { func (*ShutDownRequestMessage) ProtoMessage() {} func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5904,7 +6164,7 @@ func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} + return file_messages_proto_rawDescGZIP(), []int{90} } type ShutDownResponseMessage struct { @@ -5918,7 +6178,7 @@ type ShutDownResponseMessage struct { func (x *ShutDownResponseMessage) Reset() { *x = ShutDownResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5931,7 +6191,7 @@ func (x *ShutDownResponseMessage) String() string { func (*ShutDownResponseMessage) ProtoMessage() {} func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5944,7 +6204,7 @@ func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} + return file_messages_proto_rawDescGZIP(), []int{91} } func (x *ShutDownResponseMessage) GetError() *RPCError { @@ -5967,7 +6227,7 @@ type GetHeadersRequestMessage struct { func (x *GetHeadersRequestMessage) Reset() { *x = GetHeadersRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5980,7 +6240,7 @@ func (x *GetHeadersRequestMessage) String() string { func (*GetHeadersRequestMessage) ProtoMessage() {} func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[92] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5993,7 +6253,7 @@ func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} + return file_messages_proto_rawDescGZIP(), []int{92} } func (x *GetHeadersRequestMessage) GetStartHash() string { @@ -6029,7 +6289,7 @@ type GetHeadersResponseMessage struct { func (x *GetHeadersResponseMessage) Reset() { *x = GetHeadersResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6042,7 +6302,7 @@ func (x *GetHeadersResponseMessage) String() string { func (*GetHeadersResponseMessage) ProtoMessage() {} func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[93] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6055,7 +6315,7 @@ func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} + return file_messages_proto_rawDescGZIP(), []int{93} } func (x *GetHeadersResponseMessage) GetHeaders() []string { @@ -6076,7 +6336,7 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0x8d, 0x33, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xbc, 0x36, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -6104,1038 +6364,1083 @@ var file_messages_proto_rawDesc = []byte{ 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x12, 0x5c, 0x0a, 0x14, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, - 0x78, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x14, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x44, 0x6f, 0x6e, 0x65, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x44, 0x6f, 0x6e, - 0x65, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x47, 0x0a, 0x0d, - 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0e, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, - 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, - 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x6f, 0x6e, - 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, - 0x12, 0x41, 0x0a, 0x0b, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x70, 0x12, 0x32, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x13, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x59, - 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, - 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x6a, - 0x65, 0x63, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x69, 0x0a, - 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, - 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, - 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, - 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, - 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, - 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, - 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, - 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, - 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, - 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, - 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, - 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, - 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, - 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, - 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, - 0x6e, 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, 0x12, 0x7e, - 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, - 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, 0x12, 0x75, - 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, - 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, - 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, - 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x50, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, + 0x73, 0x12, 0x4a, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, + 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x44, 0x6f, 0x6e, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xbe, 0x01, 0x0a, 0x10, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x69, 0x6e, + 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, + 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, + 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x41, + 0x0a, 0x0b, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x12, 0x32, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x13, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, + 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x76, + 0x65, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x13, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, + 0x75, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, + 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, + 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x77, + 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, + 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, + 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, + 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, + 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4d, 0x0a, + 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, + 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, + 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x69, 0x0a, 0x18, + 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, + 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, + 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, + 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, + 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, + 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, + 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, + 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, + 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, + 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, + 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, + 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, + 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, + 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 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, 0x48, 0x00, 0x52, 0x14, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 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, 0x48, 0x00, 0x52, + 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x1e, 0x72, 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, + 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, + 0x1f, 0x72, 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, + 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, + 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, 0x12, 0x7e, 0x0a, + 0x1f, 0x6e, 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, + 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, + 0x1c, 0x66, 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, 0x18, 0x91, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 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, 0x48, 0x00, 0x52, 0x24, + 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, + 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, + 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, + 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x50, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xbe, 0x01, 0x0a, 0x10, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x44, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, + 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8c, 0x01, + 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, + 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x22, 0xd3, 0x02, 0x0a, + 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, + 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x44, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, - 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, - 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, - 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8c, - 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, - 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x22, 0xd3, 0x02, - 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, - 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x70, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x76, - 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, - 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, - 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x0d, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xdb, 0x02, 0x0a, 0x0b, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, - 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, - 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, - 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, - 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, - 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, - 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3e, 0x0a, - 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x71, 0x0a, - 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, - 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, - 0x22, 0x1d, 0x0a, 0x1b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, - 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x16, 0x0a, 0x14, 0x44, 0x6f, 0x6e, 0x65, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x1b, 0x0a, - 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, - 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, - 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, - 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, - 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x4f, 0x0a, 0x12, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, - 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8d, 0x03, 0x0a, 0x0e, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, - 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x6b, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x26, 0x0a, 0x0e, - 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, - 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, - 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, - 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, - 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 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, 0x40, 0x0a, 0x1e, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, - 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, + 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, + 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, + 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x0d, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, + 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, + 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, + 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, + 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, + 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, + 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, + 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, + 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, + 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, + 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, + 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, + 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x22, 0x4f, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x8d, 0x03, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, + 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, + 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, + 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, + 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, + 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, + 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 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, 0x40, 0x0a, + 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x8a, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 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, 0x4e, 0x0a, 0x1d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x9b, 0x01, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, + 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, + 0x65, 0x64, 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, 0x4e, 0x0a, + 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, + 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, + 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x9b, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, + 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, - 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, - 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, - 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xff, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, - 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, - 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, - 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, - 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, - 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, - 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x12, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 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, 0x9e, 0x01, 0x0a, 0x1f, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, - 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, - 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, + 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, + 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, + 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xff, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, + 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, + 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, + 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, + 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, + 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, + 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, + 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 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, 0x9e, 0x01, + 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, + 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, + 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, - 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, 0x06, 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, + 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, 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, - 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, + 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, 0x6a, + 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, 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, 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, - 0x43, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, + 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, + 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, 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 ( @@ -7150,7 +7455,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 90) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 94) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage (*AddressesMessage)(nil), // 1: protowire.AddressesMessage @@ -7163,13 +7468,13 @@ var file_messages_proto_goTypes = []interface{}{ (*TransactionID)(nil), // 8: protowire.TransactionID (*TransactionOutput)(nil), // 9: protowire.TransactionOutput (*BlockMessage)(nil), // 10: protowire.BlockMessage - (*BlockHeader)(nil), // 11: protowire.BlockHeader + (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage (*Hash)(nil), // 12: protowire.Hash (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage - (*RequestIBDBlocksMessage)(nil), // 15: protowire.RequestIBDBlocksMessage - (*RequestNextIBDBlocksMessage)(nil), // 16: protowire.RequestNextIBDBlocksMessage - (*DoneIBDBlocksMessage)(nil), // 17: protowire.DoneIBDBlocksMessage + (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage (*RequestSelectedTipMessage)(nil), // 19: protowire.RequestSelectedTipMessage (*RequestTransactionsMessage)(nil), // 20: protowire.RequestTransactionsMessage @@ -7182,66 +7487,70 @@ var file_messages_proto_goTypes = []interface{}{ (*VerackMessage)(nil), // 27: protowire.VerackMessage (*VersionMessage)(nil), // 28: protowire.VersionMessage (*RejectMessage)(nil), // 29: protowire.RejectMessage - (*RPCError)(nil), // 30: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 31: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 32: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 33: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 34: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 35: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 36: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 37: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 38: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 39: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 40: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 41: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 42: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 43: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 44: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 45: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 46: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 47: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 48: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 49: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 50: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 51: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 52: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 53: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 54: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 55: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 56: protowire.SubmitTransactionResponseMessage - (*NotifyChainChangedRequestMessage)(nil), // 57: protowire.NotifyChainChangedRequestMessage - (*NotifyChainChangedResponseMessage)(nil), // 58: protowire.NotifyChainChangedResponseMessage - (*ChainChangedNotificationMessage)(nil), // 59: protowire.ChainChangedNotificationMessage - (*ChainBlock)(nil), // 60: protowire.ChainBlock - (*AcceptedBlock)(nil), // 61: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 62: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 63: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 64: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 65: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 66: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 67: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 68: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 69: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 70: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 71: protowire.GetSubnetworkResponseMessage - (*GetChainFromBlockRequestMessage)(nil), // 72: protowire.GetChainFromBlockRequestMessage - (*GetChainFromBlockResponseMessage)(nil), // 73: protowire.GetChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 74: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 75: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 76: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 77: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 78: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 79: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 80: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 81: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 82: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 83: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 84: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 85: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 86: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 87: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 88: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 89: protowire.GetHeadersResponseMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 30: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IBDRootUTXOSetAndBlockMessage)(nil), // 31: protowire.IBDRootUTXOSetAndBlockMessage + (*RequestIBDBlocksMessage)(nil), // 32: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 33: protowire.IBDRootNotFoundMessage + (*RPCError)(nil), // 34: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 35: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 36: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 37: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 38: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 39: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 40: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 41: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 42: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 43: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 44: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 45: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 46: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 47: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 48: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 49: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 50: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 51: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 52: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 53: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 54: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 55: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 56: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 57: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 58: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 59: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 60: protowire.SubmitTransactionResponseMessage + (*NotifyChainChangedRequestMessage)(nil), // 61: protowire.NotifyChainChangedRequestMessage + (*NotifyChainChangedResponseMessage)(nil), // 62: protowire.NotifyChainChangedResponseMessage + (*ChainChangedNotificationMessage)(nil), // 63: protowire.ChainChangedNotificationMessage + (*ChainBlock)(nil), // 64: protowire.ChainBlock + (*AcceptedBlock)(nil), // 65: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 66: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 67: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 68: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 69: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 70: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 71: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 72: protowire.TransactionVerboseOutput + (*ScriptPubKeyResult)(nil), // 73: protowire.ScriptPubKeyResult + (*GetSubnetworkRequestMessage)(nil), // 74: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 75: protowire.GetSubnetworkResponseMessage + (*GetChainFromBlockRequestMessage)(nil), // 76: protowire.GetChainFromBlockRequestMessage + (*GetChainFromBlockResponseMessage)(nil), // 77: protowire.GetChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 78: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 79: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 80: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 81: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 82: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 83: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 84: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 85: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 86: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 87: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 88: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 89: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 90: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 91: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 92: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 93: protowire.GetHeadersResponseMessage } var file_messages_proto_depIdxs = []int32{ 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -7250,9 +7559,9 @@ var file_messages_proto_depIdxs = []int32{ 13, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage 14, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage 4, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage - 15, // 6: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 16, // 7: protowire.KaspadMessage.requestNextIBDBlocks:type_name -> protowire.RequestNextIBDBlocksMessage - 17, // 8: protowire.KaspadMessage.DoneIBDBlocks:type_name -> protowire.DoneIBDBlocksMessage + 15, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage + 16, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage + 17, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage 18, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage 19, // 10: protowire.KaspadMessage.requestSelectedTip:type_name -> protowire.RequestSelectedTipMessage 20, // 11: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage @@ -7266,134 +7575,142 @@ var file_messages_proto_depIdxs = []int32{ 28, // 19: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage 21, // 20: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage 29, // 21: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 31, // 22: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 32, // 23: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 33, // 24: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 34, // 25: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 35, // 26: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 36, // 27: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 37, // 28: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 38, // 29: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 39, // 30: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 40, // 31: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 41, // 32: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 43, // 33: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 44, // 34: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 46, // 35: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 47, // 36: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 50, // 37: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 51, // 38: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 53, // 39: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 54, // 40: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 55, // 41: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 56, // 42: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 57, // 43: protowire.KaspadMessage.notifyChainChangedRequest:type_name -> protowire.NotifyChainChangedRequestMessage - 58, // 44: protowire.KaspadMessage.notifyChainChangedResponse:type_name -> protowire.NotifyChainChangedResponseMessage - 59, // 45: protowire.KaspadMessage.chainChangedNotification:type_name -> protowire.ChainChangedNotificationMessage - 62, // 46: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 63, // 47: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 70, // 48: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 71, // 49: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 72, // 50: protowire.KaspadMessage.getChainFromBlockRequest:type_name -> protowire.GetChainFromBlockRequestMessage - 73, // 51: protowire.KaspadMessage.getChainFromBlockResponse:type_name -> protowire.GetChainFromBlockResponseMessage - 74, // 52: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 75, // 53: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 76, // 54: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 77, // 55: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 78, // 56: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 79, // 57: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 80, // 58: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 81, // 59: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 82, // 60: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 83, // 61: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 84, // 62: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 85, // 63: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 48, // 64: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 49, // 65: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 86, // 66: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 87, // 67: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 88, // 68: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 89, // 69: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 3, // 70: protowire.AddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID - 2, // 71: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 3, // 72: protowire.RequestAddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID - 6, // 73: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 74: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 3, // 75: protowire.TransactionMessage.subnetworkID:type_name -> protowire.SubnetworkID - 12, // 76: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 77: protowire.TransactionInput.PreviousOutpoint:type_name -> protowire.Outpoint - 8, // 78: protowire.Outpoint.transactionID:type_name -> protowire.TransactionID - 11, // 79: protowire.BlockMessage.header:type_name -> protowire.BlockHeader - 5, // 80: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 81: protowire.BlockHeader.parentHashes:type_name -> protowire.Hash - 12, // 82: protowire.BlockHeader.hashMerkleRoot:type_name -> protowire.Hash - 12, // 83: protowire.BlockHeader.acceptedIDMerkleRoot:type_name -> protowire.Hash - 12, // 84: protowire.BlockHeader.utxoCommitment:type_name -> protowire.Hash - 12, // 85: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 86: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 87: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 88: protowire.RequestIBDBlocksMessage.lowHash:type_name -> protowire.Hash - 12, // 89: protowire.RequestIBDBlocksMessage.highHash:type_name -> protowire.Hash - 12, // 90: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 91: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionID - 8, // 92: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionID - 12, // 93: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 94: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionID - 12, // 95: protowire.SelectedTipMessage.selectedTipHash:type_name -> protowire.Hash - 2, // 96: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 12, // 97: protowire.VersionMessage.selectedTipHash:type_name -> protowire.Hash - 3, // 98: protowire.VersionMessage.subnetworkID:type_name -> protowire.SubnetworkID - 30, // 99: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 100: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 30, // 101: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 102: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 30, // 103: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 30, // 104: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 105: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 42, // 106: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 30, // 107: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 30, // 108: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 65, // 109: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 45, // 110: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 30, // 111: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 45, // 112: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 30, // 113: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 52, // 114: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 30, // 115: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 30, // 116: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 5, // 117: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage - 30, // 118: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 30, // 119: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError - 60, // 120: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 61, // 121: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 64, // 122: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 30, // 123: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 65, // 124: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 66, // 125: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 68, // 126: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 67, // 127: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 69, // 128: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 30, // 129: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 60, // 130: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 64, // 131: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 30, // 132: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 64, // 133: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 30, // 134: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 30, // 135: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 30, // 136: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 30, // 137: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 30, // 138: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 30, // 139: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 30, // 140: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 0, // 141: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 142: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 143: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 144: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 143, // [143:145] is the sub-list for method output_type - 141, // [141:143] is the sub-list for method input_type - 141, // [141:141] is the sub-list for extension type_name - 141, // [141:141] is the sub-list for extension extendee - 0, // [0:141] is the sub-list for field type_name + 11, // 22: protowire.KaspadMessage.blockHeader:type_name -> protowire.BlockHeaderMessage + 30, // 23: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage + 31, // 24: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage + 32, // 25: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage + 33, // 26: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage + 35, // 27: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 36, // 28: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 37, // 29: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 38, // 30: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 39, // 31: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 40, // 32: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 41, // 33: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 42, // 34: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 43, // 35: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 44, // 36: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 45, // 37: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 47, // 38: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 48, // 39: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 50, // 40: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 51, // 41: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 54, // 42: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 55, // 43: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 57, // 44: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 58, // 45: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 59, // 46: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 60, // 47: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 61, // 48: protowire.KaspadMessage.notifyChainChangedRequest:type_name -> protowire.NotifyChainChangedRequestMessage + 62, // 49: protowire.KaspadMessage.notifyChainChangedResponse:type_name -> protowire.NotifyChainChangedResponseMessage + 63, // 50: protowire.KaspadMessage.chainChangedNotification:type_name -> protowire.ChainChangedNotificationMessage + 66, // 51: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 67, // 52: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 74, // 53: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 75, // 54: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 76, // 55: protowire.KaspadMessage.getChainFromBlockRequest:type_name -> protowire.GetChainFromBlockRequestMessage + 77, // 56: protowire.KaspadMessage.getChainFromBlockResponse:type_name -> protowire.GetChainFromBlockResponseMessage + 78, // 57: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 79, // 58: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 80, // 59: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 81, // 60: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 82, // 61: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 83, // 62: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 84, // 63: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 85, // 64: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 86, // 65: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 87, // 66: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 88, // 67: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 89, // 68: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 52, // 69: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 53, // 70: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 90, // 71: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 91, // 72: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 92, // 73: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 93, // 74: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 3, // 75: protowire.AddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID + 2, // 76: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 3, // 77: protowire.RequestAddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID + 6, // 78: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 79: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 3, // 80: protowire.TransactionMessage.subnetworkID:type_name -> protowire.SubnetworkID + 12, // 81: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 7, // 82: protowire.TransactionInput.PreviousOutpoint:type_name -> protowire.Outpoint + 8, // 83: protowire.Outpoint.transactionID:type_name -> protowire.TransactionID + 11, // 84: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 85: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 86: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 87: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 88: protowire.BlockHeaderMessage.acceptedIDMerkleRoot:type_name -> protowire.Hash + 12, // 89: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 90: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 91: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 92: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 93: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 94: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 95: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 96: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionID + 8, // 97: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionID + 12, // 98: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 99: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionID + 12, // 100: protowire.SelectedTipMessage.selectedTipHash:type_name -> protowire.Hash + 2, // 101: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 12, // 102: protowire.VersionMessage.selectedTipHash:type_name -> protowire.Hash + 3, // 103: protowire.VersionMessage.subnetworkID:type_name -> protowire.SubnetworkID + 12, // 104: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 105: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 106: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 34, // 107: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 108: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 34, // 109: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 110: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 34, // 111: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 34, // 112: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 113: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 46, // 114: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 34, // 115: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 34, // 116: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 69, // 117: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 49, // 118: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 34, // 119: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 49, // 120: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 34, // 121: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 56, // 122: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 34, // 123: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 124: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 5, // 125: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage + 34, // 126: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 34, // 127: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError + 64, // 128: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 65, // 129: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 68, // 130: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 131: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 69, // 132: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 70, // 133: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 72, // 134: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 71, // 135: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 73, // 136: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 34, // 137: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 64, // 138: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 68, // 139: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 140: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 68, // 141: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 142: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 34, // 143: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 34, // 144: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 145: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 34, // 146: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 34, // 147: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 34, // 148: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 0, // 149: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 150: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 151: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 152: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 151, // [151:153] is the sub-list for method output_type + 149, // [149:151] is the sub-list for method input_type + 149, // [149:149] is the sub-list for extension type_name + 149, // [149:149] is the sub-list for extension extendee + 0, // [0:149] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -7535,7 +7852,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockHeader); i { + switch v := v.(*BlockHeaderMessage); i { case 0: return &v.state case 1: @@ -7583,7 +7900,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDBlocksMessage); i { + switch v := v.(*RequestHeadersMessage); i { case 0: return &v.state case 1: @@ -7595,7 +7912,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestNextIBDBlocksMessage); i { + switch v := v.(*RequestNextHeadersMessage); i { case 0: return &v.state case 1: @@ -7607,7 +7924,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DoneIBDBlocksMessage); i { + switch v := v.(*DoneHeadersMessage); i { case 0: return &v.state case 1: @@ -7763,7 +8080,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCError); i { + switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { case 0: return &v.state case 1: @@ -7775,7 +8092,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkRequestMessage); i { + switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { case 0: return &v.state case 1: @@ -7787,7 +8104,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkResponseMessage); i { + switch v := v.(*RequestIBDBlocksMessage); i { case 0: return &v.state case 1: @@ -7799,7 +8116,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockRequestMessage); i { + switch v := v.(*IBDRootNotFoundMessage); i { case 0: return &v.state case 1: @@ -7811,7 +8128,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockResponseMessage); i { + switch v := v.(*RPCError); i { case 0: return &v.state case 1: @@ -7823,7 +8140,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateRequestMessage); i { + switch v := v.(*GetCurrentNetworkRequestMessage); i { case 0: return &v.state case 1: @@ -7835,7 +8152,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateResponseMessage); i { + switch v := v.(*GetCurrentNetworkResponseMessage); i { case 0: return &v.state case 1: @@ -7847,7 +8164,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedRequestMessage); i { + switch v := v.(*SubmitBlockRequestMessage); i { case 0: return &v.state case 1: @@ -7859,7 +8176,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedResponseMessage); i { + switch v := v.(*SubmitBlockResponseMessage); i { case 0: return &v.state case 1: @@ -7871,7 +8188,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockAddedNotificationMessage); i { + switch v := v.(*GetBlockTemplateRequestMessage); i { case 0: return &v.state case 1: @@ -7883,7 +8200,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesRequestMessage); i { + switch v := v.(*GetBlockTemplateResponseMessage); i { case 0: return &v.state case 1: @@ -7895,7 +8212,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesResponseMessage); i { + switch v := v.(*NotifyBlockAddedRequestMessage); i { case 0: return &v.state case 1: @@ -7907,7 +8224,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesKnownAddressMessage); i { + switch v := v.(*NotifyBlockAddedResponseMessage); i { case 0: return &v.state case 1: @@ -7919,7 +8236,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashRequestMessage); i { + switch v := v.(*BlockAddedNotificationMessage); i { case 0: return &v.state case 1: @@ -7931,7 +8248,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashResponseMessage); i { + switch v := v.(*GetPeerAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -7943,7 +8260,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MempoolEntry); i { + switch v := v.(*GetPeerAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -7955,7 +8272,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryRequestMessage); i { + switch v := v.(*GetPeerAddressesKnownAddressMessage); i { case 0: return &v.state case 1: @@ -7967,7 +8284,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryResponseMessage); i { + switch v := v.(*GetSelectedTipHashRequestMessage); i { case 0: return &v.state case 1: @@ -7979,7 +8296,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesRequestMessage); i { + switch v := v.(*GetSelectedTipHashResponseMessage); i { case 0: return &v.state case 1: @@ -7991,7 +8308,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesResponseMessage); i { + switch v := v.(*MempoolEntry); i { case 0: return &v.state case 1: @@ -8003,7 +8320,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoRequestMessage); i { + switch v := v.(*GetMempoolEntryRequestMessage); i { case 0: return &v.state case 1: @@ -8015,7 +8332,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoResponseMessage); i { + switch v := v.(*GetMempoolEntryResponseMessage); i { case 0: return &v.state case 1: @@ -8027,7 +8344,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoMessage); i { + switch v := v.(*GetMempoolEntriesRequestMessage); i { case 0: return &v.state case 1: @@ -8039,7 +8356,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerRequestMessage); i { + switch v := v.(*GetMempoolEntriesResponseMessage); i { case 0: return &v.state case 1: @@ -8051,7 +8368,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerResponseMessage); i { + switch v := v.(*GetConnectedPeerInfoRequestMessage); i { case 0: return &v.state case 1: @@ -8063,7 +8380,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionRequestMessage); i { + switch v := v.(*GetConnectedPeerInfoResponseMessage); i { case 0: return &v.state case 1: @@ -8075,7 +8392,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionResponseMessage); i { + switch v := v.(*GetConnectedPeerInfoMessage); i { case 0: return &v.state case 1: @@ -8087,7 +8404,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyChainChangedRequestMessage); i { + switch v := v.(*AddPeerRequestMessage); i { case 0: return &v.state case 1: @@ -8099,7 +8416,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyChainChangedResponseMessage); i { + switch v := v.(*AddPeerResponseMessage); i { case 0: return &v.state case 1: @@ -8111,7 +8428,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainChangedNotificationMessage); i { + switch v := v.(*SubmitTransactionRequestMessage); i { case 0: return &v.state case 1: @@ -8123,7 +8440,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainBlock); i { + switch v := v.(*SubmitTransactionResponseMessage); i { case 0: return &v.state case 1: @@ -8135,7 +8452,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptedBlock); i { + switch v := v.(*NotifyChainChangedRequestMessage); i { case 0: return &v.state case 1: @@ -8147,7 +8464,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockRequestMessage); i { + switch v := v.(*NotifyChainChangedResponseMessage); i { case 0: return &v.state case 1: @@ -8159,7 +8476,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockResponseMessage); i { + switch v := v.(*ChainChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -8171,7 +8488,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockVerboseData); i { + switch v := v.(*ChainBlock); i { case 0: return &v.state case 1: @@ -8183,7 +8500,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseData); i { + switch v := v.(*AcceptedBlock); i { case 0: return &v.state case 1: @@ -8195,7 +8512,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseInput); i { + switch v := v.(*GetBlockRequestMessage); i { case 0: return &v.state case 1: @@ -8207,7 +8524,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptSig); i { + switch v := v.(*GetBlockResponseMessage); i { case 0: return &v.state case 1: @@ -8219,7 +8536,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseOutput); i { + switch v := v.(*BlockVerboseData); i { case 0: return &v.state case 1: @@ -8231,7 +8548,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPubKeyResult); i { + switch v := v.(*TransactionVerboseData); i { case 0: return &v.state case 1: @@ -8243,7 +8560,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkRequestMessage); i { + switch v := v.(*TransactionVerboseInput); i { case 0: return &v.state case 1: @@ -8255,7 +8572,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkResponseMessage); i { + switch v := v.(*ScriptSig); i { case 0: return &v.state case 1: @@ -8267,7 +8584,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetChainFromBlockRequestMessage); i { + switch v := v.(*TransactionVerboseOutput); i { case 0: return &v.state case 1: @@ -8279,7 +8596,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetChainFromBlockResponseMessage); i { + switch v := v.(*ScriptPubKeyResult); i { case 0: return &v.state case 1: @@ -8291,7 +8608,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksRequestMessage); i { + switch v := v.(*GetSubnetworkRequestMessage); i { case 0: return &v.state case 1: @@ -8303,7 +8620,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksResponseMessage); i { + switch v := v.(*GetSubnetworkResponseMessage); i { case 0: return &v.state case 1: @@ -8315,7 +8632,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountRequestMessage); i { + switch v := v.(*GetChainFromBlockRequestMessage); i { case 0: return &v.state case 1: @@ -8327,7 +8644,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountResponseMessage); i { + switch v := v.(*GetChainFromBlockResponseMessage); i { case 0: return &v.state case 1: @@ -8339,7 +8656,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoRequestMessage); i { + switch v := v.(*GetBlocksRequestMessage); i { case 0: return &v.state case 1: @@ -8351,7 +8668,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoResponseMessage); i { + switch v := v.(*GetBlocksResponseMessage); i { case 0: return &v.state case 1: @@ -8363,7 +8680,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictRequestMessage); i { + switch v := v.(*GetBlockCountRequestMessage); i { case 0: return &v.state case 1: @@ -8375,7 +8692,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictResponseMessage); i { + switch v := v.(*GetBlockCountResponseMessage); i { case 0: return &v.state case 1: @@ -8387,7 +8704,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsRequestMessage); i { + switch v := v.(*GetBlockDagInfoRequestMessage); i { case 0: return &v.state case 1: @@ -8399,7 +8716,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsResponseMessage); i { + switch v := v.(*GetBlockDagInfoResponseMessage); i { case 0: return &v.state case 1: @@ -8411,7 +8728,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictNotificationMessage); i { + switch v := v.(*ResolveFinalityConflictRequestMessage); i { case 0: return &v.state case 1: @@ -8423,7 +8740,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + switch v := v.(*ResolveFinalityConflictResponseMessage); i { case 0: return &v.state case 1: @@ -8435,7 +8752,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownRequestMessage); i { + switch v := v.(*NotifyFinalityConflictsRequestMessage); i { case 0: return &v.state case 1: @@ -8447,7 +8764,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownResponseMessage); i { + switch v := v.(*NotifyFinalityConflictsResponseMessage); i { case 0: return &v.state case 1: @@ -8459,7 +8776,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersRequestMessage); i { + switch v := v.(*FinalityConflictNotificationMessage); i { case 0: return &v.state case 1: @@ -8471,6 +8788,54 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShutDownRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShutDownResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetHeadersRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetHeadersResponseMessage); i { case 0: return &v.state @@ -8490,9 +8855,9 @@ func file_messages_proto_init() { (*KaspadMessage_RequestBlockLocator)(nil), (*KaspadMessage_BlockLocator)(nil), (*KaspadMessage_RequestAddresses)(nil), - (*KaspadMessage_RequestIBDBlocks)(nil), - (*KaspadMessage_RequestNextIBDBlocks)(nil), - (*KaspadMessage_DoneIBDBlocks)(nil), + (*KaspadMessage_RequestHeaders)(nil), + (*KaspadMessage_RequestNextHeaders)(nil), + (*KaspadMessage_DoneHeaders)(nil), (*KaspadMessage_RequestRelayBlocks)(nil), (*KaspadMessage_RequestSelectedTip)(nil), (*KaspadMessage_RequestTransactions)(nil), @@ -8506,6 +8871,11 @@ func file_messages_proto_init() { (*KaspadMessage_Version)(nil), (*KaspadMessage_TransactionNotFound)(nil), (*KaspadMessage_Reject)(nil), + (*KaspadMessage_BlockHeader)(nil), + (*KaspadMessage_RequestIBDRootUTXOSetAndBlock)(nil), + (*KaspadMessage_IbdRootUTXOSetAndBlock)(nil), + (*KaspadMessage_RequestIBDBlocks)(nil), + (*KaspadMessage_IbdRootNotFound)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), @@ -8561,7 +8931,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 90, + NumMessages: 94, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 3d3a9d7b0..1984055f4 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -11,9 +11,9 @@ message KaspadMessage { RequestBlockLocatorMessage requestBlockLocator = 4; BlockLocatorMessage blockLocator = 5; RequestAddressesMessage requestAddresses = 6; - RequestIBDBlocksMessage requestIBDBlocks = 7; - RequestNextIBDBlocksMessage requestNextIBDBlocks = 8; - DoneIBDBlocksMessage DoneIBDBlocks = 9; + RequestHeadersMessage requestHeaders = 7; + RequestNextHeadersMessage requestNextHeaders = 8; + DoneHeadersMessage DoneHeaders = 9; RequestRelayBlocksMessage requestRelayBlocks = 10; RequestSelectedTipMessage requestSelectedTip = 11; RequestTransactionsMessage requestTransactions = 12; @@ -27,6 +27,11 @@ message KaspadMessage { VersionMessage version = 20; TransactionNotFoundMessage transactionNotFound = 21; RejectMessage reject = 22; + BlockHeaderMessage blockHeader = 23; + RequestIBDRootUTXOSetAndBlockMessage requestIBDRootUTXOSetAndBlock = 24; + IBDRootUTXOSetAndBlockMessage ibdRootUTXOSetAndBlock = 25; + RequestIBDBlocksMessage requestIBDBlocks = 26; + IBDRootNotFoundMessage ibdRootNotFound = 27; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; @@ -144,11 +149,11 @@ message TransactionOutput{ // BlockMessage start message BlockMessage{ - BlockHeader header = 1; + BlockHeaderMessage header = 1; repeated TransactionMessage transactions = 2; } -message BlockHeader{ +message BlockHeaderMessage{ int32 version = 1; repeated Hash parentHashes = 2; Hash hashMerkleRoot = 3; @@ -178,27 +183,27 @@ message BlockLocatorMessage{ // BlockLocatorMessage end // GetBlocksMessage start -message RequestIBDBlocksMessage{ +message RequestHeadersMessage{ Hash lowHash = 1; Hash highHash = 2; } // GetBlocksMessage end // RequestNextIBDBlocksMessage start -message RequestNextIBDBlocksMessage{ +message RequestNextHeadersMessage{ } // RequestNextIBDBlocksMessage end // DoneIBDBlocksMessage start -message DoneIBDBlocksMessage{ +message DoneHeadersMessage{ } // DoneIBDBlocksMessage end -// GetRelayBlocksMessage start +// RequestRelayBlocksMessage start message RequestRelayBlocksMessage{ repeated Hash hashes = 1; } -// GetRelayBlocksMessage end +// RequestRelayBlocksMessage end // GetSelectedTipMessage start message RequestSelectedTipMessage{ @@ -273,6 +278,30 @@ message RejectMessage{ } // RejectMessage end +// RequestIBDRootUTXOSetAndBlockMessage start +message RequestIBDRootUTXOSetAndBlockMessage{ + Hash ibdRoot = 1; +} +// RequestIBDRootUTXOSetAndBlockMessage end + +// IBDRootUTXOSetAndBlockMessage start +message IBDRootUTXOSetAndBlockMessage{ + bytes utxoSet = 1; + BlockMessage block = 2; +} +// IBDRootUTXOSetAndBlockMessage end + +// RequestIBDBlocksMessage start +message RequestIBDBlocksMessage{ + repeated Hash hashes = 1; +} +// RequestIBDBlocksMessage end + +// IBDRootNotFoundMessage start +message IBDRootNotFoundMessage{ +} +// IBDRootNotFoundMessage end + service P2P { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} } @@ -455,7 +484,7 @@ message BlockVerboseData{ double difficulty = 11; repeated string parentHashes = 12; string selectedParentHash = 13; - repeated string transactionIDs=14; + repeated string transactionIDs = 14; } message TransactionVerboseData{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block.go index d3474a9fa..d82d38cc5 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block.go @@ -2,7 +2,6 @@ package protowire import ( "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" ) @@ -15,7 +14,7 @@ func (x *KaspadMessage_Block) fromAppMessage(msgBlock *appmessage.MsgBlock) erro return x.Block.fromAppMessage(msgBlock) } -func (x *BlockMessage) toAppMessage() (appmessage.Message, error) { +func (x *BlockMessage) toAppMessage() (*appmessage.MsgBlock, error) { if len(x.Transactions) > appmessage.MaxTxPerBlock { return nil, errors.Errorf("too many transactions to fit into a block "+ "[count %d, max %d]", len(x.Transactions), appmessage.MaxTxPerBlock) @@ -31,37 +30,11 @@ func (x *BlockMessage) toAppMessage() (appmessage.Message, error) { "is %d", len(protoBlockHeader.ParentHashes), appmessage.MaxBlockParents) } - parentHashes, err := protoHashesToDomain(protoBlockHeader.ParentHashes) + header, err := x.Header.toAppMessage() if err != nil { return nil, err } - hashMerkleRoot, err := protoBlockHeader.HashMerkleRoot.toDomain() - if err != nil { - return nil, err - } - - acceptedIDMerkleRoot, err := protoBlockHeader.AcceptedIDMerkleRoot.toDomain() - if err != nil { - return nil, err - } - - utxoCommitment, err := protoBlockHeader.UtxoCommitment.toDomain() - if err != nil { - return nil, err - } - - header := appmessage.BlockHeader{ - Version: protoBlockHeader.Version, - ParentHashes: parentHashes, - HashMerkleRoot: hashMerkleRoot, - AcceptedIDMerkleRoot: acceptedIDMerkleRoot, - UTXOCommitment: utxoCommitment, - Timestamp: mstime.UnixMilliseconds(protoBlockHeader.Timestamp), - Bits: protoBlockHeader.Bits, - Nonce: protoBlockHeader.Nonce, - } - transactions := make([]*appmessage.MsgTx, len(x.Transactions)) for i, protoTx := range x.Transactions { msgTx, err := protoTx.toAppMessage() @@ -72,7 +45,7 @@ func (x *BlockMessage) toAppMessage() (appmessage.Message, error) { } return &appmessage.MsgBlock{ - Header: header, + Header: *header, Transactions: transactions, }, nil } @@ -88,17 +61,12 @@ func (x *BlockMessage) fromAppMessage(msgBlock *appmessage.MsgBlock) error { "is %d", len(msgBlock.Header.ParentHashes), appmessage.MaxBlockParents) } - header := msgBlock.Header - protoHeader := &BlockHeader{ - Version: header.Version, - ParentHashes: domainHashesToProto(header.ParentHashes), - HashMerkleRoot: domainHashToProto(header.HashMerkleRoot), - AcceptedIDMerkleRoot: domainHashToProto(header.AcceptedIDMerkleRoot), - UtxoCommitment: domainHashToProto(header.UTXOCommitment), - Timestamp: header.Timestamp.UnixMilliseconds(), - Bits: header.Bits, - Nonce: header.Nonce, + protoHeader := new(BlockHeaderMessage) + err := protoHeader.fromAppMessage(&msgBlock.Header) + if err != nil { + return err } + protoTransactions := make([]*TransactionMessage, len(msgBlock.Transactions)) for i, tx := range msgBlock.Transactions { protoTx := new(TransactionMessage) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_blocks.go index 5c12ba77f..566a7e673 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_blocks.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_blocks.go @@ -2,10 +2,10 @@ package protowire import "github.com/kaspanet/kaspad/app/appmessage" -func (x *KaspadMessage_DoneIBDBlocks) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgDoneIBDBlocks{}, nil +func (x *KaspadMessage_DoneHeaders) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgDoneHeaders{}, nil } -func (x *KaspadMessage_DoneIBDBlocks) fromAppMessage(_ *appmessage.MsgDoneIBDBlocks) error { +func (x *KaspadMessage_DoneHeaders) fromAppMessage(_ *appmessage.MsgDoneHeaders) error { return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go new file mode 100644 index 000000000..b95d5644d --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go @@ -0,0 +1,73 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/util/mstime" + "github.com/pkg/errors" +) + +func (x *KaspadMessage_BlockHeader) toAppMessage() (appmessage.Message, error) { + return x.BlockHeader.toAppMessage() +} + +func (x *KaspadMessage_BlockHeader) fromAppMessage(msgBlockHeader *appmessage.MsgBlockHeader) error { + x.BlockHeader = new(BlockHeaderMessage) + return x.BlockHeader.fromAppMessage(msgBlockHeader) +} + +func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) { + if len(x.ParentHashes) > appmessage.MaxBlockParents { + return nil, errors.Errorf("block header has %d parents, but the maximum allowed amount "+ + "is %d", len(x.ParentHashes), appmessage.MaxBlockParents) + } + + parentHashes, err := protoHashesToDomain(x.ParentHashes) + if err != nil { + return nil, err + } + + hashMerkleRoot, err := x.HashMerkleRoot.toDomain() + if err != nil { + return nil, err + } + + acceptedIDMerkleRoot, err := x.AcceptedIDMerkleRoot.toDomain() + if err != nil { + return nil, err + } + + utxoCommitment, err := x.UtxoCommitment.toDomain() + if err != nil { + return nil, err + } + + return &appmessage.MsgBlockHeader{ + Version: x.Version, + ParentHashes: parentHashes, + HashMerkleRoot: hashMerkleRoot, + AcceptedIDMerkleRoot: acceptedIDMerkleRoot, + UTXOCommitment: utxoCommitment, + Timestamp: mstime.UnixMilliseconds(x.Timestamp), + Bits: x.Bits, + Nonce: x.Nonce, + }, nil +} + +func (x *BlockHeaderMessage) fromAppMessage(msgBlockHeader *appmessage.MsgBlockHeader) error { + if len(msgBlockHeader.ParentHashes) > appmessage.MaxBlockParents { + return errors.Errorf("block header has %d parents, but the maximum allowed amount "+ + "is %d", len(msgBlockHeader.ParentHashes), appmessage.MaxBlockParents) + } + + *x = BlockHeaderMessage{ + Version: msgBlockHeader.Version, + ParentHashes: domainHashesToProto(msgBlockHeader.ParentHashes), + HashMerkleRoot: domainHashToProto(msgBlockHeader.HashMerkleRoot), + AcceptedIDMerkleRoot: domainHashToProto(msgBlockHeader.AcceptedIDMerkleRoot), + UtxoCommitment: domainHashToProto(msgBlockHeader.UTXOCommitment), + Timestamp: msgBlockHeader.Timestamp.UnixMilliseconds(), + Bits: msgBlockHeader.Bits, + Nonce: msgBlockHeader.Nonce, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block.go index 1841a9c9f..192524c0e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block.go @@ -7,7 +7,7 @@ func (x *KaspadMessage_IbdBlock) toAppMessage() (appmessage.Message, error) { if err != nil { return nil, err } - return &appmessage.MsgIBDBlock{MsgBlock: msgBlock.(*appmessage.MsgBlock)}, nil + return &appmessage.MsgIBDBlock{MsgBlock: msgBlock}, nil } func (x *KaspadMessage_IbdBlock) fromAppMessage(msgIBDBlock *appmessage.MsgIBDBlock) error { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go new file mode 100644 index 000000000..b22b3eecb --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go @@ -0,0 +1,11 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_IbdRootNotFound) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgIBDRootNotFound{}, nil +} + +func (x *KaspadMessage_IbdRootNotFound) fromAppMessage(_ *appmessage.MsgIBDRootNotFound) error { + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go new file mode 100644 index 000000000..895615b22 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go @@ -0,0 +1,19 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_IbdRootUTXOSetAndBlock) toAppMessage() (appmessage.Message, error) { + msgBlock, err := x.IbdRootUTXOSetAndBlock.Block.toAppMessage() + if err != nil { + return nil, err + } + return &appmessage.MsgIBDRootUTXOSetAndBlock{ + UTXOSet: x.IbdRootUTXOSetAndBlock.UtxoSet, + Block: msgBlock, + }, nil +} + +func (x *KaspadMessage_IbdRootUTXOSetAndBlock) fromAppMessage(msgIBDRootUTXOSetAndBlock *appmessage.MsgIBDRootUTXOSetAndBlock) error { + x.IbdRootUTXOSetAndBlock.UtxoSet = msgIBDRootUTXOSetAndBlock.UTXOSet + return x.IbdRootUTXOSetAndBlock.Block.fromAppMessage(msgIBDRootUTXOSetAndBlock.Block) +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_headers.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_headers.go new file mode 100644 index 000000000..afea5d02b --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_headers.go @@ -0,0 +1,28 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestHeaders) toAppMessage() (appmessage.Message, error) { + lowHash, err := x.RequestHeaders.LowHash.toDomain() + if err != nil { + return nil, err + } + + highHash, err := x.RequestHeaders.HighHash.toDomain() + if err != nil { + return nil, err + } + + return &appmessage.MsgRequestHeaders{ + LowHash: lowHash, + HighHash: highHash, + }, nil +} + +func (x *KaspadMessage_RequestHeaders) fromAppMessage(msgRequestHeaders *appmessage.MsgRequestHeaders) error { + x.RequestHeaders = &RequestHeadersMessage{ + LowHash: domainHashToProto(msgRequestHeaders.LowHash), + HighHash: domainHashToProto(msgRequestHeaders.HighHash), + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go index bcf81bc39..1f8784f33 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go @@ -1,28 +1,31 @@ package protowire -import "github.com/kaspanet/kaspad/app/appmessage" +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/pkg/errors" +) func (x *KaspadMessage_RequestIBDBlocks) toAppMessage() (appmessage.Message, error) { - lowHash, err := x.RequestIBDBlocks.LowHash.toDomain() + if len(x.RequestIBDBlocks.Hashes) > appmessage.MaxRequestIBDBlocksHashes { + return nil, errors.Errorf("too many hashes for message "+ + "[count %d, max %d]", len(x.RequestIBDBlocks.Hashes), appmessage.MaxRequestIBDBlocksHashes) + } + hashes, err := protoHashesToDomain(x.RequestIBDBlocks.Hashes) if err != nil { return nil, err } - - highHash, err := x.RequestIBDBlocks.HighHash.toDomain() - if err != nil { - return nil, err - } - - return &appmessage.MsgRequestIBDBlocks{ - LowHash: lowHash, - HighHash: highHash, - }, nil + return &appmessage.MsgRequestRelayBlocks{Hashes: hashes}, nil } -func (x *KaspadMessage_RequestIBDBlocks) fromAppMessage(msgGetBlocks *appmessage.MsgRequestIBDBlocks) error { - x.RequestIBDBlocks = &RequestIBDBlocksMessage{ - LowHash: domainHashToProto(msgGetBlocks.LowHash), - HighHash: domainHashToProto(msgGetBlocks.HighHash), +func (x *KaspadMessage_RequestIBDBlocks) fromAppMessage(msgRequestIBDBlocks *appmessage.MsgRequestIBDBlocks) error { + if len(msgRequestIBDBlocks.Hashes) > appmessage.MaxRequestIBDBlocksHashes { + return errors.Errorf("too many hashes for message "+ + "[count %d, max %d]", len(msgRequestIBDBlocks.Hashes), appmessage.MaxRequestIBDBlocksHashes) } + + x.RequestIBDBlocks = &RequestIBDBlocksMessage{ + Hashes: domainHashesToProto(msgRequestIBDBlocks.Hashes), + } + return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go new file mode 100644 index 000000000..934d36c72 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go @@ -0,0 +1,18 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestIBDRootUTXOSetAndBlock) toAppMessage() (appmessage.Message, error) { + ibdRoot, err := x.RequestIBDRootUTXOSetAndBlock.IbdRoot.toDomain() + if err != nil { + return nil, err + } + + return &appmessage.MsgRequestIBDRootUTXOSetAndBlock{IBDRoot: ibdRoot}, nil +} + +func (x *KaspadMessage_RequestIBDRootUTXOSetAndBlock) fromAppMessage( + msgRequestIBDRootUTXOSetAndBlock *appmessage.MsgRequestIBDRootUTXOSetAndBlock) error { + x.RequestIBDRootUTXOSetAndBlock.IbdRoot = domainHashToProto(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_headers.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_headers.go new file mode 100644 index 000000000..1e9689f91 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_headers.go @@ -0,0 +1,11 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestNextHeaders) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgRequestNextHeaders{}, nil +} + +func (x *KaspadMessage_RequestNextHeaders) fromAppMessage(_ *appmessage.MsgRequestNextHeaders) error { + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_blocks.go deleted file mode 100644 index 4ef579ed3..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_blocks.go +++ /dev/null @@ -1,11 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_RequestNextIBDBlocks) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgRequestNextIBDBlocks{}, nil -} - -func (x *KaspadMessage_RequestNextIBDBlocks) fromAppMessage(_ *appmessage.MsgRequestNextIBDBlocks) error { - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_relay_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_relay_blocks.go index b394aa721..ea8779b13 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_relay_blocks.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_relay_blocks.go @@ -6,9 +6,9 @@ import ( ) func (x *KaspadMessage_RequestRelayBlocks) toAppMessage() (appmessage.Message, error) { - if len(x.RequestRelayBlocks.Hashes) > appmessage.MsgRequestRelayBlocksHashes { + if len(x.RequestRelayBlocks.Hashes) > appmessage.MaxRequestRelayBlocksHashes { return nil, errors.Errorf("too many hashes for message "+ - "[count %d, max %d]", len(x.RequestRelayBlocks.Hashes), appmessage.MsgRequestRelayBlocksHashes) + "[count %d, max %d]", len(x.RequestRelayBlocks.Hashes), appmessage.MaxRequestRelayBlocksHashes) } hashes, err := protoHashesToDomain(x.RequestRelayBlocks.Hashes) if err != nil { @@ -18,9 +18,9 @@ func (x *KaspadMessage_RequestRelayBlocks) toAppMessage() (appmessage.Message, e } func (x *KaspadMessage_RequestRelayBlocks) fromAppMessage(msgGetRelayBlocks *appmessage.MsgRequestRelayBlocks) error { - if len(msgGetRelayBlocks.Hashes) > appmessage.MsgRequestRelayBlocksHashes { + if len(msgGetRelayBlocks.Hashes) > appmessage.MaxRequestRelayBlocksHashes { return errors.Errorf("too many hashes for message "+ - "[count %d, max %d]", len(msgGetRelayBlocks.Hashes), appmessage.MsgRequestRelayBlocksHashes) + "[count %d, max %d]", len(msgGetRelayBlocks.Hashes), appmessage.MaxRequestRelayBlocksHashes) } x.RequestRelayBlocks = &RequestRelayBlocksMessage{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go index 1d4aa418d..d45c3b3af 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go @@ -22,7 +22,7 @@ func (x *KaspadMessage_GetBlockTemplateResponse) toAppMessage() (appmessage.Mess if err != nil { return nil, err } - return appmessage.NewGetBlockTemplateResponseMessage(msgBlock.(*appmessage.MsgBlock)), nil + return appmessage.NewGetBlockTemplateResponseMessage(msgBlock), nil } func (x *KaspadMessage_GetBlockTemplateResponse) fromAppMessage(message *appmessage.GetBlockTemplateResponseMessage) error { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go index 2e08fb26b..b4b718dc1 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go @@ -38,7 +38,7 @@ func (x *KaspadMessage_BlockAddedNotification) toAppMessage() (appmessage.Messag return nil, err } return &appmessage.BlockAddedNotificationMessage{ - Block: block.(*appmessage.MsgBlock), + Block: block, }, nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go index fe8be232d..4ba9bd747 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go @@ -9,7 +9,7 @@ func (x *KaspadMessage_SubmitBlockRequest) toAppMessage() (appmessage.Message, e } return &appmessage.SubmitBlockRequestMessage{ - Block: blockAppMessage.(*appmessage.MsgBlock), + Block: blockAppMessage, }, nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index f386de8ca..c690ac9a3 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -93,15 +93,15 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgRequestNextIBDBlocks: - payload := new(KaspadMessage_RequestNextIBDBlocks) + case *appmessage.MsgRequestNextHeaders: + payload := new(KaspadMessage_RequestNextHeaders) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.MsgDoneIBDBlocks: - payload := new(KaspadMessage_DoneIBDBlocks) + case *appmessage.MsgDoneHeaders: + payload := new(KaspadMessage_DoneHeaders) err := payload.fromAppMessage(message) if err != nil { return nil, err @@ -205,6 +205,47 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + + case *appmessage.MsgBlockHeader: + payload := new(KaspadMessage_BlockHeader) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + + case *appmessage.MsgRequestIBDRootUTXOSetAndBlock: + payload := new(KaspadMessage_RequestIBDRootUTXOSetAndBlock) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + + case *appmessage.MsgIBDRootUTXOSetAndBlock: + payload := new(KaspadMessage_IbdRootUTXOSetAndBlock) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + + case *appmessage.MsgRequestHeaders: + payload := new(KaspadMessage_RequestHeaders) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + + case *appmessage.MsgIBDRootNotFound: + payload := new(KaspadMessage_IbdRootNotFound) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + default: return nil, nil } From 8290fadd3ae649fcf5d29d0ecb51c6ca815c9675 Mon Sep 17 00:00:00 2001 From: oudeis Date: Tue, 10 Nov 2020 15:59:35 +0000 Subject: [PATCH 012/351] [NOD-1521] use staticcheck (#1015) * [NOD-1521] Use static check as part of jenkins to check for swallowed errors * [NOD-1521] added staticcheck installation * [NOD-1521] Fix static check errors Co-authored-by: Ori Newman --- app/protocol/flows/blockrelay/handle_relay_invs.go | 4 ++++ cmd/kaspactl/docker/Dockerfile | 4 +++- cmd/kaspaminer/docker/Dockerfile | 4 +++- docker/Dockerfile | 4 +++- infrastructure/db/database/ldb/leveldb_test.go | 4 ++-- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index c73153989..29458b46b 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -222,6 +222,10 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS return err } selectedTipBlueScore, err := blocks.ExtractBlueScore(virtualSelectedParent) + if err != nil { + return err + } + if blueScore > selectedTipBlueScore+maxOrphanBlueScoreDiff { log.Infof("Orphan block %s has blue score %d and the selected tip blue score is "+ "%d. Ignoring orphans with a blue score difference from the selected tip greater than %d", diff --git a/cmd/kaspactl/docker/Dockerfile b/cmd/kaspactl/docker/Dockerfile index 9e83826de..319623966 100644 --- a/cmd/kaspactl/docker/Dockerfile +++ b/cmd/kaspactl/docker/Dockerfile @@ -6,7 +6,8 @@ RUN mkdir -p /go/src/github.com/kaspanet/kaspad WORKDIR /go/src/github.com/kaspanet/kaspad RUN apk add --no-cache curl git openssh binutils gcc musl-dev -RUN go get -u golang.org/x/lint/golint +RUN go get -u golang.org/x/lint/golint \ + honnef.co/go/tools/cmd/staticcheck COPY go.mod . COPY go.sum . @@ -20,6 +21,7 @@ WORKDIR /go/src/github.com/kaspanet/kaspad/cmd/kaspactl RUN GOFMT_RESULT=`go fmt ./...`; echo $GOFMT_RESULT; test -z "$GOFMT_RESULT" RUN go vet ./... RUN golint -set_exit_status ./... +RUN staticcheck -checks SA4006 ./... RUN GOOS=linux go build -a -installsuffix cgo -o kaspactl . # --- multistage docker build: stage #2: runtime image diff --git a/cmd/kaspaminer/docker/Dockerfile b/cmd/kaspaminer/docker/Dockerfile index 6aa3f3861..bc904fb51 100644 --- a/cmd/kaspaminer/docker/Dockerfile +++ b/cmd/kaspaminer/docker/Dockerfile @@ -6,7 +6,8 @@ RUN mkdir -p /go/src/github.com/kaspanet/kaspad WORKDIR /go/src/github.com/kaspanet/kaspad RUN apk add --no-cache curl git openssh binutils gcc musl-dev -RUN go get -u golang.org/x/lint/golint +RUN go get -u golang.org/x/lint/golint \ + honnef.co/go/tools/cmd/staticcheck COPY go.mod . COPY go.sum . @@ -20,6 +21,7 @@ WORKDIR /go/src/github.com/kaspanet/kaspad/cmd/kaspaminer RUN GOFMT_RESULT=`go fmt ./...`; echo $GOFMT_RESULT; test -z "$GOFMT_RESULT" RUN go vet ./... RUN golint -set_exit_status ./... +RUN staticcheck -checks SA4006 ./... RUN GOOS=linux go build -a -installsuffix cgo -o kaspaminer . # --- multistage docker build: stage #2: runtime image diff --git a/docker/Dockerfile b/docker/Dockerfile index 57fff00fe..7ef305f88 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,7 +10,8 @@ RUN go get -u golang.org/x/lint/golint \ github.com/kisielk/errcheck \ github.com/opennota/check/cmd/aligncheck \ github.com/opennota/check/cmd/structcheck \ - github.com/opennota/check/cmd/varcheck + github.com/opennota/check/cmd/varcheck \ + honnef.co/go/tools/cmd/staticcheck COPY go.mod . COPY go.sum . @@ -25,6 +26,7 @@ RUN golint -set_exit_status ./... # RUN aligncheck ./... # RUN structcheck -e ./... # RUN varcheck -e ./... +RUN staticcheck -checks SA4006 ./... RUN GOOS=linux go build -a -installsuffix cgo -o kaspad . # Remove the line below and uncomment the line after it for testing with coverage diff --git a/infrastructure/db/database/ldb/leveldb_test.go b/infrastructure/db/database/ldb/leveldb_test.go index 067cb2fbf..cc91639ae 100644 --- a/infrastructure/db/database/ldb/leveldb_test.go +++ b/infrastructure/db/database/ldb/leveldb_test.go @@ -81,7 +81,7 @@ func TestLevelDBTransactionSanity(t *testing.T) { // Get from the key previously put to. Since the tx is not // yet committed, this should return ErrNotFound. - getData, err := ldb.Get(key) + _, err = ldb.Get(key) if err == nil { t.Fatalf("TestLevelDBTransactionSanity: Get " + "unexpectedly succeeded") @@ -100,7 +100,7 @@ func TestLevelDBTransactionSanity(t *testing.T) { // Get from the key previously put to. Now that the tx was // committed, this should succeed. - getData, err = ldb.Get(key) + getData, err := ldb.Get(key) if err != nil { t.Fatalf("TestLevelDBTransactionSanity: Get "+ "returned unexpected error: %s", err) From 4736213ba4f34908f9c58a90b6b75f3224532817 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 10 Nov 2020 08:32:42 -0800 Subject: [PATCH 013/351] [NOD-1528] Make data stores copy data on stage (#1020) * [NOD-1528] Make data stores copy data on stage * [NOD-1528] Add proto objects to serialize consensus state objects * [NOD-1528] Fix receiver names * [NOD-1528] Add copy to block store and utxo diff staging * [NOD-1528] Return errors where needed --- .../database/serialization/dbobjects.pb.go | 155 ++++++++++++++++-- .../database/serialization/dbobjects.proto | 10 +- .../database/serialization/header_tips.go | 4 +- .../consensus/database/serialization/tips.go | 17 ++ .../serialization/virtual_diff_parents.go | 17 ++ .../acceptancedatastore.go | 19 ++- .../blockheaderstore/blockheaderstore.go | 19 ++- .../blockrelationstore/blockrelationstore.go | 19 ++- .../datastructures/blockstore/blockstore.go | 19 ++- .../consensusstatestore/tips.go | 50 +++++- .../consensusstatestore/utxo.go | 34 +++- .../virtual_diff_parents.go | 50 +++++- .../ghostdagdatastore/ghostdagdatastore.go | 19 ++- .../headertipsstore/headertipsstore.go | 23 ++- .../pruningstore/pruningstore.go | 2 +- .../reachabilitydatastore.go | 20 ++- .../utxodiffstore/utxodiffstore.go | 21 ++- ...face_datastructures_acceptancedatastore.go | 2 +- ...terface_datastructures_blockheaderstore.go | 2 +- ...rface_datastructures_blockrelationstore.go | 2 +- .../interface_datastructures_blockstore.go | 2 +- ...face_datastructures_consensusstatestore.go | 4 +- ...erface_datastructures_ghostdagdatastore.go | 2 +- ...nterface_datastructures_headertipsstore.go | 2 +- ...ce_datastructures_reachabilitydatastore.go | 2 +- .../interface_datastructures_utxodiffstore.go | 2 +- .../blockbuilder/test_block_builder.go | 12 +- .../blockprocessor/validateandinsertblock.go | 19 ++- .../add_block_to_virtual.go | 6 +- .../resolve_block_status.go | 15 +- .../set_pruning_utxo_set.go | 12 +- .../consensusstatemanager/update_virtual.go | 14 +- .../dagtopologymanager/dagtopologymanager.go | 16 +- .../processes/ghostdagmanager/ghostdag.go | 6 +- .../headertipsmanager/headertipsmanager.go | 6 +- .../processes/reachabilitymanager/stage.go | 10 +- domain/consensus/utils/hashes/hash_array.go | 41 ----- 37 files changed, 548 insertions(+), 127 deletions(-) create mode 100644 domain/consensus/database/serialization/tips.go create mode 100644 domain/consensus/database/serialization/virtual_diff_parents.go delete mode 100644 domain/consensus/utils/hashes/hash_array.go diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index 67cf8593e..a451cc051 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -1535,6 +1535,100 @@ func (x *DbHeaderTips) GetTips() []*DbHash { return nil } +type DbTips struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Tips []*DbHash `protobuf:"bytes,1,rep,name=tips,proto3" json:"tips,omitempty"` +} + +func (x *DbTips) Reset() { + *x = DbTips{} + if protoimpl.UnsafeEnabled { + mi := &file_dbobjects_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DbTips) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DbTips) ProtoMessage() {} + +func (x *DbTips) ProtoReflect() protoreflect.Message { + mi := &file_dbobjects_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DbTips.ProtoReflect.Descriptor instead. +func (*DbTips) Descriptor() ([]byte, []int) { + return file_dbobjects_proto_rawDescGZIP(), []int{26} +} + +func (x *DbTips) GetTips() []*DbHash { + if x != nil { + return x.Tips + } + return nil +} + +type DbVirtualDiffParents struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + VirtualDiffParents []*DbHash `protobuf:"bytes,1,rep,name=virtualDiffParents,proto3" json:"virtualDiffParents,omitempty"` +} + +func (x *DbVirtualDiffParents) Reset() { + *x = DbVirtualDiffParents{} + if protoimpl.UnsafeEnabled { + mi := &file_dbobjects_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DbVirtualDiffParents) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DbVirtualDiffParents) ProtoMessage() {} + +func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { + mi := &file_dbobjects_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DbVirtualDiffParents.ProtoReflect.Descriptor instead. +func (*DbVirtualDiffParents) Descriptor() ([]byte, []int) { + return file_dbobjects_proto_rawDescGZIP(), []int{27} +} + +func (x *DbVirtualDiffParents) GetVirtualDiffParents() []*DbHash { + if x != nil { + return x.VirtualDiffParents + } + return nil +} + var File_dbobjects_proto protoreflect.FileDescriptor var file_dbobjects_proto_rawDesc = []byte{ @@ -1754,11 +1848,20 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x42, 0x2a, - 0x5a, 0x28, 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, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x33, + 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, + 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, + 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x73, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1773,7 +1876,7 @@ func file_dbobjects_proto_rawDescGZIP() []byte { return file_dbobjects_proto_rawDescData } -var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_dbobjects_proto_goTypes = []interface{}{ (*DbBlock)(nil), // 0: serialization.DbBlock (*DbBlockHeader)(nil), // 1: serialization.DbBlockHeader @@ -1801,6 +1904,8 @@ var file_dbobjects_proto_goTypes = []interface{}{ (*DbUtxoDiff)(nil), // 23: serialization.DbUtxoDiff (*DbPruningPointUTXOSetBytes)(nil), // 24: serialization.DbPruningPointUTXOSetBytes (*DbHeaderTips)(nil), // 25: serialization.DbHeaderTips + (*DbTips)(nil), // 26: serialization.DbTips + (*DbVirtualDiffParents)(nil), // 27: serialization.DbVirtualDiffParents } var file_dbobjects_proto_depIdxs = []int32{ 1, // 0: serialization.DbBlock.header:type_name -> serialization.DbBlockHeader @@ -1836,11 +1941,13 @@ var file_dbobjects_proto_depIdxs = []int32{ 18, // 30: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem 18, // 31: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem 2, // 32: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash - 33, // [33:33] is the sub-list for method output_type - 33, // [33:33] is the sub-list for method input_type - 33, // [33:33] is the sub-list for extension type_name - 33, // [33:33] is the sub-list for extension extendee - 0, // [0:33] is the sub-list for field type_name + 2, // 33: serialization.DbTips.tips:type_name -> serialization.DbHash + 2, // 34: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash + 35, // [35:35] is the sub-list for method output_type + 35, // [35:35] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 35, // [35:35] is the sub-list for extension extendee + 0, // [0:35] is the sub-list for field type_name } func init() { file_dbobjects_proto_init() } @@ -2161,6 +2268,30 @@ func file_dbobjects_proto_init() { return nil } } + file_dbobjects_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DbTips); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dbobjects_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DbVirtualDiffParents); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -2168,7 +2299,7 @@ func file_dbobjects_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_dbobjects_proto_rawDesc, NumEnums: 0, - NumMessages: 26, + NumMessages: 28, NumExtensions: 0, NumServices: 0, }, diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 8e6aa3c14..79c811228 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -141,4 +141,12 @@ message DbPruningPointUTXOSetBytes { message DbHeaderTips { repeated DbHash tips = 1; -} \ No newline at end of file +} + +message DbTips { + repeated DbHash tips = 1; +} + +message DbVirtualDiffParents { + repeated DbHash virtualDiffParents = 1; +} diff --git a/domain/consensus/database/serialization/header_tips.go b/domain/consensus/database/serialization/header_tips.go index 320f340ec..8855fba19 100644 --- a/domain/consensus/database/serialization/header_tips.go +++ b/domain/consensus/database/serialization/header_tips.go @@ -11,7 +11,7 @@ func HeaderTipsToDBHeaderTips(tips []*externalapi.DomainHash) *DbHeaderTips { } } -// DBHeaderTipsTOHeaderTips converts DbHeaderTips to a slice of hashes -func DBHeaderTipsTOHeaderTips(dbHeaderTips *DbHeaderTips) ([]*externalapi.DomainHash, error) { +// DBHeaderTipsToHeaderTips converts DbHeaderTips to a slice of hashes +func DBHeaderTipsToHeaderTips(dbHeaderTips *DbHeaderTips) ([]*externalapi.DomainHash, error) { return DbHashesToDomainHashes(dbHeaderTips.Tips) } diff --git a/domain/consensus/database/serialization/tips.go b/domain/consensus/database/serialization/tips.go new file mode 100644 index 000000000..e89eb8261 --- /dev/null +++ b/domain/consensus/database/serialization/tips.go @@ -0,0 +1,17 @@ +package serialization + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// TipsToDBTips converts a slice of hashes to DbTips +func TipsToDBTips(tips []*externalapi.DomainHash) *DbTips { + return &DbTips{ + Tips: DomainHashesToDbHashes(tips), + } +} + +// DBTipsToTips converts DbTips to a slice of hashes +func DBTipsToTips(dbTips *DbTips) ([]*externalapi.DomainHash, error) { + return DbHashesToDomainHashes(dbTips.Tips) +} diff --git a/domain/consensus/database/serialization/virtual_diff_parents.go b/domain/consensus/database/serialization/virtual_diff_parents.go new file mode 100644 index 000000000..9d933d411 --- /dev/null +++ b/domain/consensus/database/serialization/virtual_diff_parents.go @@ -0,0 +1,17 @@ +package serialization + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// VirtualDiffParentsToDBHeaderVirtualDiffParents converts a slice of hashes to DbVirtualDiffParents +func VirtualDiffParentsToDBHeaderVirtualDiffParents(tips []*externalapi.DomainHash) *DbVirtualDiffParents { + return &DbVirtualDiffParents{ + VirtualDiffParents: DomainHashesToDbHashes(tips), + } +} + +// DBVirtualDiffParentsToVirtualDiffParents converts DbHeaderTips to a slice of hashes +func DBVirtualDiffParentsToVirtualDiffParents(dbVirtualDiffParents *DbVirtualDiffParents) ([]*externalapi.DomainHash, error) { + return DbHashesToDomainHashes(dbVirtualDiffParents.VirtualDiffParents) +} diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index ab0c59659..b74cec547 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -25,8 +25,14 @@ func New() model.AcceptanceDataStore { } // Stage stages the given acceptanceData for the given blockHash -func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) { - ads.staging[*blockHash] = acceptanceData +func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error { + clone, err := ads.cloneAcceptanceData(acceptanceData) + if err != nil { + return err + } + + ads.staging[*blockHash] = clone + return nil } func (ads *acceptanceDataStore) IsStaged() bool { @@ -101,3 +107,12 @@ func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes [] func (ads *acceptanceDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } + +func (ads *acceptanceDataStore) cloneAcceptanceData(acceptanceData model.AcceptanceData) (model.AcceptanceData, error) { + serialized, err := ads.serializeAcceptanceData(acceptanceData) + if err != nil { + return nil, err + } + + return ads.deserializeAcceptanceData(serialized) +} diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index 7b07e8d9f..4fb6ffa47 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -25,8 +25,14 @@ func New() model.BlockHeaderStore { } // Stage stages the given block header for the given blockHash -func (bms *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) { - bms.staging[*blockHash] = blockHeader +func (bms *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error { + clone, err := bms.cloneHeader(blockHeader) + if err != nil { + return err + } + + bms.staging[*blockHash] = clone + return nil } func (bms *blockHeaderStore) IsStaged() bool { @@ -128,3 +134,12 @@ func (bms *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi } return serialization.DbBlockHeaderToDomainBlockHeader(dbBlockHeader) } + +func (bms *blockHeaderStore) cloneHeader(header *externalapi.DomainBlockHeader) (*externalapi.DomainBlockHeader, error) { + serialized, err := bms.serializeHeader(header) + if err != nil { + return nil, err + } + + return bms.deserializeHeader(serialized) +} diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index 974c86022..284b32162 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -22,8 +22,14 @@ func New() model.BlockRelationStore { } } -func (brs *blockRelationStore) StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *model.BlockRelations) { - brs.staging[*blockHash] = blockRelations +func (brs *blockRelationStore) StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *model.BlockRelations) error { + clone, err := brs.clone(blockRelations) + if err != nil { + return err + } + + brs.staging[*blockHash] = clone + return nil } func (brs *blockRelationStore) IsStaged() bool { @@ -88,3 +94,12 @@ func (brs *blockRelationStore) deserializeBlockRelations(blockRelationsBytes []b } return serialization.DbBlockRelationsToDomainBlockRelations(dbBlockRelations) } + +func (brs *blockRelationStore) clone(blockRelations *model.BlockRelations) (*model.BlockRelations, error) { + serialized, err := brs.serializeBlockRelations(blockRelations) + if err != nil { + return nil, err + } + + return brs.deserializeBlockRelations(serialized) +} diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index 42744e0ee..84fedbb54 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -25,8 +25,14 @@ func New() model.BlockStore { } // Stage stages the given block for the given blockHash -func (bms *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) { - bms.staging[*blockHash] = block +func (bms *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error { + clone, err := bms.clone(block) + if err != nil { + return err + } + + bms.staging[*blockHash] = clone + return nil } func (bms *blockStore) IsStaged() bool { @@ -128,3 +134,12 @@ func (bms *blockStore) deserializeBlock(blockBytes []byte) (*externalapi.DomainB func (bms *blockStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } + +func (bms *blockStore) clone(block *externalapi.DomainBlock) (*externalapi.DomainBlock, error) { + serialized, err := bms.serializeBlock(block) + if err != nil { + return nil, err + } + + return bms.deserializeBlock(serialized) +} diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go index b27418227..1e64a9354 100644 --- a/domain/consensus/datastructures/consensusstatestore/tips.go +++ b/domain/consensus/datastructures/consensusstatestore/tips.go @@ -1,10 +1,11 @@ package consensusstatestore 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" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) var tipsKey = dbkeys.MakeBucket().Key([]byte("tips")) @@ -19,20 +20,57 @@ func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.Dom return nil, err } - return hashes.DeserializeHashSlice(tipsBytes) + return c.deserializeTips(tipsBytes) } -func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) { - c.stagedTips = tipHashes +func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) error { + clone, err := c.cloneTips(tipHashes) + if err != nil { + return err + } + + c.stagedTips = clone + return nil } func (c *consensusStateStore) commitTips(dbTx model.DBTransaction) error { - tipsBytes := hashes.SerializeHashSlice(c.stagedTips) + tipsBytes, err := c.serializeTips(c.stagedTips) + if err != nil { + return err + } - err := dbTx.Put(tipsKey, tipsBytes) + err = dbTx.Put(tipsKey, tipsBytes) if err != nil { return err } return nil } + +func (c *consensusStateStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { + dbTips := serialization.TipsToDBTips(tips) + return proto.Marshal(dbTips) +} + +func (c *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, + error) { + + dbTips := &serialization.DbTips{} + err := proto.Unmarshal(tipsBytes, dbTips) + if err != nil { + return nil, err + } + + return serialization.DBTipsToTips(dbTips) +} + +func (c *consensusStateStore) cloneTips(tips []*externalapi.DomainHash, +) ([]*externalapi.DomainHash, error) { + + serialized, err := c.serializeTips(tips) + if err != nil { + return nil, err + } + + return c.deserializeTips(serialized) +} diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index fc225fff0..b99b7dbc0 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -23,7 +23,7 @@ func (c *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODi return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged") } - c.stagedVirtualUTXODiff = virtualUTXODiff + c.stagedVirtualUTXODiff = c.cloneUTXODiff(virtualUTXODiff) return nil } @@ -228,3 +228,35 @@ func (c *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.R return nil } + +func (c *consensusStateStore) cloneUTXODiff(diff *model.UTXODiff) *model.UTXODiff { + utxoDiffCopy := &model.UTXODiff{ + ToAdd: make(model.UTXOCollection, len(diff.ToAdd)), + ToRemove: make(model.UTXOCollection, len(diff.ToRemove)), + } + + for outpoint, entry := range diff.ToAdd { + scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey)) + copy(scriptPublicKeyCopy, entry.ScriptPublicKey) + utxoDiffCopy.ToAdd[outpoint] = cloneUTXOEntry(entry) + } + + for outpoint, entry := range diff.ToRemove { + scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey)) + copy(scriptPublicKeyCopy, entry.ScriptPublicKey) + utxoDiffCopy.ToRemove[outpoint] = cloneUTXOEntry(entry) + } + + return diff +} + +func cloneUTXOEntry(entry *externalapi.UTXOEntry) *externalapi.UTXOEntry { + scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey)) + copy(scriptPublicKeyCopy, entry.ScriptPublicKey) + return &externalapi.UTXOEntry{ + Amount: entry.Amount, + ScriptPublicKey: scriptPublicKeyCopy, + BlockBlueScore: entry.BlockBlueScore, + IsCoinbase: entry.IsCoinbase, + } +} diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go index 3915a67d0..3a9b3ff3c 100644 --- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go +++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go @@ -1,10 +1,11 @@ package consensusstatestore 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" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) var virtualDiffParentsKey = dbkeys.MakeBucket().Key([]byte("virtual-diff-parents")) @@ -19,20 +20,57 @@ func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*e return nil, err } - return hashes.DeserializeHashSlice(virtualDiffParentsBytes) + return c.deserializeVirtualDiffParents(virtualDiffParentsBytes) } -func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) { - c.stagedVirtualDiffParents = tipHashes +func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) error { + clone, err := c.cloneVirtualDiffParents(tipHashes) + if err != nil { + return err + } + + c.stagedVirtualDiffParents = clone + return nil } func (c *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { - virtualDiffParentsBytes := hashes.SerializeHashSlice(c.stagedVirtualDiffParents) + virtualDiffParentsBytes, err := c.serializeVirtualDiffParents(c.stagedVirtualDiffParents) + if err != nil { + return err + } - err := dbTx.Put(virtualDiffParentsKey, virtualDiffParentsBytes) + err = dbTx.Put(virtualDiffParentsKey, virtualDiffParentsBytes) if err != nil { return err } return nil } + +func (c *consensusStateStore) serializeVirtualDiffParents(virtualDiffParentsBytes []*externalapi.DomainHash) ([]byte, error) { + virtualDiffParents := serialization.VirtualDiffParentsToDBHeaderVirtualDiffParents(virtualDiffParentsBytes) + return proto.Marshal(virtualDiffParents) +} + +func (c *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBytes []byte) ([]*externalapi.DomainHash, + error) { + + dbVirtualDiffParents := &serialization.DbVirtualDiffParents{} + err := proto.Unmarshal(virtualDiffParentsBytes, dbVirtualDiffParents) + if err != nil { + return nil, err + } + + return serialization.DBVirtualDiffParentsToVirtualDiffParents(dbVirtualDiffParents) +} + +func (c *consensusStateStore) cloneVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash, +) ([]*externalapi.DomainHash, error) { + + serialized, err := c.serializeVirtualDiffParents(virtualDiffParents) + if err != nil { + return nil, err + } + + return c.deserializeVirtualDiffParents(serialized) +} diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index 81c0a9038..b84f213c7 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -23,8 +23,14 @@ func New() model.GHOSTDAGDataStore { } // Stage stages the given blockGHOSTDAGData for the given blockHash -func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { - gds.staging[*blockHash] = blockGHOSTDAGData +func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) error { + clone, err := gds.clone(blockGHOSTDAGData) + if err != nil { + return err + } + + gds.staging[*blockHash] = clone + return nil } func (gds *ghostdagDataStore) IsStaged() bool { @@ -83,3 +89,12 @@ func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataByte return serialization.DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData) } + +func (gds *ghostdagDataStore) clone(blockGHOSTDAGData *model.BlockGHOSTDAGData) (*model.BlockGHOSTDAGData, error) { + serialized, err := gds.serializeBlockGHOSTDAGData(blockGHOSTDAGData) + if err != nil { + return nil, err + } + + return gds.deserializeBlockGHOSTDAGData(serialized) +} diff --git a/domain/consensus/datastructures/headertipsstore/headertipsstore.go b/domain/consensus/datastructures/headertipsstore/headertipsstore.go index a846a982b..c404a4318 100644 --- a/domain/consensus/datastructures/headertipsstore/headertipsstore.go +++ b/domain/consensus/datastructures/headertipsstore/headertipsstore.go @@ -45,8 +45,14 @@ func (h *headerTipsStore) Commit(dbTx model.DBTransaction) error { return nil } -func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) { - h.staging = tips +func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) error { + clone, err := h.clone(tips) + if err != nil { + return err + } + + h.staging = clone + return nil } func (h *headerTipsStore) IsStaged() bool { @@ -78,7 +84,18 @@ func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.Doma return nil, err } - return serialization.DBHeaderTipsTOHeaderTips(dbTips) + return serialization.DBHeaderTipsToHeaderTips(dbTips) +} + +func (h *headerTipsStore) clone(tips []*externalapi.DomainHash, +) ([]*externalapi.DomainHash, error) { + + serialized, err := h.serializeTips(tips) + if err != nil { + return nil, err + } + + return h.deserializeTips(serialized) } // New instantiates a new HeaderTipsStore diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index b310b6268..e72f531af 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -27,7 +27,7 @@ func New() model.PruningStore { // Stage stages the pruning state func (ps *pruningStore) Stage(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) { - ps.pruningPointStaging = pruningPointBlockHash + ps.pruningPointStaging = &(*pruningPointBlockHash) ps.serializedUTXOSetStaging = pruningPointUTXOSetBytes } diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index 355496483..e7f996cf8 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -26,8 +26,15 @@ func New() model.ReachabilityDataStore { } // StageReachabilityData stages the given reachabilityData for the given blockHash -func (rds *reachabilityDataStore) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) { - rds.reachabilityDataStaging[*blockHash] = reachabilityData +func (rds *reachabilityDataStore) StageReachabilityData(blockHash *externalapi.DomainHash, + reachabilityData *model.ReachabilityData) error { + clone, err := rds.cloneReachabilityData(reachabilityData) + if err != nil { + return err + } + + rds.reachabilityDataStaging[*blockHash] = clone + return nil } // StageReachabilityReindexRoot stages the given reachabilityReindexRoot @@ -144,3 +151,12 @@ func (rds *reachabilityDataStore) deserializeReachabilityReindexRoot(reachabilit return serialization.DbHashToDomainHash(dbHash) } + +func (rds *reachabilityDataStore) cloneReachabilityData(reachabilityData *model.ReachabilityData) (*model.ReachabilityData, error) { + serialized, err := rds.serializeReachabilityData(reachabilityData) + if err != nil { + return nil, err + } + + return rds.deserializeReachabilityData(serialized) +} diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index 53cf843aa..786d0096f 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -28,9 +28,15 @@ func New() model.UTXODiffStore { } // Stage stages the given utxoDiff for the given blockHash -func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) { - uds.utxoDiffStaging[*blockHash] = utxoDiff - uds.utxoDiffChildStaging[*blockHash] = utxoDiffChild +func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { + clone, err := uds.cloneUTXODiff(utxoDiff) + if err != nil { + return err + } + + uds.utxoDiffStaging[*blockHash] = clone + uds.utxoDiffChildStaging[*blockHash] = &*utxoDiffChild + return nil } func (uds *utxoDiffStore) IsStaged() bool { @@ -181,3 +187,12 @@ func (uds *utxoDiffStore) deserializeUTXODiffChild(utxoDiffChildBytes []byte) (* return serialization.DbHashToDomainHash(dbHash) } + +func (uds *utxoDiffStore) cloneUTXODiff(diff *model.UTXODiff) (*model.UTXODiff, error) { + serialized, err := uds.serializeUTXODiff(diff) + if err != nil { + return nil, err + } + + return uds.deserializeUTXODiff(serialized) +} diff --git a/domain/consensus/model/interface_datastructures_acceptancedatastore.go b/domain/consensus/model/interface_datastructures_acceptancedatastore.go index 4d75e1225..db656cd49 100644 --- a/domain/consensus/model/interface_datastructures_acceptancedatastore.go +++ b/domain/consensus/model/interface_datastructures_acceptancedatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // AcceptanceDataStore represents a store of AcceptanceData type AcceptanceDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData) + Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData) error IsStaged() bool Get(dbContext DBReader, blockHash *externalapi.DomainHash) (AcceptanceData, error) Delete(blockHash *externalapi.DomainHash) diff --git a/domain/consensus/model/interface_datastructures_blockheaderstore.go b/domain/consensus/model/interface_datastructures_blockheaderstore.go index 7accac722..6b98f815c 100644 --- a/domain/consensus/model/interface_datastructures_blockheaderstore.go +++ b/domain/consensus/model/interface_datastructures_blockheaderstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockHeaderStore represents a store of block headers type BlockHeaderStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) + Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error IsStaged() bool BlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) HasBlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_blockrelationstore.go b/domain/consensus/model/interface_datastructures_blockrelationstore.go index b4274c68e..e34cca75a 100644 --- a/domain/consensus/model/interface_datastructures_blockrelationstore.go +++ b/domain/consensus/model/interface_datastructures_blockrelationstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockRelationStore represents a store of BlockRelations type BlockRelationStore interface { Store - StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations) + StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations) error IsStaged() bool BlockRelation(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockRelations, error) Has(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_blockstore.go b/domain/consensus/model/interface_datastructures_blockstore.go index d4e06c8ed..0eaead6a0 100644 --- a/domain/consensus/model/interface_datastructures_blockstore.go +++ b/domain/consensus/model/interface_datastructures_blockstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockStore represents a store of blocks type BlockStore interface { Store - Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) + Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error IsStaged() bool Block(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) HasBlock(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_consensusstatestore.go b/domain/consensus/model/interface_datastructures_consensusstatestore.go index 022f8c547..9be748079 100644 --- a/domain/consensus/model/interface_datastructures_consensusstatestore.go +++ b/domain/consensus/model/interface_datastructures_consensusstatestore.go @@ -13,9 +13,9 @@ type ConsensusStateStore interface { HasUTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) VirtualUTXOSetIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error) - StageVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash) + StageVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash) error VirtualDiffParents(dbContext DBReader) ([]*externalapi.DomainHash, error) - StageTips(tipHashes []*externalapi.DomainHash) + StageTips(tipHashes []*externalapi.DomainHash) error Tips(dbContext DBReader) ([]*externalapi.DomainHash, error) } diff --git a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go index 13522feb1..7d8f4c041 100644 --- a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go +++ b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // GHOSTDAGDataStore represents a store of BlockGHOSTDAGData type GHOSTDAGDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) + Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) error IsStaged() bool Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error) } diff --git a/domain/consensus/model/interface_datastructures_headertipsstore.go b/domain/consensus/model/interface_datastructures_headertipsstore.go index df3bc6dca..b285599b6 100644 --- a/domain/consensus/model/interface_datastructures_headertipsstore.go +++ b/domain/consensus/model/interface_datastructures_headertipsstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // HeaderTipsStore represents a store of the header tips type HeaderTipsStore interface { Store - Stage(tips []*externalapi.DomainHash) + Stage(tips []*externalapi.DomainHash) error IsStaged() bool Tips(dbContext DBReader) ([]*externalapi.DomainHash, error) HasTips(dbContext DBReader) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go index e1225b19e..5d82c1384 100644 --- a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go +++ b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // ReachabilityDataStore represents a store of ReachabilityData type ReachabilityDataStore interface { Store - StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData) + StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData) error StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) IsAnythingStaged() bool ReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (*ReachabilityData, error) diff --git a/domain/consensus/model/interface_datastructures_utxodiffstore.go b/domain/consensus/model/interface_datastructures_utxodiffstore.go index 4d7ab3101..4388d4b32 100644 --- a/domain/consensus/model/interface_datastructures_utxodiffstore.go +++ b/domain/consensus/model/interface_datastructures_utxodiffstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // UTXODiffStore represents a store of UTXODiffs type UTXODiffStore interface { Store - Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash) + Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash) error IsStaged() bool UTXODiff(dbContext DBReader, blockHash *externalapi.DomainHash) (*UTXODiff, error) UTXODiffChild(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 1690709b4..e05175ba1 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -66,10 +66,13 @@ func (bb *testBlockBuilder) buildBlockWithParents( parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { - bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) + err := bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) + if err != nil { + return nil, err + } defer bb.blockRelationStore.Discard() - err := bb.ghostdagManager.GHOSTDAG(tempBlockHash) + err = bb.ghostdagManager.GHOSTDAG(tempBlockHash) if err != nil { return nil, err } @@ -79,7 +82,10 @@ func (bb *testBlockBuilder) buildBlockWithParents( if err != nil { return nil, err } - bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData) + err = bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData) + if err != nil { + return nil, err + } defer bb.acceptanceDataStore.Discard() coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index b4f217874..741b3511c 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -108,7 +108,10 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) if err != nil { return err } - bp.headerTipsStore.Stage(tips) + err = bp.headerTipsStore.Stage(tips) + if err != nil { + return err + } } if mode.State != externalapi.SyncStateMissingGenesis { @@ -181,7 +184,11 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex } if !hasHeader { - bp.blockHeaderStore.Stage(blockHash, block.Header) + err = bp.blockHeaderStore.Stage(blockHash, block.Header) + if err != nil { + return err + } + err = bp.dagTopologyManager.SetParents(blockHash, block.Header.ParentHashes) if err != nil { return err @@ -242,8 +249,12 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock blockHash := consensusserialization.BlockHash(block) if mode.State != externalapi.SyncStateHeadersFirst { - bp.blockStore.Stage(blockHash, block) - err := bp.blockValidator.ValidateBodyInIsolation(blockHash) + err := bp.blockStore.Stage(blockHash, block) + if err != nil { + return err + } + + err = bp.blockValidator.ValidateBodyInIsolation(blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 81b5b19de..137bf0eeb 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -80,6 +80,10 @@ func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (ne } } - csm.consensusStateStore.StageTips(newTips) + err = csm.consensusStateStore.StageTips(newTips) + if err != nil { + return nil, err + } + return newTips, nil } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index f184f6333..3ecc2c3bc 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -68,7 +68,10 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap return 0, err } - csm.acceptanceDataStore.Stage(blockHash, acceptanceData) + err = csm.acceptanceDataStore.Stage(blockHash, acceptanceData) + if err != nil { + return 0, err + } block, err := csm.blockStore.Block(csm.databaseContext, blockHash) if err != nil { @@ -84,7 +87,10 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap } csm.multisetStore.Stage(blockHash, multiset) - csm.utxoDiffStore.Stage(blockHash, pastUTXODiff, nil) + err = csm.utxoDiffStore.Stage(blockHash, pastUTXODiff, nil) + if err != nil { + return 0, err + } err = csm.updateParentDiffs(blockHash, pastUTXODiff) if err != nil { @@ -120,7 +126,10 @@ func (csm *consensusStateManager) updateParentDiffs( return err } - csm.utxoDiffStore.Stage(parentHash, parentNewDiff, blockHash) + err = csm.utxoDiffStore.Stage(parentHash, parentNewDiff, blockHash) + if err != nil { + return err + } } return nil diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 8651162db..2cef787f9 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -58,7 +58,11 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt "point UTXO set is %s but got %s", headerTipsPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash()) } - csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes) + err = csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes) + if err != nil { + return err + } + err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes) if err != nil { return err @@ -137,9 +141,13 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH return nil, err } - csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{ + err = csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{ Parents: headerTips, }) + if err != nil { + return nil, err + } + defer csm.blockRelationStore.Discard() err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 39541096c..0fac18352 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -28,7 +28,10 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain return err } - csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) + err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) + if err != nil { + return err + } err = csm.updateVirtualDiffParents(newBlockHash, virtualUTXODiff) if err != nil { @@ -63,13 +66,14 @@ func (csm *consensusStateManager) updateVirtualDiffParents( if err != nil { return err } - csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, newBlockHash) + err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, newBlockHash) + if err != nil { + return err + } } else { newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } } - csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) - - return nil + return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) } diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index e354fa60c..cc1a30519 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -127,7 +127,11 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par for i, parentChild := range parentRelations.Children { if *parentChild == *blockHash { parentRelations.Children = append(parentRelations.Children[:i], parentRelations.Children[i+1:]...) - dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations) + err = dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations) + if err != nil { + return err + } + break } } @@ -149,15 +153,21 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par } if !isBlockAlreadyInChildren { parentRelations.Children = append(parentRelations.Children, blockHash) - dtm.blockRelationStore.StageBlockRelation(parent, parentRelations) + err = dtm.blockRelationStore.StageBlockRelation(parent, parentRelations) + if err != nil { + return err + } } } // Finally - create the relations for the block itself - dtm.blockRelationStore.StageBlockRelation(blockHash, &model.BlockRelations{ + err = dtm.blockRelationStore.StageBlockRelation(blockHash, &model.BlockRelations{ Parents: parentHashes, Children: []*externalapi.DomainHash{}, }) + if err != nil { + return err + } return nil } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index e1700331f..230377761 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -82,7 +82,11 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { newBlockData.BlueScore = 0 } - gm.ghostdagDataStore.Stage(blockHash, newBlockData) + err = gm.ghostdagDataStore.Stage(blockHash, newBlockData) + if err != nil { + return err + } + return nil } diff --git a/domain/consensus/processes/headertipsmanager/headertipsmanager.go b/domain/consensus/processes/headertipsmanager/headertipsmanager.go index c271de7a3..96ba6544d 100644 --- a/domain/consensus/processes/headertipsmanager/headertipsmanager.go +++ b/domain/consensus/processes/headertipsmanager/headertipsmanager.go @@ -53,6 +53,10 @@ func (h headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error { } newTips = append(newTips, hash) - h.headerTipsStore.Stage(newTips) + err = h.headerTipsStore.Stage(newTips) + if err != nil { + return err + } + return nil } diff --git a/domain/consensus/processes/reachabilitymanager/stage.go b/domain/consensus/processes/reachabilitymanager/stage.go index 0c38d61d8..563b42c57 100644 --- a/domain/consensus/processes/reachabilitymanager/stage.go +++ b/domain/consensus/processes/reachabilitymanager/stage.go @@ -5,8 +5,8 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) { - rt.reachabilityDataStore.StageReachabilityData(blockHash, data) +func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) error { + return rt.reachabilityDataStore.StageReachabilityData(blockHash, data) } func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.DomainHash, set model.FutureCoveringTreeNodeSet) error { @@ -16,8 +16,7 @@ func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.Dom } data.FutureCoveringSet = set - rt.reachabilityDataStore.StageReachabilityData(blockHash, data) - return nil + return rt.reachabilityDataStore.StageReachabilityData(blockHash, data) } func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash, node *model.ReachabilityTreeNode) error { @@ -27,8 +26,7 @@ func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash, } data.TreeNode = node - rt.reachabilityDataStore.StageReachabilityData(blockHash, data) - return nil + return rt.reachabilityDataStore.StageReachabilityData(blockHash, data) } func (rt *reachabilityManager) stageReindexRoot(blockHash *externalapi.DomainHash) { diff --git a/domain/consensus/utils/hashes/hash_array.go b/domain/consensus/utils/hashes/hash_array.go deleted file mode 100644 index 0e491df16..000000000 --- a/domain/consensus/utils/hashes/hash_array.go +++ /dev/null @@ -1,41 +0,0 @@ -package hashes - -import ( - "bytes" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" -) - -// DeserializeHashSlice decodes an array of DomainHashes from byte-slice representation -func DeserializeHashSlice(hashesBytes []byte) ([]*externalapi.DomainHash, error) { - if len(hashesBytes)%externalapi.DomainHashSize != 0 { - return nil, errors.Errorf("serialized hashes length is %d bytes, while it should be a multiple of %d", - len(hashesBytes), externalapi.DomainHashSize) - } - - hashes := make([]*externalapi.DomainHash, 0, len(hashesBytes)/externalapi.DomainHashSize) - - for i := 0; i < len(hashesBytes); i += externalapi.DomainHashSize { - hashBytes := hashesBytes[i : i+externalapi.DomainHashSize] - hash, err := FromBytes(hashBytes) - if err != nil { - return nil, err - } - - hashes = append(hashes, hash) - } - - return hashes, nil -} - -// SerializeHashSlice encodes a slice of DomainHashes into a byte slice -func SerializeHashSlice(hashes []*externalapi.DomainHash) []byte { - hashesBytes := make([][]byte, 0, len(hashes)) - - for _, hash := range hashes { - hashesBytes = append(hashesBytes, hash[:]) - } - - return bytes.Join(hashesBytes, []byte{}) -} From 135ffbd4f29e794a2082bdbfb78b690da32f6d42 Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 11 Nov 2020 12:31:13 +0200 Subject: [PATCH 014/351] [NOD-1529] Add getters + AddBlock to TestConsensus (#1025) * [NOD-1529] Add all stores and processes to consensus, and add access to TestConsensus * [NOD-1529] Move the getters of TestConsensus to separate file * [NOD-1529] Add AddBlock to TestConsensus * [NOD-1529] Update NewTestConsensus to be more all-encompassing * [NOD-1529] Remove test directory in teardown * [NOD-1529] Add ForAllNets function * [NOD-1529] Add comment --- domain/consensus/consensus.go | 26 +++- domain/consensus/factory.go | 55 +++++++-- .../consensus/model/testapi/test_consensus.go | 40 +++++- domain/consensus/test_consensus.go | 42 +++++++ domain/consensus/test_consensus_getters.go | 115 ++++++++++++++++++ .../consensus/utils/testutils/for_all_nets.go | 27 ++++ 6 files changed, 288 insertions(+), 17 deletions(-) create mode 100644 domain/consensus/test_consensus_getters.go create mode 100644 domain/consensus/utils/testutils/for_all_nets.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index b93ca8e87..9b5137de8 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -19,12 +19,28 @@ type consensus struct { transactionValidator model.TransactionValidator syncManager model.SyncManager pastMedianTimeManager model.PastMedianTimeManager + blockValidator model.BlockValidator + coinbaseManager model.CoinbaseManager + dagTopologyManager model.DAGTopologyManager + dagTraversalManager model.DAGTraversalManager + difficultyManager model.DifficultyManager + ghostdagManager model.GHOSTDAGManager + headerTipsManager model.HeaderTipsManager + mergeDepthManager model.MergeDepthManager + pruningManager model.PruningManager + reachabilityManager model.ReachabilityManager - blockStore model.BlockStore - blockHeaderStore model.BlockHeaderStore - pruningStore model.PruningStore - ghostdagDataStore model.GHOSTDAGDataStore - blockStatusStore model.BlockStatusStore + 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 } // BuildBlock builds a block over the current state, with the transactions diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 830a51fcc..3c7927706 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,8 +1,12 @@ package consensus import ( + "io/ioutil" + "os" "sync" + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" + consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore" "github.com/kaspanet/kaspad/domain/consensus/datastructures/blockheaderstore" @@ -42,7 +46,7 @@ import ( // Factory instantiates new Consensuses type Factory interface { NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) - NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (testapi.TestConsensus, error) + NewTestConsensus(dagParams *dagconfig.Params, testName string) (tc testapi.TestConsensus, teardown func(), err error) } type factory struct{} @@ -255,12 +259,27 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat transactionValidator: transactionValidator, syncManager: syncManager, pastMedianTimeManager: pastMedianTimeManager, + blockValidator: blockValidator, + coinbaseManager: coinbaseManager, + dagTopologyManager: dagTopologyManager, + dagTraversalManager: dagTraversalManager, + difficultyManager: difficultyManager, + ghostdagManager: ghostdagManager, + headerTipsManager: headerTipsManager, + mergeDepthManager: mergeDepthManager, + pruningManager: pruningManager, + reachabilityManager: reachabilityManager, - blockStore: blockStore, - blockHeaderStore: blockHeaderStore, - pruningStore: pruningStore, - ghostdagDataStore: ghostdagDataStore, - blockStatusStore: blockStatusStore, + blockStore: blockStore, + blockHeaderStore: blockHeaderStore, + pruningStore: pruningStore, + ghostdagDataStore: ghostdagDataStore, + blockStatusStore: blockStatusStore, + blockRelationStore: blockRelationStore, + consensusStateStore: consensusStateStore, + headerTipsStore: headerTipsStore, + multisetStore: multisetStore, + reachabilityDataStore: reachabilityDataStore, } genesisInfo, err := c.GetBlockInfo(genesisHash) @@ -278,18 +297,32 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat return c, nil } -func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) ( - testapi.TestConsensus, error) { +func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) ( + tc testapi.TestConsensus, teardown func(), err error) { + testDatabaseDir, err := ioutil.TempDir("", testName) + if err != nil { + return nil, nil, err + } + db, err := ldb.NewLevelDB(testDatabaseDir) + if err != nil { + return nil, nil, err + } consensusAsInterface, err := f.NewConsensus(dagParams, db) if err != nil { - return nil, err + return nil, nil, err } consensusAsImplementation := consensusAsInterface.(*consensus) - return &testConsensus{ + tc = &testConsensus{ consensus: consensusAsImplementation, testBlockBuilder: blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder), - }, nil + } + teardown = func() { + db.Close() + os.RemoveAll(testDatabaseDir) + } + + return tc, teardown, nil } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index ce291126d..1a1e994bc 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -1,6 +1,9 @@ package testapi -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // TestConsensus wraps the Consensus interface with some methods that are needed by tests only type TestConsensus interface { @@ -8,4 +11,39 @@ type TestConsensus interface { BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) + + // 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) + + AcceptanceDataStore() model.AcceptanceDataStore + BlockHeaderStore() model.BlockHeaderStore + BlockRelationStore() model.BlockRelationStore + BlockStatusStore() model.BlockStatusStore + BlockStore() model.BlockStore + ConsensusStateStore() model.ConsensusStateStore + GHOSTDAGDataStore() model.GHOSTDAGDataStore + HeaderTipsStore() model.HeaderTipsStore + MultisetStore() model.MultisetStore + PruningStore() model.PruningStore + ReachabilityDataStore() model.ReachabilityDataStore + UTXODiffStore() model.UTXODiffStore + + BlockBuilder() model.BlockBuilder + BlockProcessor() model.BlockProcessor + BlockValidator() model.BlockValidator + CoinbaseManager() model.CoinbaseManager + ConsensusStateManager() model.ConsensusStateManager + DAGTopologyManager() model.DAGTopologyManager + DAGTraversalManager() model.DAGTraversalManager + DifficultyManager() model.DifficultyManager + GHOSTDAGManager() model.GHOSTDAGManager + HeaderTipsManager() model.HeaderTipsManager + MergeDepthManager() model.MergeDepthManager + PastMedianTimeManager() model.PastMedianTimeManager + PruningManager() model.PruningManager + ReachabilityManager() model.ReachabilityManager + SyncManager() model.SyncManager + TransactionValidator() model.TransactionValidator } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 22c3eb80f..bf4c31077 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -1,8 +1,14 @@ package consensus import ( + "errors" + "math" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/util" ) type testConsensus struct { @@ -19,3 +25,39 @@ func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.Domai return tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) } + +func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error) { + + // Require write lock because BuildBlockWithParents stages temporary data + tc.lock.Lock() + defer tc.lock.Unlock() + + block, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) + if err != nil { + return nil, err + } + + solveBlock(block) + + err = tc.ValidateAndInsertBlock(block) + if err != nil { + return nil, err + } + + return consensusserialization.BlockHash(block), nil +} + +func solveBlock(block *externalapi.DomainBlock) { + targetDifficulty := util.CompactToBig(block.Header.Bits) + + for i := uint64(0); i < math.MaxUint64; i++ { + block.Header.Nonce = i + hash := consensusserialization.BlockHash(block) + if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { + return + } + } + + panic(errors.New("went over all the nonce space and couldn't find a single one that gives a valid block")) +} diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go new file mode 100644 index 000000000..6a6574f98 --- /dev/null +++ b/domain/consensus/test_consensus_getters.go @@ -0,0 +1,115 @@ +package consensus + +import "github.com/kaspanet/kaspad/domain/consensus/model" + +func (tc *testConsensus) AcceptanceDataStore() model.AcceptanceDataStore { + return tc.AcceptanceDataStore() +} + +func (tc *testConsensus) BlockHeaderStore() model.BlockHeaderStore { + return tc.blockHeaderStore +} + +func (tc *testConsensus) BlockRelationStore() model.BlockRelationStore { + return tc.blockRelationStore +} + +func (tc *testConsensus) BlockStatusStore() model.BlockStatusStore { + return tc.blockStatusStore +} + +func (tc *testConsensus) BlockStore() model.BlockStore { + return tc.blockStore +} + +func (tc *testConsensus) ConsensusStateStore() model.ConsensusStateStore { + return tc.consensusStateStore +} + +func (tc *testConsensus) GHOSTDAGDataStore() model.GHOSTDAGDataStore { + return tc.ghostdagDataStore +} + +func (tc *testConsensus) HeaderTipsStore() model.HeaderTipsStore { + return tc.headerTipsStore +} + +func (tc *testConsensus) MultisetStore() model.MultisetStore { + return tc.multisetStore +} + +func (tc *testConsensus) PruningStore() model.PruningStore { + return tc.pruningStore +} + +func (tc *testConsensus) ReachabilityDataStore() model.ReachabilityDataStore { + return tc.reachabilityDataStore +} + +func (tc *testConsensus) UTXODiffStore() model.UTXODiffStore { + return tc.utxoDiffStore +} + +func (tc *testConsensus) BlockBuilder() model.BlockBuilder { + return tc.blockBuilder +} + +func (tc *testConsensus) BlockProcessor() model.BlockProcessor { + return tc.blockProcessor +} + +func (tc *testConsensus) BlockValidator() model.BlockValidator { + return tc.blockValidator +} + +func (tc *testConsensus) CoinbaseManager() model.CoinbaseManager { + return tc.coinbaseManager +} + +func (tc *testConsensus) ConsensusStateManager() model.ConsensusStateManager { + return tc.consensusStateManager +} + +func (tc *testConsensus) DAGTopologyManager() model.DAGTopologyManager { + return tc.dagTopologyManager +} + +func (tc *testConsensus) DAGTraversalManager() model.DAGTraversalManager { + return tc.dagTraversalManager +} + +func (tc *testConsensus) DifficultyManager() model.DifficultyManager { + return tc.difficultyManager +} + +func (tc *testConsensus) GHOSTDAGManager() model.GHOSTDAGManager { + return tc.ghostdagManager +} + +func (tc *testConsensus) HeaderTipsManager() model.HeaderTipsManager { + return tc.headerTipsManager +} + +func (tc *testConsensus) MergeDepthManager() model.MergeDepthManager { + return tc.mergeDepthManager +} + +func (tc *testConsensus) PastMedianTimeManager() model.PastMedianTimeManager { + return tc.pastMedianTimeManager +} + +func (tc *testConsensus) PruningManager() model.PruningManager { + return tc.pruningManager +} + +func (tc *testConsensus) ReachabilityManager() model.ReachabilityManager { + return tc.reachabilityManager +} + +func (tc *testConsensus) SyncManager() model.SyncManager { + return tc.syncManager +} + +func (tc *testConsensus) TransactionValidator() model.TransactionValidator { + return tc.transactionValidator +} diff --git a/domain/consensus/utils/testutils/for_all_nets.go b/domain/consensus/utils/testutils/for_all_nets.go new file mode 100644 index 000000000..0fd718a8d --- /dev/null +++ b/domain/consensus/utils/testutils/for_all_nets.go @@ -0,0 +1,27 @@ +package testutils + +import ( + "testing" + + "github.com/kaspanet/kaspad/domain/dagconfig" +) + +// ForAllNets runs the passed testFunc with all available networks +// if setDifficultyToMinumum = true - will modify the net params to have minimal difficulty, like in SimNet +func ForAllNets(t *testing.T, setDifficultyToMinimum bool, testFunc func(*testing.T, *dagconfig.Params)) { + allParams := []dagconfig.Params{ + dagconfig.MainnetParams, + dagconfig.TestnetParams, + dagconfig.SimnetParams, + dagconfig.DevnetParams, + } + + for _, params := range allParams { + if setDifficultyToMinimum { + params.DisableDifficultyAdjustment = dagconfig.SimnetParams.DisableDifficultyAdjustment + params.TargetTimePerBlock = dagconfig.SimnetParams.TargetTimePerBlock + } + + testFunc(t, ¶ms) + } +} From 37fbdcb4536eec6de60798ee849e470c4994c3a7 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 12 Nov 2020 10:22:17 +0200 Subject: [PATCH 015/351] [NOD-1526] Restore txscript tests (#1019) * [NOD-1526] Fix compilation errors * [NOD-1526] Make MsgTx.PayloadHash non-pointer * [NOD-1526] Fixed many tests * [NOD-1526] Fix reference_test.go * [NOD-1526] Removed last instances of appmessage in consensus * [NOD-1526] No need to check for subnetwork --- app/appmessage/domainconverters.go | 4 +- app/appmessage/p2p_msgtx.go | 39 +- .../transaction_in_context.go | 11 +- domain/consensus/utils/constants/constants.go | 27 + .../consensus/utils/txscript/engine_test.go | 338 ++ domain/consensus/utils/txscript/opcode.go | 18 +- .../utils/txscript/reference_test.go | 398 ++ domain/consensus/utils/txscript/script.go | 3 +- .../consensus/utils/txscript/script_test.go | 3973 +++++++++++++++++ domain/consensus/utils/txscript/sign_test.go | 1101 +++++ .../consensus/utils/txscript/standard_test.go | 506 +++ domain/miningmanager/mempool/policy_test.go | 11 +- .../grpcserver/protowire/p2p_transaction.go | 10 +- 13 files changed, 6375 insertions(+), 64 deletions(-) create mode 100644 domain/consensus/utils/txscript/engine_test.go create mode 100644 domain/consensus/utils/txscript/reference_test.go create mode 100644 domain/consensus/utils/txscript/script_test.go create mode 100644 domain/consensus/utils/txscript/sign_test.go create mode 100644 domain/consensus/utils/txscript/standard_test.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 6d91961dc..460dc9dcb 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -77,7 +77,7 @@ func DomainTransactionToMsgTx(domainTransaction *externalapi.DomainTransaction) LockTime: domainTransaction.LockTime, SubnetworkID: domainTransaction.SubnetworkID, Gas: domainTransaction.Gas, - PayloadHash: &domainTransaction.PayloadHash, + PayloadHash: domainTransaction.PayloadHash, Payload: domainTransaction.Payload, } } @@ -121,7 +121,7 @@ func MsgTxToDomainTransaction(msgTx *MsgTx) *externalapi.DomainTransaction { LockTime: msgTx.LockTime, SubnetworkID: msgTx.SubnetworkID, Gas: msgTx.Gas, - PayloadHash: *msgTx.PayloadHash, + PayloadHash: msgTx.PayloadHash, Payload: msgTx.Payload, } } diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index f8691c66b..343e5cf58 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -6,9 +6,10 @@ package appmessage import ( "encoding/binary" - "math" "strconv" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" @@ -19,38 +20,10 @@ import ( ) const ( - // TxVersion is the current latest supported transaction version. - TxVersion = 1 - - // MaxTxInSequenceNum is the maximum sequence number the sequence field - // of a transaction input can be. - MaxTxInSequenceNum uint64 = math.MaxUint64 - // MaxPrevOutIndex is the maximum index the index field of a previous // outpoint can be. MaxPrevOutIndex uint32 = 0xffffffff - // SequenceLockTimeDisabled is a flag that if set on a transaction - // input's sequence number, the sequence number will not be interpreted - // as a relative locktime. - SequenceLockTimeDisabled = 1 << 31 - - // SequenceLockTimeIsSeconds is a flag that if set on a transaction - // input's sequence number, the relative locktime has units of 512 - // seconds. - SequenceLockTimeIsSeconds = 1 << 22 - - // SequenceLockTimeMask is a mask that extracts the relative locktime - // when masked against the transaction input sequence number. - SequenceLockTimeMask = 0x0000ffff - - // SequenceLockTimeGranularity is the defined time based granularity - // for milliseconds-based relative time locks. When converting from milliseconds - // to a sequence number, the value is right shifted by this amount, - // therefore the granularity of relative time locks in 524288 or 2^19 - // seconds. Enforced relative lock times are multiples of 524288 milliseconds. - SequenceLockTimeGranularity = 19 - // defaultTxInOutAlloc is the default size used for the backing array for // transaction inputs and outputs. The array will dynamically grow as needed, // but this figure is intended to provide enough space for the number of @@ -130,7 +103,7 @@ func NewTxIn(prevOut *Outpoint, signatureScript []byte) *TxIn { return &TxIn{ PreviousOutpoint: *prevOut, SignatureScript: signatureScript, - Sequence: MaxTxInSequenceNum, + Sequence: constants.MaxTxInSequenceNum, } } @@ -163,7 +136,7 @@ type MsgTx struct { LockTime uint64 SubnetworkID externalapi.DomainSubnetworkID Gas uint64 - PayloadHash *externalapi.DomainHash + PayloadHash externalapi.DomainHash Payload []byte } @@ -310,9 +283,9 @@ func newMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, subnetworkID *externa txOut = make([]*TxOut, 0, defaultTxInOutAlloc) } - var payloadHash *externalapi.DomainHash + var payloadHash externalapi.DomainHash if *subnetworkID != subnetworks.SubnetworkIDNative { - payloadHash = hashes.HashData(payload) + payloadHash = *hashes.HashData(payload) } return &MsgTx{ diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index 8121ce600..3f7f9a5bb 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -1,7 +1,6 @@ package transactionvalidator import ( - "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" @@ -248,14 +247,14 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries( // mask in order to obtain the time lock delta required before // this input can be spent. sequenceNum := input.Sequence - relativeLock := int64(sequenceNum & appmessage.SequenceLockTimeMask) + relativeLock := int64(sequenceNum & constants.SequenceLockTimeMask) switch { // Relative time locks are disabled for this input, so we can // skip any further calculation. - case sequenceNum&appmessage.SequenceLockTimeDisabled == appmessage.SequenceLockTimeDisabled: + case sequenceNum&constants.SequenceLockTimeDisabled == constants.SequenceLockTimeDisabled: continue - case sequenceNum&appmessage.SequenceLockTimeIsSeconds == appmessage.SequenceLockTimeIsSeconds: + case sequenceNum&constants.SequenceLockTimeIsSeconds == constants.SequenceLockTimeIsSeconds: // This input requires a relative time lock expressed // in seconds before it can be spent. Therefore, we // need to query for the block prior to the one in @@ -290,11 +289,11 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries( } // Time based relative time-locks have a time granularity of - // appmessage.SequenceLockTimeGranularity, so we shift left by this + // constants.SequenceLockTimeGranularity, so we shift left by this // amount to convert to the proper relative time-lock. We also // subtract one from the relative lock to maintain the original // lockTime semantics. - timeLockMilliseconds := (relativeLock << appmessage.SequenceLockTimeGranularity) - 1 + timeLockMilliseconds := (relativeLock << constants.SequenceLockTimeGranularity) - 1 timeLock := medianTime + timeLockMilliseconds if timeLock > sequenceLock.Milliseconds { sequenceLock.Milliseconds = timeLock diff --git a/domain/consensus/utils/constants/constants.go b/domain/consensus/utils/constants/constants.go index 02e83dc45..87cf247ee 100644 --- a/domain/consensus/utils/constants/constants.go +++ b/domain/consensus/utils/constants/constants.go @@ -1,5 +1,7 @@ package constants +import "math" + const ( // BlockVersion represents the current version of blocks mined and the maximum block version // this node is able to validate @@ -46,4 +48,29 @@ const ( // CoinbasePayloadScriptPublicKeyMaxLength is the maximum allowed script public key in the coinbase's payload CoinbasePayloadScriptPublicKeyMaxLength = 150 + + // MaxTxInSequenceNum is the maximum sequence number the sequence field + // of a transaction input can be. + MaxTxInSequenceNum uint64 = math.MaxUint64 + + // SequenceLockTimeDisabled is a flag that if set on a transaction + // input's sequence number, the sequence number will not be interpreted + // as a relative locktime. + SequenceLockTimeDisabled = 1 << 31 + + // SequenceLockTimeIsSeconds is a flag that if set on a transaction + // input's sequence number, the relative locktime has units of 512 + // seconds. + SequenceLockTimeIsSeconds = 1 << 22 + + // SequenceLockTimeMask is a mask that extracts the relative locktime + // when masked against the transaction input sequence number. + SequenceLockTimeMask = 0x0000ffff + + // SequenceLockTimeGranularity is the defined time based granularity + // for milliseconds-based relative time locks. When converting from milliseconds + // to a sequence number, the value is right shifted by this amount, + // therefore the granularity of relative time locks in 524288 or 2^19 + // seconds. Enforced relative lock times are multiples of 524288 milliseconds. + SequenceLockTimeGranularity = 19 ) diff --git a/domain/consensus/utils/txscript/engine_test.go b/domain/consensus/utils/txscript/engine_test.go new file mode 100644 index 000000000..46f1dafc6 --- /dev/null +++ b/domain/consensus/utils/txscript/engine_test.go @@ -0,0 +1,338 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package txscript + +import ( + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// TestBadPC sets the pc to a deliberately bad result then confirms that Step() +// and Disasm fail correctly. +func TestBadPC(t *testing.T) { + t.Parallel() + + tests := []struct { + script, off int + }{ + {script: 2, off: 0}, + {script: 0, off: 2}, + } + + // tx with almost empty scripts. + inputs := []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: mustParseShortForm(""), + Sequence: 4294967295, + }, + } + outputs := []*externalapi.DomainTransactionOutput{{ + Value: 1000000000, + ScriptPublicKey: nil, + }} + tx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: inputs, + Outputs: outputs, + } + scriptPubKey := mustParseShortForm("NOP") + + for _, test := range tests { + vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) + if err != nil { + t.Errorf("Failed to create script: %v", err) + } + + // set to after all scripts + vm.scriptIdx = test.script + vm.scriptOff = test.off + + _, err = vm.Step() + if err == nil { + t.Errorf("Step with invalid pc (%v) succeeds!", test) + continue + } + + _, err = vm.DisasmPC() + if err == nil { + t.Errorf("DisasmPC with invalid pc (%v) succeeds!", + test) + } + } +} + +func TestCheckErrorCondition(t *testing.T) { + tests := []struct { + script string + finalScript bool + stepCount int + expectedErr error + }{ + {"OP_1", true, 1, nil}, + {"NOP", true, 0, scriptError(ErrScriptUnfinished, "")}, + {"NOP", true, 1, scriptError(ErrEmptyStack, "")}, + {"OP_1 OP_1", true, 2, scriptError(ErrCleanStack, "")}, + {"OP_0", true, 1, scriptError(ErrEvalFalse, "")}, + } + + for i, test := range tests { + func() { + inputs := []*externalapi.DomainTransactionInput{{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: nil, + Sequence: 4294967295, + }} + outputs := []*externalapi.DomainTransactionOutput{{ + Value: 1000000000, + ScriptPublicKey: nil, + }} + tx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: inputs, + Outputs: outputs, + } + + scriptPubKey := mustParseShortForm(test.script) + + vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) + if err != nil { + t.Errorf("TestCheckErrorCondition: %d: failed to create script: %v", i, err) + } + + for j := 0; j < test.stepCount; j++ { + _, err = vm.Step() + if err != nil { + t.Errorf("TestCheckErrorCondition: %d: failed to execute step No. %d: %v", i, j+1, err) + return + } + + if j != test.stepCount-1 { + err = vm.CheckErrorCondition(false) + if !IsErrorCode(err, ErrScriptUnfinished) { + t.Fatalf("TestCheckErrorCondition: %d: got unexepected error %v on %dth iteration", + i, err, j) + return + } + } + } + + err = vm.CheckErrorCondition(test.finalScript) + if e := checkScriptError(err, test.expectedErr); e != nil { + t.Errorf("TestCheckErrorCondition: %d: %s", i, e) + } + }() + } +} + +// TestCheckPubKeyEncoding ensures the internal checkPubKeyEncoding function +// works as expected. +func TestCheckPubKeyEncoding(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + key []byte + isValid bool + }{ + { + name: "uncompressed ok", + key: hexToBytes("0411db93e1dcdb8a016b49840f8c53bc1eb68" + + "a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf" + + "9744464f82e160bfa9b8b64f9d4c03f999b8643f656b" + + "412a3"), + isValid: true, + }, + { + name: "compressed ok", + key: hexToBytes("02ce0b14fb842b1ba549fdd675c98075f12e9" + + "c510f8ef52bd021a9a1f4809d3b4d"), + isValid: true, + }, + { + name: "compressed ok", + key: hexToBytes("032689c7c2dab13309fb143e0e8fe39634252" + + "1887e976690b6b47f5b2a4b7d448e"), + isValid: true, + }, + { + name: "hybrid", + key: hexToBytes("0679be667ef9dcbbac55a06295ce870b07029" + + "bfcdb2dce28d959f2815b16f81798483ada7726a3c46" + + "55da4fbfc0e1108a8fd17b448a68554199c47d08ffb1" + + "0d4b8"), + isValid: false, + }, + { + name: "empty", + key: nil, + isValid: false, + }, + } + + vm := Engine{} + for _, test := range tests { + err := vm.checkPubKeyEncoding(test.key) + if err != nil && test.isValid { + t.Errorf("checkSignatureLength test '%s' failed "+ + "when it should have succeeded: %v", test.name, + err) + } else if err == nil && !test.isValid { + t.Errorf("checkSignatureEncooding test '%s' succeeded "+ + "when it should have failed", test.name) + } + } + +} + +func TestDisasmPC(t *testing.T) { + t.Parallel() + + // tx with almost empty scripts. + inputs := []*externalapi.DomainTransactionInput{{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: mustParseShortForm("OP_2"), + Sequence: 4294967295, + }} + outputs := []*externalapi.DomainTransactionOutput{{ + Value: 1000000000, + ScriptPublicKey: nil, + }} + tx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: inputs, + Outputs: outputs, + } + + scriptPubKey := mustParseShortForm("OP_DROP NOP TRUE") + + vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) + if err != nil { + t.Fatalf("failed to create script: %v", err) + } + + tests := []struct { + expected string + expectedErr error + }{ + {"00:0000: OP_2", nil}, + {"01:0000: OP_DROP", nil}, + {"01:0001: OP_NOP", nil}, + {"01:0002: OP_1", nil}, + {"", scriptError(ErrInvalidProgramCounter, "")}, + } + + for i, test := range tests { + actual, err := vm.DisasmPC() + if e := checkScriptError(err, test.expectedErr); e != nil { + t.Errorf("TestDisasmPC: %d: %s", i, e) + } + + if actual != test.expected { + t.Errorf("TestDisasmPC: %d: expected: '%s'. Got: '%s'", i, test.expected, actual) + } + + // ignore results from vm.Step() to keep going even when no opcodes left, to hit error case + _, _ = vm.Step() + } +} + +func TestDisasmScript(t *testing.T) { + t.Parallel() + + // tx with almost empty scripts. + inputs := []*externalapi.DomainTransactionInput{{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc9, 0x97, 0xa5, 0xe5, + 0x6e, 0x10, 0x41, 0x02, + 0xfa, 0x20, 0x9c, 0x6a, + 0x85, 0x2d, 0xd9, 0x06, + 0x60, 0xa2, 0x0b, 0x2d, + 0x9c, 0x35, 0x24, 0x23, + 0xed, 0xce, 0x25, 0x85, + 0x7f, 0xcd, 0x37, 0x04, + }), + Index: 0, + }, + SignatureScript: mustParseShortForm("OP_2"), + Sequence: 4294967295, + }} + outputs := []*externalapi.DomainTransactionOutput{{ + Value: 1000000000, + ScriptPublicKey: nil, + }} + tx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: inputs, + Outputs: outputs, + } + + scriptPubKey := mustParseShortForm("OP_DROP NOP TRUE") + + vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) + if err != nil { + t.Fatalf("failed to create script: %v", err) + } + + tests := []struct { + index int + expected string + expectedErr error + }{ + {-1, "", scriptError(ErrInvalidIndex, "")}, + {0, "00:0000: OP_2\n", nil}, + {1, "01:0000: OP_DROP\n01:0001: OP_NOP\n01:0002: OP_1\n", nil}, + {2, "", scriptError(ErrInvalidIndex, "")}, + } + + for _, test := range tests { + actual, err := vm.DisasmScript(test.index) + if e := checkScriptError(err, test.expectedErr); e != nil { + t.Errorf("TestDisasmScript: %d: %s", test.index, e) + } + + if actual != test.expected { + t.Errorf("TestDisasmScript: %d: expected: '%s'. Got: '%s'", test.index, test.expected, actual) + } + } +} diff --git a/domain/consensus/utils/txscript/opcode.go b/domain/consensus/utils/txscript/opcode.go index 784bf13d1..f87bb87b0 100644 --- a/domain/consensus/utils/txscript/opcode.go +++ b/domain/consensus/utils/txscript/opcode.go @@ -12,12 +12,12 @@ import ( "fmt" "hash" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "golang.org/x/crypto/ripemd160" - - "github.com/kaspanet/kaspad/app/appmessage" ) // An opcode defines the information related to a txscript opcode. opfunc, if @@ -1149,7 +1149,7 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error { // The lock time feature can also be disabled, thereby bypassing // OP_CHECKLOCKTIMEVERIFY, if every transaction input has been finalized by - // setting its sequence to the maximum value (appmessage.MaxTxInSequenceNum). This + // setting its sequence to the maximum value (constants.MaxTxInSequenceNum). This // condition would result in the transaction being allowed into the blockDAG // making the opcode ineffective. // @@ -1161,7 +1161,7 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error { // NOTE: This implies that even if the transaction is not finalized due to // another input being unlocked, the opcode execution will still fail when the // input being used by the opcode is locked. - if vm.tx.Inputs[vm.txIdx].Sequence == appmessage.MaxTxInSequenceNum { + if vm.tx.Inputs[vm.txIdx].Sequence == constants.MaxTxInSequenceNum { return scriptError(ErrUnsatisfiedLockTime, "transaction input is finalized") } @@ -1205,7 +1205,7 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { // To provide for future soft-fork extensibility, if the // operand has the disabled lock-time flag set, // CHECKSEQUENCEVERIFY behaves as a NOP. - if sequence&uint64(appmessage.SequenceLockTimeDisabled) != 0 { + if sequence&uint64(constants.SequenceLockTimeDisabled) != 0 { return nil } @@ -1214,17 +1214,17 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { // number does not have this bit set prevents using this property // to get around a CHECKSEQUENCEVERIFY check. txSequence := vm.tx.Inputs[vm.txIdx].Sequence - if txSequence&appmessage.SequenceLockTimeDisabled != 0 { + if txSequence&constants.SequenceLockTimeDisabled != 0 { str := fmt.Sprintf("transaction sequence has sequence "+ "locktime disabled bit set: 0x%x", txSequence) return scriptError(ErrUnsatisfiedLockTime, str) } // Mask off non-consensus bits before doing comparisons. - lockTimeMask := uint64(appmessage.SequenceLockTimeIsSeconds | - appmessage.SequenceLockTimeMask) + lockTimeMask := uint64(constants.SequenceLockTimeIsSeconds | + constants.SequenceLockTimeMask) return verifyLockTime(txSequence&lockTimeMask, - appmessage.SequenceLockTimeIsSeconds, sequence&lockTimeMask) + constants.SequenceLockTimeIsSeconds, sequence&lockTimeMask) } // opcodeToAltStack removes the top item from the main data stack and pushes it diff --git a/domain/consensus/utils/txscript/reference_test.go b/domain/consensus/utils/txscript/reference_test.go new file mode 100644 index 000000000..1ff595b32 --- /dev/null +++ b/domain/consensus/utils/txscript/reference_test.go @@ -0,0 +1,398 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package txscript + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "strconv" + "strings" + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" +) + +// scriptTestName returns a descriptive test name for the given reference script +// test data. +func scriptTestName(test []interface{}) (string, error) { + // The test must consist of a signature script, public key script, flags, + // and expected error. Finally, it may optionally contain a comment. + if len(test) < 4 || len(test) > 5 { + return "", errors.Errorf("invalid test length %d", len(test)) + } + + // Use the comment for the test name if one is specified, otherwise, + // construct the name based on the signature script, public key script, + // and flags. + var name string + if len(test) == 5 { + name = fmt.Sprintf("test (%s)", test[4]) + } else { + name = fmt.Sprintf("test ([%s, %s, %s])", test[0], + test[1], test[2]) + } + return name, nil +} + +// parse hex string into a []byte. +func parseHex(tok string) ([]byte, error) { + if !strings.HasPrefix(tok, "0x") { + return nil, errors.New("not a hex number") + } + return hex.DecodeString(tok[2:]) +} + +// shortFormOps holds a map of opcode names to values for use in short form +// parsing. It is declared here so it only needs to be created once. +var shortFormOps map[string]byte + +// parseShortForm parses a string into a script as follows: +// - Opcodes other than the push opcodes and unknown are present as +// either OP_NAME or just NAME +// - Plain numbers are made into push operations +// - Numbers beginning with 0x are inserted into the []byte as-is (so +// 0x14 is OP_DATA_20) +// - Single quoted strings are pushed as data +// - Anything else is an error +func parseShortForm(script string) ([]byte, error) { + // Only create the short form opcode map once. + if shortFormOps == nil { + ops := make(map[string]byte) + for opcodeName, opcodeValue := range OpcodeByName { + if strings.Contains(opcodeName, "OP_UNKNOWN") { + continue + } + ops[opcodeName] = opcodeValue + + // The opcodes named OP_# can't have the OP_ prefix + // stripped or they would conflict with the plain + // numbers. Also, since OP_FALSE and OP_TRUE are + // aliases for the OP_0, and OP_1, respectively, they + // have the same value, so detect those by name and + // allow them. + if (opcodeName == "OP_FALSE" || opcodeName == "OP_TRUE") || + (opcodeValue != Op0 && (opcodeValue < Op1 || + opcodeValue > Op16)) { + + ops[strings.TrimPrefix(opcodeName, "OP_")] = opcodeValue + } + } + shortFormOps = ops + } + + // Split only does one separator so convert all \n and tab into space. + script = strings.Replace(script, "\n", " ", -1) + script = strings.Replace(script, "\t", " ", -1) + tokens := strings.Split(script, " ") + builder := NewScriptBuilder() + + for _, tok := range tokens { + if len(tok) == 0 { + continue + } + // if parses as a plain number + if num, err := strconv.ParseInt(tok, 10, 64); err == nil { + builder.AddInt64(num) + continue + } else if bts, err := parseHex(tok); err == nil { + // Concatenate the bytes manually since the test code + // intentionally creates scripts that are too large and + // would cause the builder to error otherwise. + if builder.err == nil { + builder.script = append(builder.script, bts...) + } + } else if len(tok) >= 2 && + tok[0] == '\'' && tok[len(tok)-1] == '\'' { + builder.AddFullData([]byte(tok[1 : len(tok)-1])) + } else if opcode, ok := shortFormOps[tok]; ok { + builder.AddOp(opcode) + } else { + return nil, errors.Errorf("bad token %q", tok) + } + + } + return builder.Script() +} + +// parseScriptFlags parses the provided flags string from the format used in the +// reference tests into ScriptFlags suitable for use in the script engine. +func parseScriptFlags(flagStr string) (ScriptFlags, error) { + var flags ScriptFlags + + sFlags := strings.Split(flagStr, ",") + for _, flag := range sFlags { + switch flag { + case "": + // Nothing. + case "DISCOURAGE_UPGRADABLE_NOPS": + flags |= ScriptDiscourageUpgradableNops + default: + return flags, errors.Errorf("invalid flag: %s", flag) + } + } + return flags, nil +} + +// parseExpectedResult parses the provided expected result string into allowed +// script error codes. An error is returned if the expected result string is +// not supported. +func parseExpectedResult(expected string) ([]ErrorCode, error) { + switch expected { + case "OK": + return nil, nil + case "UNKNOWN_ERROR": + return []ErrorCode{ErrNumberTooBig, ErrMinimalData}, nil + case "PUBKEYFORMAT": + return []ErrorCode{ErrPubKeyFormat}, nil + case "EVAL_FALSE": + return []ErrorCode{ErrEvalFalse, ErrEmptyStack}, nil + case "EMPTY_STACK": + return []ErrorCode{ErrEmptyStack}, nil + case "EQUALVERIFY": + return []ErrorCode{ErrEqualVerify}, nil + case "NULLFAIL": + return []ErrorCode{ErrNullFail}, nil + case "SIG_HIGH_S": + return []ErrorCode{ErrSigHighS}, nil + case "SIG_HASHTYPE": + return []ErrorCode{ErrInvalidSigHashType}, nil + case "SIG_PUSHONLY": + return []ErrorCode{ErrNotPushOnly}, nil + case "CLEANSTACK": + return []ErrorCode{ErrCleanStack}, nil + case "BAD_OPCODE": + return []ErrorCode{ErrReservedOpcode, ErrMalformedPush}, nil + case "UNBALANCED_CONDITIONAL": + return []ErrorCode{ErrUnbalancedConditional, + ErrInvalidStackOperation}, nil + case "OP_RETURN": + return []ErrorCode{ErrEarlyReturn}, nil + case "VERIFY": + return []ErrorCode{ErrVerify}, nil + case "INVALID_STACK_OPERATION", "INVALID_ALTSTACK_OPERATION": + return []ErrorCode{ErrInvalidStackOperation}, nil + case "DISABLED_OPCODE": + return []ErrorCode{ErrDisabledOpcode}, nil + case "DISCOURAGE_UPGRADABLE_NOPS": + return []ErrorCode{ErrDiscourageUpgradableNOPs}, nil + case "PUSH_SIZE": + return []ErrorCode{ErrElementTooBig}, nil + case "OP_COUNT": + return []ErrorCode{ErrTooManyOperations}, nil + case "STACK_SIZE": + return []ErrorCode{ErrStackOverflow}, nil + case "SCRIPT_SIZE": + return []ErrorCode{ErrScriptTooBig}, nil + case "PUBKEY_COUNT": + return []ErrorCode{ErrInvalidPubKeyCount}, nil + case "SIG_COUNT": + return []ErrorCode{ErrInvalidSignatureCount}, nil + case "MINIMALDATA": + return []ErrorCode{ErrMinimalData}, nil + case "NEGATIVE_LOCKTIME": + return []ErrorCode{ErrNegativeLockTime}, nil + case "UNSATISFIED_LOCKTIME": + return []ErrorCode{ErrUnsatisfiedLockTime}, nil + case "MINIMALIF": + return []ErrorCode{ErrMinimalIf}, nil + } + + return nil, errors.Errorf("unrecognized expected result in test data: %v", + expected) +} + +// createSpendTx generates a basic spending transaction given the passed +// signature and public key scripts. +func createSpendingTx(sigScript, scriptPubKey []byte) *externalapi.DomainTransaction { + outpoint := externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: ^uint32(0), + } + input := &externalapi.DomainTransactionInput{ + PreviousOutpoint: outpoint, + SignatureScript: []byte{Op0, Op0}, + Sequence: constants.MaxTxInSequenceNum, + } + output := &externalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPubKey} + coinbaseTx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{input}, + Outputs: []*externalapi.DomainTransactionOutput{output}, + } + + outpoint = externalapi.DomainOutpoint{ + TransactionID: *consensusserialization.TransactionID(coinbaseTx), + Index: 0, + } + input = &externalapi.DomainTransactionInput{ + PreviousOutpoint: outpoint, + SignatureScript: sigScript, + Sequence: constants.MaxTxInSequenceNum, + } + output = &externalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: nil} + spendingTx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{input}, + Outputs: []*externalapi.DomainTransactionOutput{output}, + } + + return spendingTx +} + +// testScripts ensures all of the passed script tests execute with the expected +// results with or without using a signature cache, as specified by the +// parameter. +func testScripts(t *testing.T, tests [][]interface{}, useSigCache bool) { + // Create a signature cache to use only if requested. + var sigCache *SigCache + if useSigCache { + sigCache = NewSigCache(10) + } + + for i, test := range tests { + // "Format is: [[wit..., amount]?, scriptSig, scriptPubKey, + // flags, expected_scripterror, ... comments]" + + // Skip single line comments. + if len(test) == 1 { + continue + } + + // Construct a name for the test based on the comment and test + // data. + name, err := scriptTestName(test) + if err != nil { + t.Errorf("TestScripts: invalid test #%d: %v", i, err) + continue + } + + // Extract and parse the signature script from the test fields. + scriptSigStr, ok := test[0].(string) + if !ok { + t.Errorf("%s: signature script is not a string", name) + continue + } + scriptSig, err := parseShortForm(scriptSigStr) + if err != nil { + t.Errorf("%s: can't parse signature script: %v", name, + err) + continue + } + + // Extract and parse the public key script from the test fields. + scriptPubKeyStr, ok := test[1].(string) + if !ok { + t.Errorf("%s: public key script is not a string", name) + continue + } + scriptPubKey, err := parseShortForm(scriptPubKeyStr) + if err != nil { + t.Errorf("%s: can't parse public key script: %v", name, + err) + continue + } + + // Extract and parse the script flags from the test fields. + flagsStr, ok := test[2].(string) + if !ok { + t.Errorf("%s: flags field is not a string", name) + continue + } + flags, err := parseScriptFlags(flagsStr) + if err != nil { + t.Errorf("%s: %v", name, err) + continue + } + + // Extract and parse the expected result from the test fields. + // + // Convert the expected result string into the allowed script + // error codes. This is necessary because txscript is more + // fine grained with its errors than the reference test data, so + // some of the reference test data errors map to more than one + // possibility. + resultStr, ok := test[3].(string) + if !ok { + t.Errorf("%s: result field is not a string", name) + continue + } + allowedErrorCodes, err := parseExpectedResult(resultStr) + if err != nil { + t.Errorf("%s: %v", name, err) + continue + } + + // Generate a transaction pair such that one spends from the + // other and the provided signature and public key scripts are + // used, then create a new engine to execute the scripts. + tx := createSpendingTx(scriptSig, scriptPubKey) + + vm, err := NewEngine(scriptPubKey, tx, 0, flags, sigCache) + if err == nil { + err = vm.Execute() + } + + // Ensure there were no errors when the expected result is OK. + if resultStr == "OK" { + if err != nil { + t.Errorf("%s failed to execute: %v", name, err) + } + continue + } + + // At this point an error was expected so ensure the result of + // the execution matches it. + success := false + for _, code := range allowedErrorCodes { + if IsErrorCode(err, code) { + success = true + break + } + } + if !success { + var scriptErr Error + if ok := errors.As(err, &scriptErr); ok { + t.Errorf("%s: want error codes %v, got %v", name, + allowedErrorCodes, scriptErr.ErrorCode) + continue + } + t.Errorf("%s: want error codes %v, got err: %v (%T)", + name, allowedErrorCodes, err, err) + continue + } + } +} + +// TestScripts ensures all of the tests in script_tests.json execute with the +// expected results as defined in the test data. +func TestScripts(t *testing.T) { + file, err := ioutil.ReadFile("data/script_tests.json") + if err != nil { + t.Fatalf("TestScripts: %v\n", err) + } + + var tests [][]interface{} + err = json.Unmarshal(file, &tests) + if err != nil { + t.Fatalf("TestScripts couldn't Unmarshal: %v", err) + } + + // Disable non-test logs + logLevel := log.Level() + log.SetLevel(logger.LevelOff) + defer log.SetLevel(logLevel) + + // Run all script tests with and without the signature cache. + testScripts(t, tests, true) + testScripts(t, tests, false) +} diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index 17f6a1360..7615c2544 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -7,6 +7,7 @@ package txscript import ( "bytes" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/pkg/errors" @@ -255,8 +256,6 @@ func shallowCopyTx(tx *externalapi.DomainTransaction) externalapi.DomainTransact // for the copied inputs and outputs and point the final slice of // pointers into the contiguous arrays. This avoids a lot of small // allocations. - // Specifically avoid using appmessage.NewMsgTx() to prevent correcting errors by - // auto-generating various fields. txCopy := externalapi.DomainTransaction{ Version: tx.Version, Inputs: make([]*externalapi.DomainTransactionInput, len(tx.Inputs)), diff --git a/domain/consensus/utils/txscript/script_test.go b/domain/consensus/utils/txscript/script_test.go new file mode 100644 index 000000000..70a08e21e --- /dev/null +++ b/domain/consensus/utils/txscript/script_test.go @@ -0,0 +1,3973 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package txscript + +import ( + "bytes" + "reflect" + "testing" +) + +// TestParseOpcode tests for opcode parsing with bad data templates. +func TestParseOpcode(t *testing.T) { + // Deep copy the array and make one of the opcodes invalid by setting it + // to the wrong length. + fakeArray := opcodeArray + fakeArray[OpPushData4] = opcode{value: OpPushData4, + name: "OP_PUSHDATA4", length: -8, opfunc: opcodePushData} + + // This script would be fine if -8 was a valid length. + _, err := parseScriptTemplate([]byte{OpPushData4, 0x1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}, &fakeArray) + if err == nil { + t.Errorf("no error with dodgy opcode array!") + } +} + +// TestUnparsingInvalidOpcodes tests for errors when unparsing invalid parsed +// opcodes. +func TestUnparsingInvalidOpcodes(t *testing.T) { + tests := []struct { + name string + pop *parsedOpcode + expectedErr error + }{ + { + name: "OP_FALSE", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpFalse], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_FALSE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpFalse], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_1 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData1], + data: nil, + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_1", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData1], + data: make([]byte, 1), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_1 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData1], + data: make([]byte, 2), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_2 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData2], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_2", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData2], + data: make([]byte, 2), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_2 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData2], + data: make([]byte, 3), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_3 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData3], + data: make([]byte, 2), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_3", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData3], + data: make([]byte, 3), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_3 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData3], + data: make([]byte, 4), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_4 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData4], + data: make([]byte, 3), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_4", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData4], + data: make([]byte, 4), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_4 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData4], + data: make([]byte, 5), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_5 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData5], + data: make([]byte, 4), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_5", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData5], + data: make([]byte, 5), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_5 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData5], + data: make([]byte, 6), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_6 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData6], + data: make([]byte, 5), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_6", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData6], + data: make([]byte, 6), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_6 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData6], + data: make([]byte, 7), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_7 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData7], + data: make([]byte, 6), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_7", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData7], + data: make([]byte, 7), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_7 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData7], + data: make([]byte, 8), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_8 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData8], + data: make([]byte, 7), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_8", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData8], + data: make([]byte, 8), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_8 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData8], + data: make([]byte, 9), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_9 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData9], + data: make([]byte, 8), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_9", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData9], + data: make([]byte, 9), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_9 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData9], + data: make([]byte, 10), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_10 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData10], + data: make([]byte, 9), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_10", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData10], + data: make([]byte, 10), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_10 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData10], + data: make([]byte, 11), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_11 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData11], + data: make([]byte, 10), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_11", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData11], + data: make([]byte, 11), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_11 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData11], + data: make([]byte, 12), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_12 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData12], + data: make([]byte, 11), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_12", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData12], + data: make([]byte, 12), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_12 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData12], + data: make([]byte, 13), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_13 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData13], + data: make([]byte, 12), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_13", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData13], + data: make([]byte, 13), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_13 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData13], + data: make([]byte, 14), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_14 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData14], + data: make([]byte, 13), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_14", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData14], + data: make([]byte, 14), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_14 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData14], + data: make([]byte, 15), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_15 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData15], + data: make([]byte, 14), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_15", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData15], + data: make([]byte, 15), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_15 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData15], + data: make([]byte, 16), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_16 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData16], + data: make([]byte, 15), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_16", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData16], + data: make([]byte, 16), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_16 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData16], + data: make([]byte, 17), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_17 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData17], + data: make([]byte, 16), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_17", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData17], + data: make([]byte, 17), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_17 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData17], + data: make([]byte, 18), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_18 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData18], + data: make([]byte, 17), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_18", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData18], + data: make([]byte, 18), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_18 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData18], + data: make([]byte, 19), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_19 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData19], + data: make([]byte, 18), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_19", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData19], + data: make([]byte, 19), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_19 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData19], + data: make([]byte, 20), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_20 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData20], + data: make([]byte, 19), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_20", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData20], + data: make([]byte, 20), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_20 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData20], + data: make([]byte, 21), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_21 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData21], + data: make([]byte, 20), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_21", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData21], + data: make([]byte, 21), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_21 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData21], + data: make([]byte, 22), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_22 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData22], + data: make([]byte, 21), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_22", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData22], + data: make([]byte, 22), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_22 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData22], + data: make([]byte, 23), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_23 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData23], + data: make([]byte, 22), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_23", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData23], + data: make([]byte, 23), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_23 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData23], + data: make([]byte, 24), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_24 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData24], + data: make([]byte, 23), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_24", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData24], + data: make([]byte, 24), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_24 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData24], + data: make([]byte, 25), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_25 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData25], + data: make([]byte, 24), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_25", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData25], + data: make([]byte, 25), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_25 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData25], + data: make([]byte, 26), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_26 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData26], + data: make([]byte, 25), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_26", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData26], + data: make([]byte, 26), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_26 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData26], + data: make([]byte, 27), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_27 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData27], + data: make([]byte, 26), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_27", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData27], + data: make([]byte, 27), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_27 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData27], + data: make([]byte, 28), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_28 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData28], + data: make([]byte, 27), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_28", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData28], + data: make([]byte, 28), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_28 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData28], + data: make([]byte, 29), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_29 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData29], + data: make([]byte, 28), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_29", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData29], + data: make([]byte, 29), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_29 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData29], + data: make([]byte, 30), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_30 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData30], + data: make([]byte, 29), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_30", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData30], + data: make([]byte, 30), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_30 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData30], + data: make([]byte, 31), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_31 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData31], + data: make([]byte, 30), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_31", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData31], + data: make([]byte, 31), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_31 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData31], + data: make([]byte, 32), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_32 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData32], + data: make([]byte, 31), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_32", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData32], + data: make([]byte, 32), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_32 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData32], + data: make([]byte, 33), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_33 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData33], + data: make([]byte, 32), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_33", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData33], + data: make([]byte, 33), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_33 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData33], + data: make([]byte, 34), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_34 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData34], + data: make([]byte, 33), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_34", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData34], + data: make([]byte, 34), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_34 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData34], + data: make([]byte, 35), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_35 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData35], + data: make([]byte, 34), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_35", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData35], + data: make([]byte, 35), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_35 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData35], + data: make([]byte, 36), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_36 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData36], + data: make([]byte, 35), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_36", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData36], + data: make([]byte, 36), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_36 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData36], + data: make([]byte, 37), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_37 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData37], + data: make([]byte, 36), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_37", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData37], + data: make([]byte, 37), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_37 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData37], + data: make([]byte, 38), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_38 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData38], + data: make([]byte, 37), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_38", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData38], + data: make([]byte, 38), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_38 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData38], + data: make([]byte, 39), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_39 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData39], + data: make([]byte, 38), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_39", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData39], + data: make([]byte, 39), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_39 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData39], + data: make([]byte, 40), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_40 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData40], + data: make([]byte, 39), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_40", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData40], + data: make([]byte, 40), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_40 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData40], + data: make([]byte, 41), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_41 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData41], + data: make([]byte, 40), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_41", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData41], + data: make([]byte, 41), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_41 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData41], + data: make([]byte, 42), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_42 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData42], + data: make([]byte, 41), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_42", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData42], + data: make([]byte, 42), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_42 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData42], + data: make([]byte, 43), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_43 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData43], + data: make([]byte, 42), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_43", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData43], + data: make([]byte, 43), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_43 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData43], + data: make([]byte, 44), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_44 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData44], + data: make([]byte, 43), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_44", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData44], + data: make([]byte, 44), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_44 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData44], + data: make([]byte, 45), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_45 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData45], + data: make([]byte, 44), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_45", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData45], + data: make([]byte, 45), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_45 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData45], + data: make([]byte, 46), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_46 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData46], + data: make([]byte, 45), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_46", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData46], + data: make([]byte, 46), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_46 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData46], + data: make([]byte, 47), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_47 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData47], + data: make([]byte, 46), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_47", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData47], + data: make([]byte, 47), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_47 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData47], + data: make([]byte, 48), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_48 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData48], + data: make([]byte, 47), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_48", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData48], + data: make([]byte, 48), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_48 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData48], + data: make([]byte, 49), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_49 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData49], + data: make([]byte, 48), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_49", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData49], + data: make([]byte, 49), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_49 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData49], + data: make([]byte, 50), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_50 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData50], + data: make([]byte, 49), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_50", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData50], + data: make([]byte, 50), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_50 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData50], + data: make([]byte, 51), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_51 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData51], + data: make([]byte, 50), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_51", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData51], + data: make([]byte, 51), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_51 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData51], + data: make([]byte, 52), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_52 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData52], + data: make([]byte, 51), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_52", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData52], + data: make([]byte, 52), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_52 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData52], + data: make([]byte, 53), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_53 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData53], + data: make([]byte, 52), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_53", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData53], + data: make([]byte, 53), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_53 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData53], + data: make([]byte, 54), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_54 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData54], + data: make([]byte, 53), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_54", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData54], + data: make([]byte, 54), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_54 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData54], + data: make([]byte, 55), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_55 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData55], + data: make([]byte, 54), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_55", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData55], + data: make([]byte, 55), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_55 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData55], + data: make([]byte, 56), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_56 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData56], + data: make([]byte, 55), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_56", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData56], + data: make([]byte, 56), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_56 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData56], + data: make([]byte, 57), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_57 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData57], + data: make([]byte, 56), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_57", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData57], + data: make([]byte, 57), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_57 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData57], + data: make([]byte, 58), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_58 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData58], + data: make([]byte, 57), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_58", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData58], + data: make([]byte, 58), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_58 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData58], + data: make([]byte, 59), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_59 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData59], + data: make([]byte, 58), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_59", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData59], + data: make([]byte, 59), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_59 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData59], + data: make([]byte, 60), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_60 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData60], + data: make([]byte, 59), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_60", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData60], + data: make([]byte, 60), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_60 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData60], + data: make([]byte, 61), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_61 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData61], + data: make([]byte, 60), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_61", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData61], + data: make([]byte, 61), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_61 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData61], + data: make([]byte, 62), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_62 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData62], + data: make([]byte, 61), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_62", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData62], + data: make([]byte, 62), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_62 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData62], + data: make([]byte, 63), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_63 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData63], + data: make([]byte, 62), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_63", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData63], + data: make([]byte, 63), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_63 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData63], + data: make([]byte, 64), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_64 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData64], + data: make([]byte, 63), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_64", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData64], + data: make([]byte, 64), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_64 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData64], + data: make([]byte, 65), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_65 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData65], + data: make([]byte, 64), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_65", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData65], + data: make([]byte, 65), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_65 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData65], + data: make([]byte, 66), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_66 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData66], + data: make([]byte, 65), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_66", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData66], + data: make([]byte, 66), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_66 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData66], + data: make([]byte, 67), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_67 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData67], + data: make([]byte, 66), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_67", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData67], + data: make([]byte, 67), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_67 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData67], + data: make([]byte, 68), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_68 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData68], + data: make([]byte, 67), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_68", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData68], + data: make([]byte, 68), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_68 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData68], + data: make([]byte, 69), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_69 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData69], + data: make([]byte, 68), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_69", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData69], + data: make([]byte, 69), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_69 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData69], + data: make([]byte, 70), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_70 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData70], + data: make([]byte, 69), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_70", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData70], + data: make([]byte, 70), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_70 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData70], + data: make([]byte, 71), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_71 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData71], + data: make([]byte, 70), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_71", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData71], + data: make([]byte, 71), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_71 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData71], + data: make([]byte, 72), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_72 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData72], + data: make([]byte, 71), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_72", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData72], + data: make([]byte, 72), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_72 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData72], + data: make([]byte, 73), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_73 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData73], + data: make([]byte, 72), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_73", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData73], + data: make([]byte, 73), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_73 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData73], + data: make([]byte, 74), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_74 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData74], + data: make([]byte, 73), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_74", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData74], + data: make([]byte, 74), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_74 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData74], + data: make([]byte, 75), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_75 short", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData75], + data: make([]byte, 74), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DATA_75", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData75], + data: make([]byte, 75), + }, + expectedErr: nil, + }, + { + name: "OP_DATA_75 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpData75], + data: make([]byte, 76), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_PUSHDATA1", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPushData1], + data: []byte{0, 1, 2, 3, 4}, + }, + expectedErr: nil, + }, + { + name: "OP_PUSHDATA2", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPushData2], + data: []byte{0, 1, 2, 3, 4}, + }, + expectedErr: nil, + }, + { + name: "OP_PUSHDATA4", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPushData1], + data: []byte{0, 1, 2, 3, 4}, + }, + expectedErr: nil, + }, + { + name: "OP_1NEGATE", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op1Negate], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_1NEGATE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op1Negate], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RESERVED", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReserved], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RESERVED long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReserved], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_TRUE", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpTrue], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_TRUE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpTrue], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_3", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op3], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_3 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op3], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_4", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op4], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_4 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op4], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_5", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op5], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_5 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op5], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_6", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op6], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_6 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op6], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_7", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op7], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_7 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op7], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_8", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op8], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_8 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op8], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_9", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op9], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_9 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op9], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_10", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op10], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_10 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op10], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_11", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op11], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_11 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op11], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_12", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op12], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_12 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op12], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_13", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op13], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_13 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op13], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_14", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op14], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_14 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op14], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_15", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op15], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_15 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op15], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_16", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op16], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_16 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op16], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_VER", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVer], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VER long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVer], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_IF", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpIf], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_IF long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpIf], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOTIF", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNotIf], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOTIF long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNotIf], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_VERIF", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVerIf], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VERIF long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVerIf], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_VERNOTIF", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVerNotIf], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VERNOTIF long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVerNotIf], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_ELSE", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpElse], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ELSE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpElse], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_ENDIF", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpEndIf], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ENDIF long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpEndIf], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_VERIFY", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVerify], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_VERIFY long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpVerify], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RETURN", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReturn], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RETURN long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReturn], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_TOALTSTACK", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpToAltStack], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_TOALTSTACK long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpToAltStack], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_FROMALTSTACK", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpFromAltStack], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_FROMALTSTACK long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpFromAltStack], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2DROP", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Drop], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2DROP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Drop], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2DUP", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Dup], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2DUP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Dup], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_3DUP", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op3Dup], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_3DUP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op3Dup], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2OVER", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Over], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2OVER long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Over], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2ROT", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Rot], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2ROT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Rot], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2SWAP", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Swap], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2SWAP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Swap], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_IFDUP", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpIfDup], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_IFDUP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpIfDup], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DEPTH", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDepth], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DEPTH long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDepth], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DROP", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDrop], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DROP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDrop], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DUP", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDup], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DUP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDup], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NIP", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNip], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NIP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNip], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_OVER", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpOver], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_OVER long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpOver], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_PICK", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPick], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_PICK long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPick], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_ROLL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRoll], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ROLL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRoll], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_ROT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRot], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ROT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRot], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_SWAP", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSwap], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SWAP long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSwap], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_TUCK", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpTuck], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_TUCK long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpTuck], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_CAT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCat], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CAT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCat], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_SUBSTR", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSubStr], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SUBSTR long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSubStr], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_LEFT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLeft], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LEFT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLeft], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_LEFT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLeft], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LEFT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLeft], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RIGHT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRight], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RIGHT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRight], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_SIZE", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSize], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SIZE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSize], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_INVERT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpInvert], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_INVERT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpInvert], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_AND", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpAnd], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_AND long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpAnd], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_OR", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpOr], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_OR long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpOr], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_XOR", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpXor], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_XOR long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpXor], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_EQUAL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpEqual], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_EQUAL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpEqual], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_EQUALVERIFY", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpEqualVerify], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_EQUALVERIFY long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpEqualVerify], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RESERVED1", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReserved1], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RESERVED1 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReserved1], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RESERVED2", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReserved2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RESERVED2 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpReserved2], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_1ADD", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op1Add], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_1ADD long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op1Add], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_1SUB", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op1Sub], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_1SUB long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op1Sub], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2MUL", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Mul], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2MUL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Mul], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_2DIV", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Div], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_2DIV long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op2Div], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NEGATE", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNegate], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NEGATE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNegate], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_ABS", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpAbs], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ABS long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpAbs], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNot], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNot], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_0NOTEQUAL", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op0NotEqual], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_0NOTEQUAL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[Op0NotEqual], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_ADD", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpAdd], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_ADD long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpAdd], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_SUB", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSub], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SUB long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSub], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_MUL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMul], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MUL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMul], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_DIV", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDiv], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_DIV long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpDiv], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_MOD", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMod], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MOD long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMod], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_LSHIFT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLShift], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LSHIFT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLShift], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RSHIFT", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRShift], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RSHIFT long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRShift], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_BOOLAND", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpBoolAnd], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_BOOLAND long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpBoolAnd], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_BOOLOR", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpBoolOr], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_BOOLOR long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpBoolOr], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NUMEQUAL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNumEqual], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NUMEQUAL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNumEqual], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NUMEQUALVERIFY", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNumEqualVerify], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NUMEQUALVERIFY long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNumEqualVerify], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NUMNOTEQUAL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNumNotEqual], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NUMNOTEQUAL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNumNotEqual], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_LESSTHAN", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLessThan], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LESSTHAN long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLessThan], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_GREATERTHAN", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpGreaterThan], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_GREATERTHAN long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpGreaterThan], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_LESSTHANOREQUAL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLessThanOrEqual], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_LESSTHANOREQUAL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpLessThanOrEqual], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_GREATERTHANOREQUAL", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpGreaterThanOrEqual], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_GREATERTHANOREQUAL long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpGreaterThanOrEqual], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_MIN", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMin], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MIN long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMin], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_MAX", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMax], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_MAX long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpMax], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_WITHIN", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpWithin], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_WITHIN long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpWithin], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_RIPEMD160", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRipeMD160], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_RIPEMD160 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpRipeMD160], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_SHA1", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSHA1], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SHA1 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSHA1], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_SHA256", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSHA256], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_SHA256 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpSHA256], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_HASH160", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpHash160], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_HASH160 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpHash160], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_HASH256", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpHash256], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_HASH256 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpHash256], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_CHECKSIG", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckSig], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKSIG long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckSig], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_CHECKSIGVERIFY", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckSigVerify], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKSIGVERIFY long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckSigVerify], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_CHECKMULTISIG", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckMultiSig], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKMULTISIG long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckMultiSig], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_CHECKMULTISIGVERIFY", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckMultiSigVerify], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_CHECKMULTISIGVERIFY long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpCheckMultiSigVerify], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP1", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop1], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP1 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop1], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP2", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop2], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP2 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop2], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP3", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop3], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP3 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop3], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP4", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop4], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP4 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop4], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP5", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop5], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP5 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop5], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP6", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop6], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP6 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop6], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP7", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop7], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP7 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop7], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP8", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop8], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP8 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop8], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP9", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop9], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP9 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop9], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_NOP10", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop10], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_NOP10 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpNop10], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_PUBKEYHASH", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPubKeyHash], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_PUBKEYHASH long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPubKeyHash], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_PUBKEY", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPubKey], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_PUBKEY long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpPubKey], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + { + name: "OP_INVALIDOPCODE", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpInvalidOpCode], + data: nil, + }, + expectedErr: nil, + }, + { + name: "OP_INVALIDOPCODE long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OpInvalidOpCode], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, + } + + for _, test := range tests { + _, err := test.pop.bytes() + if e := checkScriptError(err, test.expectedErr); e != nil { + t.Errorf("Parsed opcode test '%s': %v", test.name, e) + continue + } + } +} + +// TestPushedData ensured the PushedData function extracts the expected data out +// of various scripts. +func TestPushedData(t *testing.T) { + t.Parallel() + + var tests = []struct { + script string + out [][]byte + valid bool + }{ + { + "0 IF 0 ELSE 2 ENDIF", + [][]byte{nil, nil}, + true, + }, + { + "16777216 10000000", + [][]byte{ + {0x00, 0x00, 0x00, 0x01}, // 16777216 + {0x80, 0x96, 0x98, 0x00}, // 10000000 + }, + true, + }, + { + "DUP HASH160 '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem' EQUALVERIFY CHECKSIG", + [][]byte{ + // 17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem + { + 0x31, 0x37, 0x56, 0x5a, 0x4e, 0x58, 0x31, 0x53, 0x4e, 0x35, + 0x4e, 0x74, 0x4b, 0x61, 0x38, 0x55, 0x51, 0x46, 0x78, 0x77, + 0x51, 0x62, 0x46, 0x65, 0x46, 0x63, 0x33, 0x69, 0x71, 0x52, + 0x59, 0x68, 0x65, 0x6d, + }, + }, + true, + }, + { + "PUSHDATA4 1000 EQUAL", + nil, + false, + }, + } + + for i, test := range tests { + script := mustParseShortForm(test.script) + data, err := PushedData(script) + if test.valid && err != nil { + t.Errorf("TestPushedData failed test #%d: %v\n", i, err) + continue + } else if !test.valid && err == nil { + t.Errorf("TestPushedData failed test #%d: test should "+ + "be invalid\n", i) + continue + } + if !reflect.DeepEqual(data, test.out) { + t.Errorf("TestPushedData failed test #%d: want: %x "+ + "got: %x\n", i, test.out, data) + } + } +} + +// TestHasCanonicalPush ensures the canonicalPush function works as expected. +func TestHasCanonicalPush(t *testing.T) { + t.Parallel() + + for i := 0; i < 65535; i++ { + script, err := NewScriptBuilder().AddInt64(int64(i)).Script() + if err != nil { + t.Errorf("Script: test #%d unexpected error: %v\n", i, + err) + continue + } + if result, _ := IsPushOnlyScript(script); !result { + t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i, + script) + continue + } + pops, err := parseScript(script) + if err != nil { + t.Errorf("parseScript: #%d failed: %v", i, err) + continue + } + for _, pop := range pops { + if result := canonicalPush(pop); !result { + t.Errorf("canonicalPush: test #%d failed: %x\n", + i, script) + break + } + } + } + for i := 0; i <= MaxScriptElementSize; i++ { + builder := NewScriptBuilder() + builder.AddData(bytes.Repeat([]byte{0x49}, i)) + script, err := builder.Script() + if err != nil { + t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err) + continue + } + if result, _ := IsPushOnlyScript(script); !result { + t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script) + continue + } + pops, err := parseScript(script) + if err != nil { + t.Errorf("StandardPushesTests #%d failed to TstParseScript: %v", i, err) + continue + } + for _, pop := range pops { + if result := canonicalPush(pop); !result { + t.Errorf("StandardPushesTests TstHasCanonicalPushes test #%d failed: %x\n", i, script) + break + } + } + } +} + +// TestGetPreciseSigOps ensures the more precise signature operation counting +// mechanism which includes signatures in P2SH scripts works as expected. +func TestGetPreciseSigOps(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + scriptSig []byte + nSigOps int + }{ + { + name: "scriptSig doesn't parse", + scriptSig: mustParseShortForm("PUSHDATA1 0x02"), + }, + { + name: "scriptSig isn't push only", + scriptSig: mustParseShortForm("1 DUP"), + nSigOps: 0, + }, + { + name: "scriptSig length 0", + scriptSig: nil, + nSigOps: 0, + }, + { + name: "No script at the end", + // No script at end but still push only. + scriptSig: mustParseShortForm("1 1"), + nSigOps: 0, + }, + { + name: "pushed script doesn't parse", + scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02"), + }, + } + + // The signature in the p2sh script is nonsensical for the tests since + // this script will never be executed. What matters is that it matches + // the right pattern. + scriptPubKey := mustParseShortForm("HASH160 DATA_20 0x433ec2ac1ffa1b7b7d0" + + "27f564529c57197f9ae88 EQUAL") + for _, test := range tests { + count := GetPreciseSigOpCount(test.scriptSig, scriptPubKey, true) + if count != test.nSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nSigOps, count) + + } + } +} + +// TestIsPayToScriptHash ensures the IsPayToScriptHash function returns the +// expected results for all the scripts in scriptClassTests. +func TestIsPayToScriptHash(t *testing.T) { + t.Parallel() + + for _, test := range scriptClassTests { + script := mustParseShortForm(test.script) + shouldBe := (test.class == ScriptHashTy) + p2sh := IsPayToScriptHash(script) + if p2sh != shouldBe { + t.Errorf("%s: expected p2sh %v, got %v", test.name, + shouldBe, p2sh) + } + } +} + +// TestHasCanonicalPushes ensures the canonicalPush function properly determines +// what is considered a canonical push. +func TestHasCanonicalPushes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + script string + expected bool + }{ + { + name: "does not parse", + script: "0x046708afdb0fe5548271967f1a67130b7105cd6a82" + + "8e03909a67962e0ea1f61d", + expected: false, + }, + { + name: "non-canonical push", + script: "PUSHDATA1 0x04 0x01020304", + expected: false, + }, + } + + for i, test := range tests { + script := mustParseShortForm(test.script) + pops, err := parseScript(script) + if err != nil { + if test.expected { + t.Errorf("TstParseScript #%d failed: %v", i, err) + } + continue + } + for _, pop := range pops { + if canonicalPush(pop) != test.expected { + t.Errorf("canonicalPush: #%d (%s) wrong result"+ + "\ngot: %v\nwant: %v", i, test.name, + true, test.expected) + break + } + } + } +} + +// TestIsPushOnlyScript ensures the IsPushOnlyScript function returns the +// expected results. +func TestIsPushOnlyScript(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + script []byte + expectedResult bool + shouldFail bool + }{ + { + name: "does not parse", + script: mustParseShortForm("0x046708afdb0fe5548271967f1a67130" + + "b7105cd6a828e03909a67962e0ea1f61d"), + expectedResult: false, + shouldFail: true, + }, + { + name: "non push only script", + script: mustParseShortForm("0x515293"), //OP_1 OP_2 OP_ADD + expectedResult: false, + shouldFail: false, + }, + { + name: "push only script", + script: mustParseShortForm("0x5152"), //OP_1 OP_2 + expectedResult: true, + shouldFail: false, + }, + } + + for _, test := range tests { + isPushOnly, err := IsPushOnlyScript(test.script) + + if isPushOnly != test.expectedResult { + t.Errorf("IsPushOnlyScript (%s) wrong result\ngot: %v\nwant: "+ + "%v", test.name, isPushOnly, test.expectedResult) + } + + if test.shouldFail && err == nil { + t.Errorf("IsPushOnlyScript (%s) expected an error but got ", test.name) + } + + if !test.shouldFail && err != nil { + t.Errorf("IsPushOnlyScript (%s) expected no error but got: %v", test.name, err) + } + } +} + +// TestIsUnspendable ensures the IsUnspendable function returns the expected +// results. +func TestIsUnspendable(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + scriptPubKey []byte + expected bool + }{ + { + // Unspendable + scriptPubKey: []byte{0x6a, 0x04, 0x74, 0x65, 0x73, 0x74}, + expected: true, + }, + { + // Spendable + scriptPubKey: []byte{0x76, 0xa9, 0x14, 0x29, 0x95, 0xa0, + 0xfe, 0x68, 0x43, 0xfa, 0x9b, 0x95, 0x45, + 0x97, 0xf0, 0xdc, 0xa7, 0xa4, 0x4d, 0xf6, + 0xfa, 0x0b, 0x5c, 0x88, 0xac}, + expected: false, + }, + } + + for i, test := range tests { + res := IsUnspendable(test.scriptPubKey) + if res != test.expected { + t.Errorf("TestIsUnspendable #%d failed: got %v want %v", + i, res, test.expected) + continue + } + } +} diff --git a/domain/consensus/utils/txscript/sign_test.go b/domain/consensus/utils/txscript/sign_test.go new file mode 100644 index 000000000..32c438320 --- /dev/null +++ b/domain/consensus/utils/txscript/sign_test.go @@ -0,0 +1,1101 @@ +// Copyright (c) 2013-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package txscript + +import ( + "fmt" + "testing" + + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" + + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util" +) + +type addressToKey struct { + key *secp256k1.PrivateKey + compressed bool +} + +func mkGetKey(keys map[string]addressToKey) KeyDB { + if keys == nil { + return KeyClosure(func(addr util.Address) (*secp256k1.PrivateKey, + bool, error) { + return nil, false, errors.New("nope") + }) + } + return KeyClosure(func(addr util.Address) (*secp256k1.PrivateKey, + bool, error) { + a2k, ok := keys[addr.EncodeAddress()] + if !ok { + return nil, false, errors.New("nope") + } + return a2k.key, a2k.compressed, nil + }) +} + +func mkGetScript(scripts map[string][]byte) ScriptDB { + if scripts == nil { + return ScriptClosure(func(addr util.Address) ([]byte, error) { + return nil, errors.New("nope") + }) + } + return ScriptClosure(func(addr util.Address) ([]byte, error) { + script, ok := scripts[addr.EncodeAddress()] + if !ok { + return nil, errors.New("nope") + } + return script, nil + }) +} + +func checkScripts(msg string, tx *externalapi.DomainTransaction, idx int, sigScript, scriptPubKey []byte) error { + tx.Inputs[idx].SignatureScript = sigScript + var flags ScriptFlags + vm, err := NewEngine(scriptPubKey, tx, idx, + flags, nil) + if err != nil { + return errors.Errorf("failed to make script engine for %s: %v", + msg, err) + } + + err = vm.Execute() + if err != nil { + return errors.Errorf("invalid script signature for %s: %v", msg, + err) + } + + return nil +} + +func signAndCheck(msg string, tx *externalapi.DomainTransaction, idx int, scriptPubKey []byte, + hashType SigHashType, kdb KeyDB, sdb ScriptDB, + previousScript []byte) error { + + sigScript, err := SignTxOutput(&dagconfig.TestnetParams, tx, idx, + scriptPubKey, hashType, kdb, sdb, nil) + if err != nil { + return errors.Errorf("failed to sign output %s: %v", msg, err) + } + + return checkScripts(msg, tx, idx, sigScript, scriptPubKey) +} + +func TestSignTxOutput(t *testing.T) { + t.Parallel() + + // make key + // make script based on key. + // sign with magic pixie dust. + hashTypes := []SigHashType{ + SigHashAll, + SigHashNone, + SigHashSingle, + SigHashAll | SigHashAnyOneCanPay, + SigHashNone | SigHashAnyOneCanPay, + SigHashSingle | SigHashAnyOneCanPay, + } + inputs := []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: 0, + }, + Sequence: 4294967295, + }, + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: 1, + }, + Sequence: 4294967295, + }, + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: 2, + }, + Sequence: 4294967295, + }, + } + outputs := []*externalapi.DomainTransactionOutput{ + { + Value: 1, + }, + { + Value: 2, + }, + { + Value: 3, + }, + } + tx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: inputs, + Outputs: outputs, + } + + // Pay to Pubkey Hash (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + } + + if err := signAndCheck(msg, tx, i, scriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), nil); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (uncompressed) (merging with correct) + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + address, err := util.NewAddressPubKeyHash( + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + } + + sigScript, err := SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), nil) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(nil), sigScript) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptPubKey) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + } + + if err := signAndCheck(msg, tx, i, scriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), nil); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + } + + sigScript, err := SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), nil) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err = SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(nil), sigScript) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptPubKey) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // As before, but with p2sh now. + // Pay to Pubkey Hash (uncompressed) + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + break + } + + scriptAddr, err := util.NewAddressScriptHash( + scriptPubKey, util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptScriptPubKey, err := PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script scriptPubKey for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptScriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): scriptPubKey, + }), nil); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (uncompressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + uncompressedPubKey, err := pubKey.SerializeUncompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + break + } + + scriptAddr, err := util.NewAddressScriptHash( + scriptPubKey, util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptScriptPubKey, err := PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script scriptPubKey for "+ + "%s: %v", msg, err) + break + } + + _, err = SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptScriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): scriptPubKey, + }), nil) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err := SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptScriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, false}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): scriptPubKey, + }), nil) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptScriptPubKey) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := util.NewAddressScriptHash( + scriptPubKey, util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptScriptPubKey, err := PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script scriptPubKey for "+ + "%s: %v", msg, err) + break + } + + if err := signAndCheck(msg, tx, i, scriptScriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): scriptPubKey, + }), nil); err != nil { + t.Error(err) + break + } + } + } + + // Pay to Pubkey Hash (compressed) with duplicate merge + for _, hashType := range hashTypes { + for i := range tx.Inputs { + msg := fmt.Sprintf("%d:%d", hashType, i) + + key, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Errorf("failed to make privKey for %s: %s", + msg, err) + break + } + + pubKey, err := key.SchnorrPublicKey() + if err != nil { + t.Errorf("failed to make a publickey for %s: %s", + key, err) + break + } + + compressedPubKey, err := pubKey.SerializeCompressed() + if err != nil { + t.Errorf("failed to make a pubkey for %s: %s", + key, err) + break + } + + address, err := util.NewAddressPubKeyHash( + util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make address for %s: %v", + msg, err) + break + } + + scriptPubKey, err := PayToAddrScript(address) + if err != nil { + t.Errorf("failed to make scriptPubKey "+ + "for %s: %v", msg, err) + } + + scriptAddr, err := util.NewAddressScriptHash( + scriptPubKey, util.Bech32PrefixKaspaTest) + if err != nil { + t.Errorf("failed to make p2sh addr for %s: %v", + msg, err) + break + } + + scriptScriptPubKey, err := PayToAddrScript( + scriptAddr) + if err != nil { + t.Errorf("failed to make script scriptPubKey for "+ + "%s: %v", msg, err) + break + } + + _, err = SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptScriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): scriptPubKey, + }), nil) + if err != nil { + t.Errorf("failed to sign output %s: %v", msg, + err) + break + } + + // by the above loop, this should be valid, now sign + // again and merge. + sigScript, err := SignTxOutput(&dagconfig.TestnetParams, + tx, i, scriptScriptPubKey, hashType, + mkGetKey(map[string]addressToKey{ + address.EncodeAddress(): {key, true}, + }), mkGetScript(map[string][]byte{ + scriptAddr.EncodeAddress(): scriptPubKey, + }), nil) + if err != nil { + t.Errorf("failed to sign output %s a "+ + "second time: %v", msg, err) + break + } + + err = checkScripts(msg, tx, i, sigScript, scriptScriptPubKey) + if err != nil { + t.Errorf("twice signed script invalid for "+ + "%s: %v", msg, err) + break + } + } + } +} + +type tstInput struct { + txout *externalapi.DomainTransactionOutput + sigscriptGenerates bool + inputValidates bool + indexOutOfRange bool +} + +type tstSigScript struct { + name string + inputs []tstInput + hashType SigHashType + compress bool + scriptAtWrongIndex bool +} + +var coinbaseOutpoint = &externalapi.DomainOutpoint{ + Index: (1 << 32) - 1, +} + +// Pregenerated private key, with associated public key and scriptPubKeys +// for the uncompressed and compressed hash160. +var ( + privKeyD = secp256k1.SerializedPrivateKey{0x6b, 0x0f, 0xd8, 0xda, 0x54, 0x22, 0xd0, 0xb7, + 0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65, + 0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, + 0xd6, 0x0e, 0x06, 0x92} + uncompressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, + 0x53, 0x90, 0x0e, 0x0a, 0x86, 0xc9, 0xfa, 0x88, 0xac} + compressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, + 0x61, 0x7e, 0x7c, 0x7a, 0x1c, 0x1f, 0xb2, 0x75, 0x79, 0x10, + 0x43, 0x65, 0x68, 0x27, 0x9d, 0x86, 0x88, 0xac} + shortScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, + 0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac} +) + +// Pretend output amounts. +const coinbaseVal = 2500000000 +const fee = 5000000 + +var sigScriptTests = []tstSigScript{ + { + name: "one input uncompressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "two inputs uncompressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal + fee, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "one input compressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: compressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: true, + scriptAtWrongIndex: false, + }, + { + name: "two inputs compressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: compressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal + fee, + ScriptPublicKey: compressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: true, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashNone", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashNone, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashSingle", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashSingle, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashAll | SigHashAnyoneCanPay", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll | SigHashAnyOneCanPay, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType SigHashAnyoneCanPay", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAnyOneCanPay, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "hashType non-exist", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: 0x04, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "invalid compression", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: true, + scriptAtWrongIndex: false, + }, + { + name: "short ScriptPubKey", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: shortScriptPubKey, + }, + sigscriptGenerates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: false, + scriptAtWrongIndex: false, + }, + { + name: "valid script at wrong index", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal + fee, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: false, + scriptAtWrongIndex: true, + }, + { + name: "index out of range", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal + fee, + ScriptPublicKey: uncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: true, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + compress: false, + scriptAtWrongIndex: true, + }, +} + +// Test the sigscript generation for valid and invalid inputs, all +// hashTypes, and with and without compression. This test creates +// sigscripts to spend fake coinbase inputs, as sigscripts cannot be +// created for the DomainTransactions in txTests, since they come from the blockDAG +// and we don't have the private keys. +func TestSignatureScript(t *testing.T) { + t.Parallel() + + privKey, _ := secp256k1.DeserializePrivateKey(&privKeyD) + +nexttest: + for i := range sigScriptTests { + outputs := []*externalapi.DomainTransactionOutput{ + {Value: 500, ScriptPublicKey: []byte{OpReturn}}, + } + + inputs := []*externalapi.DomainTransactionInput{} + for range sigScriptTests[i].inputs { + inputs = append(inputs, &externalapi.DomainTransactionInput{ + PreviousOutpoint: *coinbaseOutpoint, + }) + } + tx := &externalapi.DomainTransaction{ + Version: 1, + Inputs: inputs, + Outputs: outputs, + } + + var script []byte + var err error + for j := range tx.Inputs { + var idx int + if sigScriptTests[i].inputs[j].indexOutOfRange { + t.Errorf("at test %v", sigScriptTests[i].name) + idx = len(sigScriptTests[i].inputs) + } else { + idx = j + } + script, err = SignatureScript(tx, idx, + sigScriptTests[i].inputs[j].txout.ScriptPublicKey, + sigScriptTests[i].hashType, privKey, + sigScriptTests[i].compress) + + if (err == nil) != sigScriptTests[i].inputs[j].sigscriptGenerates { + if err == nil { + t.Errorf("passed test '%v' incorrectly", + sigScriptTests[i].name) + } else { + t.Errorf("failed test '%v': %v", + sigScriptTests[i].name, err) + } + continue nexttest + } + if !sigScriptTests[i].inputs[j].sigscriptGenerates { + // done with this test + continue nexttest + } + + tx.Inputs[j].SignatureScript = script + } + + // If testing using a correct sigscript but for an incorrect + // index, use last input script for first input. Requires > 0 + // inputs for test. + if sigScriptTests[i].scriptAtWrongIndex { + tx.Inputs[0].SignatureScript = script + sigScriptTests[i].inputs[0].inputValidates = false + } + + // Validate tx input scripts + var scriptFlags ScriptFlags + for j := range tx.Inputs { + vm, err := NewEngine(sigScriptTests[i]. + inputs[j].txout.ScriptPublicKey, tx, j, scriptFlags, nil) + if err != nil { + t.Errorf("cannot create script vm for test %v: %v", + sigScriptTests[i].name, err) + continue nexttest + } + err = vm.Execute() + if (err == nil) != sigScriptTests[i].inputs[j].inputValidates { + if err == nil { + t.Errorf("passed test '%v' validation incorrectly: %v", + sigScriptTests[i].name, err) + } else { + t.Errorf("failed test '%v' validation: %v", + sigScriptTests[i].name, err) + } + continue nexttest + } + } + } +} diff --git a/domain/consensus/utils/txscript/standard_test.go b/domain/consensus/utils/txscript/standard_test.go new file mode 100644 index 000000000..8e19a3e91 --- /dev/null +++ b/domain/consensus/utils/txscript/standard_test.go @@ -0,0 +1,506 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package txscript + +import ( + "bytes" + "reflect" + "testing" + + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util" +) + +// mustParseShortForm parses the passed short form script and returns the +// resulting bytes. It panics if an error occurs. This is only used in the +// tests as a helper since the only way it can fail is if there is an error in +// the test source code. +func mustParseShortForm(script string) []byte { + s, err := parseShortForm(script) + if err != nil { + panic("invalid short form script in test source: err " + + err.Error() + ", script: " + script) + } + + return s +} + +// newAddressPubKeyHash returns a new util.AddressPubKeyHash from the +// provided hash. It panics if an error occurs. This is only used in the tests +// as a helper since the only way it can fail is if there is an error in the +// test source code. +func newAddressPubKeyHash(pkHash []byte) util.Address { + addr, err := util.NewAddressPubKeyHash(pkHash, util.Bech32PrefixKaspa) + if err != nil { + panic("invalid public key hash in test source") + } + + return addr +} + +// newAddressScriptHash returns a new util.AddressScriptHash from the +// provided hash. It panics if an error occurs. This is only used in the tests +// as a helper since the only way it can fail is if there is an error in the +// test source code. +func newAddressScriptHash(scriptHash []byte) util.Address { + addr, err := util.NewAddressScriptHashFromHash(scriptHash, + util.Bech32PrefixKaspa) + if err != nil { + panic("invalid script hash in test source") + } + + return addr +} + +// TestExtractScriptPubKeyAddrs ensures that extracting the type, addresses, and +// number of required signatures from scriptPubKeys works as intended. +func TestExtractScriptPubKeyAddrs(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + script []byte + addr util.Address + class ScriptClass + }{ + { + name: "standard p2pkh", + script: hexToBytes("76a914ad06dd6ddee55cbca9a9e3713bd" + + "7587509a3056488ac"), + addr: newAddressPubKeyHash(hexToBytes("ad06dd6ddee5" + + "5cbca9a9e3713bd7587509a30564")), + class: PubKeyHashTy, + }, + { + name: "standard p2sh", + script: hexToBytes("a91463bcc565f9e68ee0189dd5cc67f1b" + + "0e5f02f45cb87"), + addr: newAddressScriptHash(hexToBytes("63bcc565f9e6" + + "8ee0189dd5cc67f1b0e5f02f45cb")), + class: ScriptHashTy, + }, + + // The below are nonstandard script due to things such as + // invalid pubkeys, failure to parse, and not being of a + // standard form. + + { + name: "p2pk with uncompressed pk missing OP_CHECKSIG", + script: hexToBytes("410411db93e1dcdb8a016b49840f8c53b" + + "c1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddf" + + "b84ccf9744464f82e160bfa9b8b64f9d4c03f999b864" + + "3f656b412a3"), + addr: nil, + class: NonStandardTy, + }, + { + name: "valid signature from a sigscript - no addresses", + script: hexToBytes("47304402204e45e16932b8af514961a1d" + + "3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41022" + + "0181522ec8eca07de4860a4acdd12909d831cc56cbba" + + "c4622082221a8768d1d0901"), + addr: nil, + class: NonStandardTy, + }, + // Note the technically the pubkey is the second item on the + // stack, but since the address extraction intentionally only + // works with standard scriptPubKeys, this should not return any + // addresses. + { + name: "valid sigscript to reedeem p2pk - no addresses", + script: hexToBytes("493046022100ddc69738bf2336318e4e0" + + "41a5a77f305da87428ab1606f023260017854350ddc0" + + "22100817af09d2eec36862d16009852b7e3a0f6dd765" + + "98290b7834e1453660367e07a014104cd4240c198e12" + + "523b6f9cb9f5bed06de1ba37e96a1bbd13745fcf9d11" + + "c25b1dff9a519675d198804ba9962d3eca2d5937d58e" + + "5a75a71042d40388a4d307f887d"), + addr: nil, + class: NonStandardTy, + }, + { + name: "empty script", + script: []byte{}, + addr: nil, + class: NonStandardTy, + }, + { + name: "script that does not parse", + script: []byte{OpData45}, + addr: nil, + class: NonStandardTy, + }, + } + + t.Logf("Running %d tests.", len(tests)) + for i, test := range tests { + class, addr, _ := ExtractScriptPubKeyAddress( + test.script, &dagconfig.MainnetParams) + + if !reflect.DeepEqual(addr, test.addr) { + t.Errorf("ExtractScriptPubKeyAddress #%d (%s) unexpected "+ + "address\ngot %v\nwant %v", i, test.name, + addr, test.addr) + continue + } + + if class != test.class { + t.Errorf("ExtractScriptPubKeyAddress #%d (%s) unexpected "+ + "script type - got %s, want %s", i, test.name, + class, test.class) + continue + } + } +} + +// TestCalcScriptInfo ensures the CalcScriptInfo provides the expected results +// for various valid and invalid script pairs. +func TestCalcScriptInfo(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + sigScript string + scriptPubKey string + + isP2SH bool + + scriptInfo ScriptInfo + scriptInfoErr error + }{ + { + // Invented scripts, the hashes do not match + // Truncated version of test below: + name: "scriptPubKey doesn't parse", + sigScript: "1 81 DATA_8 2DUP EQUAL NOT VERIFY ABS " + + "SWAP ABS EQUAL", + scriptPubKey: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + + "3152205ec4f59c", + isP2SH: true, + scriptInfoErr: scriptError(ErrMalformedPush, ""), + }, + { + name: "sigScript doesn't parse", + // Truncated version of p2sh script below. + sigScript: "1 81 DATA_8 2DUP EQUAL NOT VERIFY ABS " + + "SWAP ABS", + scriptPubKey: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + + "3152205ec4f59c74 EQUAL", + isP2SH: true, + scriptInfoErr: scriptError(ErrMalformedPush, ""), + }, + { + // Invented scripts, the hashes do not match + name: "p2sh standard script", + sigScript: "1 81 DATA_25 DUP HASH160 DATA_20 0x010203" + + "0405060708090a0b0c0d0e0f1011121314 EQUALVERIFY " + + "CHECKSIG", + scriptPubKey: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + + "3152205ec4f59c74 EQUAL", + isP2SH: true, + scriptInfo: ScriptInfo{ + ScriptPubKeyClass: ScriptHashTy, + NumInputs: 3, + ExpectedInputs: 3, // nonstandard p2sh. + SigOps: 1, + }, + }, + { + name: "p2sh nonstandard script", + sigScript: "1 81 DATA_8 2DUP EQUAL NOT VERIFY ABS " + + "SWAP ABS EQUAL", + scriptPubKey: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + + "3152205ec4f59c74 EQUAL", + isP2SH: true, + scriptInfo: ScriptInfo{ + ScriptPubKeyClass: ScriptHashTy, + NumInputs: 3, + ExpectedInputs: -1, // nonstandard p2sh. + SigOps: 0, + }, + }, + } + + for _, test := range tests { + sigScript := mustParseShortForm(test.sigScript) + scriptPubKey := mustParseShortForm(test.scriptPubKey) + + si, err := CalcScriptInfo(sigScript, scriptPubKey, test.isP2SH) + if e := checkScriptError(err, test.scriptInfoErr); e != nil { + t.Errorf("scriptinfo test %q: %v", test.name, e) + continue + } + if err != nil { + continue + } + + if *si != test.scriptInfo { + t.Errorf("%s: scriptinfo doesn't match expected. "+ + "got: %q expected %q", test.name, *si, + test.scriptInfo) + continue + } + } +} + +// bogusAddress implements the util.Address interface so the tests can ensure +// unsupported address types are handled properly. +type bogusAddress struct{} + +// EncodeAddress simply returns an empty string. It exists to satisfy the +// util.Address interface. +func (b *bogusAddress) EncodeAddress() string { + return "" +} + +// ScriptAddress simply returns an empty byte slice. It exists to satisfy the +// util.Address interface. +func (b *bogusAddress) ScriptAddress() []byte { + return nil +} + +// IsForPrefix lies blatantly to satisfy the util.Address interface. +func (b *bogusAddress) IsForPrefix(prefix util.Bech32Prefix) bool { + return true // why not? +} + +// String simply returns an empty string. It exists to satisfy the +// util.Address interface. +func (b *bogusAddress) String() string { + return "" +} + +func (b *bogusAddress) Prefix() util.Bech32Prefix { + return util.Bech32PrefixUnknown +} + +// TestPayToAddrScript ensures the PayToAddrScript function generates the +// correct scripts for the various types of addresses. +func TestPayToAddrScript(t *testing.T) { + t.Parallel() + + // 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX + p2pkhMain, err := util.NewAddressPubKeyHash(hexToBytes("e34cce70c86"+ + "373273efcc54ce7d2a491bb4a0e84"), util.Bech32PrefixKaspa) + if err != nil { + t.Fatalf("Unable to create public key hash address: %v", err) + } + + // Taken from transaction: + // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d + p2shMain, _ := util.NewAddressScriptHashFromHash(hexToBytes("e8c300"+ + "c87986efa84c37c0519929019ef86eb5b4"), util.Bech32PrefixKaspa) + if err != nil { + t.Fatalf("Unable to create script hash address: %v", err) + } + + // Errors used in the tests below defined here for convenience and to + // keep the horizontal test size shorter. + errUnsupportedAddress := scriptError(ErrUnsupportedAddress, "") + + tests := []struct { + in util.Address + expected string + err error + }{ + // pay-to-pubkey-hash address on mainnet + { + p2pkhMain, + "DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" + + "91bb4a0e8488 CHECKSIG", + nil, + }, + // pay-to-script-hash address on mainnet + { + p2shMain, + "HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" + + "6eb5b4 EQUAL", + nil, + }, + + // Supported address types with nil pointers. + {(*util.AddressPubKeyHash)(nil), "", errUnsupportedAddress}, + {(*util.AddressScriptHash)(nil), "", errUnsupportedAddress}, + + // Unsupported address type. + {&bogusAddress{}, "", errUnsupportedAddress}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + scriptPubKey, err := PayToAddrScript(test.in) + if e := checkScriptError(err, test.err); e != nil { + t.Errorf("PayToAddrScript #%d unexpected error - "+ + "got %v, want %v", i, err, test.err) + continue + } + + expected := mustParseShortForm(test.expected) + if !bytes.Equal(scriptPubKey, expected) { + t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", + i, scriptPubKey, expected) + continue + } + } +} + +// scriptClassTests houses several test scripts used to ensure various class +// determination is working as expected. It's defined as a test global versus +// inside a function scope since this spans both the standard tests and the +// consensus tests (pay-to-script-hash is part of consensus). +var scriptClassTests = []struct { + name string + script string + class ScriptClass +}{ + // p2pk + { + name: "Pay Pubkey", + script: "DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e" + + "97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e16" + + "0bfa9b8b64f9d4c03f999b8643f656b412a3 CHECKSIG", + class: NonStandardTy, + }, + // tx 599e47a8114fe098103663029548811d2651991b62397e057f0c863c2bc9f9ea + { + name: "Pay PubkeyHash", + script: "DUP HASH160 DATA_20 0x660d4ef3a743e3e696ad990364e555" + + "c271ad504b EQUALVERIFY CHECKSIG", + class: PubKeyHashTy, + }, + // mutlisig + { + name: "multisig", + script: "1 DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da4" + + "5329a00357b3a7886211ab414d55a 1 CHECKMULTISIG", + class: NonStandardTy, + }, + // tx e5779b9e78f9650debc2893fd9636d827b26b4ddfa6a8172fe8708c924f5c39d + { + name: "P2SH", + script: "HASH160 DATA_20 0x433ec2ac1ffa1b7b7d027f564529c57197f" + + "9ae88 EQUAL", + class: ScriptHashTy, + }, + + { + // Nulldata. It is standard in Bitcoin but not in Kaspa + name: "nulldata", + script: "RETURN 0", + class: NonStandardTy, + }, + + // The next few are almost multisig (it is the more complex script type) + // but with various changes to make it fail. + { + // Multisig but invalid nsigs. + name: "strange 1", + script: "DUP DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da45" + + "329a00357b3a7886211ab414d55a 1 CHECKMULTISIG", + class: NonStandardTy, + }, + { + // Multisig but invalid pubkey. + name: "strange 2", + script: "1 1 1 CHECKMULTISIG", + class: NonStandardTy, + }, + { + // Multisig but no matching npubkeys opcode. + name: "strange 3", + script: "1 DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da4532" + + "9a00357b3a7886211ab414d55a DATA_33 0x0232abdc893e7f0" + + "631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a " + + "CHECKMULTISIG", + class: NonStandardTy, + }, + { + // Multisig but with multisigverify. + name: "strange 4", + script: "1 DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da4532" + + "9a00357b3a7886211ab414d55a 1 CHECKMULTISIGVERIFY", + class: NonStandardTy, + }, + { + // Multisig but wrong length. + name: "strange 5", + script: "1 CHECKMULTISIG", + class: NonStandardTy, + }, + { + name: "doesn't parse", + script: "DATA_5 0x01020304", + class: NonStandardTy, + }, + { + name: "multisig script with wrong number of pubkeys", + script: "2 " + + "DATA_33 " + + "0x027adf5df7c965a2d46203c781bd4dd8" + + "21f11844136f6673af7cc5a4a05cd29380 " + + "DATA_33 " + + "0x02c08f3de8ee2de9be7bd770f4c10eb0" + + "d6ff1dd81ee96eedd3a9d4aeaf86695e80 " + + "3 CHECKMULTISIG", + class: NonStandardTy, + }, +} + +// TestScriptClass ensures all the scripts in scriptClassTests have the expected +// class. +func TestScriptClass(t *testing.T) { + t.Parallel() + + for _, test := range scriptClassTests { + script := mustParseShortForm(test.script) + class := GetScriptClass(script) + if class != test.class { + t.Errorf("%s: expected %s got %s (script %x)", test.name, + test.class, class, script) + continue + } + } +} + +// TestStringifyClass ensures the script class string returns the expected +// string for each script class. +func TestStringifyClass(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + class ScriptClass + stringed string + }{ + { + name: "nonstandardty", + class: NonStandardTy, + stringed: "nonstandard", + }, + { + name: "pubkeyhash", + class: PubKeyHashTy, + stringed: "pubkeyhash", + }, + { + name: "scripthash", + class: ScriptHashTy, + stringed: "scripthash", + }, + { + name: "broken", + class: ScriptClass(255), + stringed: "Invalid", + }, + } + + for _, test := range tests { + typeString := test.class.String() + if typeString != test.stringed { + t.Errorf("%s: got %#q, want %#q", test.name, + typeString, test.stringed) + } + } +} diff --git a/domain/miningmanager/mempool/policy_test.go b/domain/miningmanager/mempool/policy_test.go index bff5db24f..15ccc13a1 100644 --- a/domain/miningmanager/mempool/policy_test.go +++ b/domain/miningmanager/mempool/policy_test.go @@ -8,7 +8,8 @@ import ( "bytes" "testing" - "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/util" @@ -174,7 +175,7 @@ func TestCheckTransactionStandard(t *testing.T) { dummyTxIn := consensusexternalapi.DomainTransactionInput{ PreviousOutpoint: dummyPrevOut, SignatureScript: dummySigScript, - Sequence: appmessage.MaxTxInSequenceNum, + Sequence: constants.MaxTxInSequenceNum, } addrHash := [20]byte{0x01} addr, err := util.NewAddressPubKeyHash(addrHash[:], util.Bech32PrefixKaspaTest) @@ -205,7 +206,7 @@ func TestCheckTransactionStandard(t *testing.T) { }, { name: "Transaction version too high", - tx: consensusexternalapi.DomainTransaction{Version: appmessage.TxVersion + 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, + tx: consensusexternalapi.DomainTransaction{Version: constants.TransactionVersion + 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, height: 300000, isStandard: false, code: RejectNonstandard, @@ -238,7 +239,7 @@ func TestCheckTransactionStandard(t *testing.T) { PreviousOutpoint: dummyPrevOut, SignatureScript: bytes.Repeat([]byte{0x00}, maxStandardSigScriptSize+1), - Sequence: appmessage.MaxTxInSequenceNum, + Sequence: constants.MaxTxInSequenceNum, }}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, height: 300000, isStandard: false, @@ -250,7 +251,7 @@ func TestCheckTransactionStandard(t *testing.T) { PreviousOutpoint: dummyPrevOut, SignatureScript: []byte{ txscript.OpCheckSigVerify}, - Sequence: appmessage.MaxTxInSequenceNum, + Sequence: constants.MaxTxInSequenceNum, }}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, height: 300000, isStandard: false, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go index a58af0b46..09353f68c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go @@ -45,7 +45,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { return nil, err } - var payloadHash *externalapi.DomainHash + payloadHash := &externalapi.DomainHash{} if x.PayloadHash != nil { payloadHash, err = x.PayloadHash.toDomain() if err != nil { @@ -60,7 +60,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { LockTime: x.LockTime, SubnetworkID: *subnetworkID, Gas: x.Gas, - PayloadHash: payloadHash, + PayloadHash: *payloadHash, Payload: x.Payload, }, nil } @@ -86,10 +86,6 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { } } - var payloadHash *Hash - if msgTx.PayloadHash != nil { - payloadHash = domainHashToProto(msgTx.PayloadHash) - } *x = TransactionMessage{ Version: msgTx.Version, Inputs: protoInputs, @@ -97,7 +93,7 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { LockTime: msgTx.LockTime, SubnetworkID: domainSubnetworkIDToProto(&msgTx.SubnetworkID), Gas: msgTx.Gas, - PayloadHash: payloadHash, + PayloadHash: domainHashToProto(&msgTx.PayloadHash), Payload: msgTx.Payload, } From 7a7821e1c8de5e014d9b4fda4b89573e38d7b27b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 12 Nov 2020 04:40:41 -0800 Subject: [PATCH 016/351] [NOD-1313] Refactor AddressManager (#918) (#1049) * [NOD-1313] Refactor AddressManager (#918) * [NOD-1313] Refactor AddressManager. * [NOD-1313]Remove old tests.Minor improvements,fixes. * [NOD-1313] After merge fixes. Fix import cycle. * [NOD-1313] Integration tests fixes. * [NOD-1313] Allocate new slice for the returned key. * [NOD-1313] AddressManager improvements and fixes. * Move local and banned addresses to separate lists. * Move AddressManager config to the separate file. * Add LocalAddressManager. * Remove redundant KnownAddress structure. * Restore local addresses functionality. * Call initListeners from the LocalAddressManager. * AddressManager minor improvements and fixes. * [NOD-1313] Minor fixes. * [NOD-1313] Implement HandleGetPeerAddresses. Refactoring. * [NOD-1313] After-merge fixes. * [NOD-1313] Minor improvements. * AddressManager: added BannedAddresses() method. * AddressManager: HandleGetPeerAddresses() add banned addresses separately. * AddressManager: remove addressEntry redundant struct. * ConnectionManager: checkOutgoingConnections() minor improvements and fixes. * Minor refactoring. * Minor fixes. * [NOD-1313] GetPeerAddresses RPC message update * GetPeerAddresses RPC: add BannedAddresses in the separate field. * Update protobuf. * [NOD-1534] Update messages.pb.go Co-authored-by: Kirill --- app/appmessage/rpc_get_peer_addresses.go | 8 +- app/component_manager.go | 13 +- .../flows/addressexchange/receiveaddresses.go | 7 +- .../flows/addressexchange/sendaddresses.go | 6 +- app/protocol/flows/handshake/handshake.go | 4 +- app/protocol/flows/handshake/sendversion.go | 2 +- app/rpc/rpchandlers/get_peer_addresses.go | 23 +- .../network/addressmanager/addressmanager.go | 1653 ++--------------- .../addressmanager/addressmanager_test.go | 541 +----- .../addressmanager/addressrandomize.go | 43 + .../network/addressmanager/config.go | 27 + .../network/addressmanager/internal_test.go | 24 - .../network/addressmanager/knownaddress.go | 107 -- .../addressmanager/knownaddress_test.go | 115 -- .../addressmanager/localaddressmanager.go | 400 ++++ .../network/addressmanager/network.go | 16 +- .../network/addressmanager/network_test.go | 9 +- .../network/addressmanager/test_utils.go | 2 +- .../connmanager/outgoing_connections.go | 46 +- .../grpcserver/protowire/messages.pb.go | 877 ++++----- .../grpcserver/protowire/messages.proto | 1 + .../protowire/rpc_get_peer_addresses.go | 18 +- 22 files changed, 1148 insertions(+), 2794 deletions(-) create mode 100644 infrastructure/network/addressmanager/addressrandomize.go create mode 100644 infrastructure/network/addressmanager/config.go delete mode 100644 infrastructure/network/addressmanager/internal_test.go delete mode 100644 infrastructure/network/addressmanager/knownaddress.go delete mode 100644 infrastructure/network/addressmanager/knownaddress_test.go create mode 100644 infrastructure/network/addressmanager/localaddressmanager.go diff --git a/app/appmessage/rpc_get_peer_addresses.go b/app/appmessage/rpc_get_peer_addresses.go index 7ad2f7868..a026e5396 100644 --- a/app/appmessage/rpc_get_peer_addresses.go +++ b/app/appmessage/rpc_get_peer_addresses.go @@ -20,7 +20,8 @@ func NewGetPeerAddressesRequestMessage() *GetPeerAddressesRequestMessage { // its respective RPC message type GetPeerAddressesResponseMessage struct { baseMessage - Addresses []*GetPeerAddressesKnownAddressMessage + Addresses []*GetPeerAddressesKnownAddressMessage + BannedAddresses []*GetPeerAddressesKnownAddressMessage Error *RPCError } @@ -31,9 +32,10 @@ func (msg *GetPeerAddressesResponseMessage) Command() MessageCommand { } // NewGetPeerAddressesResponseMessage returns a instance of the message -func NewGetPeerAddressesResponseMessage(addresses []*GetPeerAddressesKnownAddressMessage) *GetPeerAddressesResponseMessage { +func NewGetPeerAddressesResponseMessage(addresses []*GetPeerAddressesKnownAddressMessage, bannedAddresses []*GetPeerAddressesKnownAddressMessage) *GetPeerAddressesResponseMessage { return &GetPeerAddressesResponseMessage{ - Addresses: addresses, + Addresses: addresses, + BannedAddresses: bannedAddresses, } } diff --git a/app/component_manager.go b/app/component_manager.go index 70198839b..04d9350ca 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -70,11 +70,6 @@ func (a *ComponentManager) Stop() { log.Errorf("Error stopping the net adapter: %+v", err) } - err = a.addressManager.Stop() - if err != nil { - log.Errorf("Error stopping address manager: %s", err) - } - return } @@ -92,10 +87,12 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, if err != nil { return nil, err } - addressManager, err := addressmanager.New(cfg, db) + + addressManager, err := addressmanager.New(addressmanager.NewConfig(cfg)) if err != nil { return nil, err } + connectionManager, err := connmanager.New(cfg, netAdapter, addressManager) if err != nil { return nil, err @@ -141,14 +138,14 @@ func (a *ComponentManager) maybeSeedFromDNS() { // Kaspad uses a lookup of the dns seeder here. Since seeder returns // IPs of nodes and not its own IP, we can not know real IP of // source. So we'll take first returned address as source. - a.addressManager.AddAddresses(addresses, addresses[0], nil) + a.addressManager.AddAddresses(addresses...) }) } if a.cfg.GRPCSeed != "" { dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil, func(addresses []*appmessage.NetAddress) { - a.addressManager.AddAddresses(addresses, addresses[0], nil) + a.addressManager.AddAddresses(addresses...) }) } } diff --git a/app/protocol/flows/addressexchange/receiveaddresses.go b/app/protocol/flows/addressexchange/receiveaddresses.go index 8df1fd880..5e6d7e4fc 100644 --- a/app/protocol/flows/addressexchange/receiveaddresses.go +++ b/app/protocol/flows/addressexchange/receiveaddresses.go @@ -20,10 +20,6 @@ type ReceiveAddressesContext interface { func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Route, outgoingRoute *router.Route, peer *peerpkg.Peer) error { - if !context.AddressManager().NeedMoreAddresses() { - return nil - } - subnetworkID := peer.SubnetworkID() msgGetAddresses := appmessage.NewMsgRequestAddresses(false, subnetworkID) err := outgoingRoute.Enqueue(msgGetAddresses) @@ -51,7 +47,6 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou context.Config().SubnetworkID, msgAddresses.Command(), msgAddresses.SubnetworkID) } - sourceAddress := peer.Connection().NetAddress() - context.AddressManager().AddAddresses(msgAddresses.AddrList, sourceAddress, msgAddresses.SubnetworkID) + context.AddressManager().AddAddresses(msgAddresses.AddrList...) return nil } diff --git a/app/protocol/flows/addressexchange/sendaddresses.go b/app/protocol/flows/addressexchange/sendaddresses.go index 236073406..af6cd4128 100644 --- a/app/protocol/flows/addressexchange/sendaddresses.go +++ b/app/protocol/flows/addressexchange/sendaddresses.go @@ -1,10 +1,11 @@ package addressexchange import ( + "math/rand" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" - "math/rand" ) // SendAddressesContext is the interface for the context needed for the SendAddresses flow. @@ -20,8 +21,7 @@ func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, ou } msgGetAddresses := message.(*appmessage.MsgRequestAddresses) - addresses := context.AddressManager().AddressCache(msgGetAddresses.IncludeAllSubnetworks, - msgGetAddresses.SubnetworkID) + addresses := context.AddressManager().Addresses() msgAddresses := appmessage.NewMsgAddresses(msgGetAddresses.IncludeAllSubnetworks, msgGetAddresses.SubnetworkID) err = msgAddresses.AddAddresses(shuffleAddresses(addresses)...) if err != nil { diff --git a/app/protocol/flows/handshake/handshake.go b/app/protocol/flows/handshake/handshake.go index 9dad8122c..515ff5b56 100644 --- a/app/protocol/flows/handshake/handshake.go +++ b/app/protocol/flows/handshake/handshake.go @@ -86,9 +86,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N } if peerAddress != nil { - subnetworkID := peer.SubnetworkID() - context.AddressManager().AddAddress(peerAddress, peerAddress, subnetworkID) - context.AddressManager().Good(peerAddress, subnetworkID) + context.AddressManager().AddAddresses(peerAddress) } err = context.StartIBDIfRequired() diff --git a/app/protocol/flows/handshake/sendversion.go b/app/protocol/flows/handshake/sendversion.go index 428fec19e..e037dc377 100644 --- a/app/protocol/flows/handshake/sendversion.go +++ b/app/protocol/flows/handshake/sendversion.go @@ -56,7 +56,7 @@ func (flow *sendVersionFlow) start() error { subnetworkID := flow.Config().SubnetworkID // Version message. - localAddress := flow.AddressManager().GetBestLocalAddress(flow.peer.Connection().NetAddress()) + localAddress := flow.AddressManager().BestLocalAddress(flow.peer.Connection().NetAddress()) msg := appmessage.NewMsgVersion(localAddress, flow.NetAdapter().ID(), flow.Config().ActiveNetParams.Name, selectedTipHash, subnetworkID) msg.AddUserAgent(userAgentName, userAgentVersion, flow.Config().UserAgentComments...) diff --git a/app/rpc/rpchandlers/get_peer_addresses.go b/app/rpc/rpchandlers/get_peer_addresses.go index 849303442..9c7d19948 100644 --- a/app/rpc/rpchandlers/get_peer_addresses.go +++ b/app/rpc/rpchandlers/get_peer_addresses.go @@ -1,6 +1,9 @@ package rpchandlers import ( + "net" + "strconv" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" @@ -8,14 +11,20 @@ import ( // HandleGetPeerAddresses handles the respectively named RPC command func HandleGetPeerAddresses(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { - peersState, err := context.AddressManager.PeersStateForSerialization() - if err != nil { - return nil, err + netAddresses := context.AddressManager.Addresses() + addressMessages := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(netAddresses)) + for i, netAddress := range netAddresses { + addressWithPort := net.JoinHostPort(netAddress.IP.String(), strconv.FormatUint(uint64(netAddress.Port), 10)) + addressMessages[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: addressWithPort} } - addresses := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(peersState.Addresses)) - for i, address := range peersState.Addresses { - addresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: string(address.Address)} + + bannedAddresses := context.AddressManager.BannedAddresses() + bannedAddressMessages := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(bannedAddresses)) + for i, netAddress := range bannedAddresses { + addressWithPort := net.JoinHostPort(netAddress.IP.String(), strconv.FormatUint(uint64(netAddress.Port), 10)) + bannedAddressMessages[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: addressWithPort} } - response := appmessage.NewGetPeerAddressesResponseMessage(addresses) + + response := appmessage.NewGetPeerAddressesResponseMessage(addressMessages, bannedAddressMessages) return response, nil } diff --git a/infrastructure/network/addressmanager/addressmanager.go b/infrastructure/network/addressmanager/addressmanager.go index 9c9d685d6..e78c321d6 100644 --- a/infrastructure/network/addressmanager/addressmanager.go +++ b/infrastructure/network/addressmanager/addressmanager.go @@ -5,1590 +5,225 @@ package addressmanager import ( - "bytes" - crand "crypto/rand" // for seeding "encoding/binary" - "encoding/gob" - "io" - "math/rand" - "net" - "runtime" - "strconv" - "strings" "sync" - "sync/atomic" - "time" - - "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/infrastructure/config" - "github.com/kaspanet/kaspad/infrastructure/db/database" - "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" ) -// AddressKey represents a "string" key in the form of ip:port for IPv4 addresses -// or [ip]:port for IPv6 addresses for use as keys in maps. +// AddressRandomizer is the interface for the randomizer needed for the AddressManager. +type AddressRandomizer interface { + RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress + RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress +} + +// AddressKey represents a "string" key of the ip addresses +// for use as keys in maps. type AddressKey string -type newAddressBucketArray [NewBucketCount]map[AddressKey]*KnownAddress -type triedAddressBucketArray [TriedBucketCount][]*KnownAddress - -// AddressManager provides a concurrency safe address manager for caching potential -// peers on the Kaspa network. -type AddressManager struct { - cfg *config.Config - database database.Database - - mutex sync.Mutex - lookupFunc func(string) ([]net.IP, error) - random *rand.Rand - key [32]byte - addressIndex map[AddressKey]*KnownAddress // address keys to known addresses for all addresses. - started int32 - shutdown int32 - wg sync.WaitGroup - quit chan struct{} - localAddressesLock sync.Mutex - localAddresses map[AddressKey]*localAddress - localSubnetworkID *externalapi.DomainSubnetworkID - - fullNodeNewAddressBucketArray newAddressBucketArray - fullNodeNewAddressCount int - fullNodeTriedAddressBucketArray triedAddressBucketArray - fullNodeTriedAddressCount int - subnetworkNewAddressBucketArrays map[externalapi.DomainSubnetworkID]*newAddressBucketArray - subnetworkNewAddressCounts map[externalapi.DomainSubnetworkID]int - subnetworkTriedAddresBucketArrays map[externalapi.DomainSubnetworkID]*triedAddressBucketArray - subnetworkTriedAddressCounts map[externalapi.DomainSubnetworkID]int -} - -type serializedKnownAddress struct { - Address AddressKey - SourceAddress AddressKey - SubnetworkID string - Attempts int - TimeStamp int64 - LastAttempt int64 - LastSuccess int64 - IsBanned bool - BannedTime int64 - // no refcount or tried, that is available from context. -} - -type serializedNewAddressBucketArray [NewBucketCount][]AddressKey -type serializedTriedAddressBucketArray [TriedBucketCount][]AddressKey - -// PeersStateForSerialization is the data model that is used to -// serialize the peers state to any encoding. -type PeersStateForSerialization struct { - Version int - Key [32]byte - Addresses []*serializedKnownAddress - - SubnetworkNewAddressBucketArrays map[string]*serializedNewAddressBucketArray // string is Subnetwork ID - FullNodeNewAddressBucketArray serializedNewAddressBucketArray - SubnetworkTriedAddressBucketArrays map[string]*serializedTriedAddressBucketArray // string is Subnetwork ID - FullNodeTriedAddressBucketArray serializedTriedAddressBucketArray -} - -type localAddress struct { - netAddress *appmessage.NetAddress - score AddressPriority -} - -// AddressPriority type is used to describe the hierarchy of local address -// discovery methods. -type AddressPriority int - -const ( - // InterfacePrio signifies the address is on a local interface - InterfacePrio AddressPriority = iota - - // BoundPrio signifies the address has been explicitly bounded to. - BoundPrio - - // UpnpPrio signifies the address was obtained from UPnP. - UpnpPrio - - // HTTPPrio signifies the address was obtained from an external HTTP service. - HTTPPrio - - // ManualPrio signifies the address was provided by --externalip. - ManualPrio -) - -const ( - // needAddressThreshold is the number of addresses under which the - // address manager will claim to need more addresses. - needAddressThreshold = 1000 - - // dumpAddressInterval is the interval used to dump the address - // cache to disk for future use. - dumpAddressInterval = time.Minute * 10 - - // triedBucketSize is the maximum number of addresses in each - // tried address bucket. - triedBucketSize = 256 - - // TriedBucketCount is the number of buckets we split tried - // addresses over. - TriedBucketCount = 64 - - // newBucketSize is the maximum number of addresses in each new address - // bucket. - newBucketSize = 64 - - // NewBucketCount is the number of buckets that we spread new addresses - // over. - NewBucketCount = 1024 - - // triedBucketsPerGroup is the number of tried buckets over which an - // address group will be spread. - triedBucketsPerGroup = 8 - - // newBucketsPerGroup is the number of new buckets over which an - // source address group will be spread. - newBucketsPerGroup = 64 - - // newBucketsPerAddress is the number of buckets a frequently seen new - // address may end up in. - newBucketsPerAddress = 8 - - // numMissingDays is the number of days before which we assume an - // address has vanished if we have not seen it announced in that long. - numMissingDays = 30 - - // numRetries is the number of tried without a single success before - // we assume an address is bad. - numRetries = 3 - - // maxFailures is the maximum number of failures we will accept without - // a success before considering an address bad. - maxFailures = 10 - - // minBadDays is the number of days since the last success before we - // will consider evicting an address. - minBadDays = 7 - - // getAddrMin is the least addresses that we will send in response - // to a getAddresses. If we have less than this amount, we send everything. - getAddrMin = 50 - - // GetAddressesMax is the most addresses that we will send in response - // to a getAddress (in practise the most addresses we will return from a - // call to AddressCache()). - GetAddressesMax = 2500 - - // getAddrPercent is the percentage of total addresses known that we - // will share with a call to AddressCache. - getAddrPercent = 23 - - // serializationVersion is the current version of the on-disk format. - serializationVersion = 1 -) - -var peersDBKey = database.MakeBucket().Key([]byte("peers")) // ErrAddressNotFound is an error returned from some functions when a // given address is not found in the address manager var ErrAddressNotFound = errors.New("address not found") +// NetAddressKey returns a key of the ip address to use it in maps. +func netAddressKey(netAddress *appmessage.NetAddress) AddressKey { + port := make([]byte, 2, 2) + binary.LittleEndian.PutUint16(port, netAddress.Port) + + key := make([]byte, len(netAddress.IP), len(netAddress.IP)+len(port)) + copy(key, netAddress.IP) + + return AddressKey(append(key, port...)) +} + +// netAddressKeys returns a key of the ip address to use it in maps. +func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[AddressKey]bool { + result := make(map[AddressKey]bool, len(netAddresses)) + for _, netAddress := range netAddresses { + key := netAddressKey(netAddress) + result[key] = true + } + + return result +} + +// AddressManager provides a concurrency safe address manager for caching potential +// peers on the Kaspa network. +type AddressManager struct { + addresses map[AddressKey]*appmessage.NetAddress + bannedAddresses map[AddressKey]*appmessage.NetAddress + localAddresses *localAddressManager + mutex sync.Mutex + cfg *Config + random AddressRandomizer +} + // New returns a new Kaspa address manager. -func New(cfg *config.Config, database database.Database) (*AddressManager, error) { - addressManager := AddressManager{ - cfg: cfg, - database: database, - lookupFunc: cfg.Lookup, - random: rand.New(rand.NewSource(time.Now().UnixNano())), - quit: make(chan struct{}), - localAddresses: make(map[AddressKey]*localAddress), - localSubnetworkID: cfg.SubnetworkID, - } - err := addressManager.initListeners() - if err != nil { - return nil, err - } - addressManager.reset() - return &addressManager, nil -} - -// updateAddress is a helper function to either update an address already known -// to the address manager, or to add the address if not already known. -func (am *AddressManager) updateAddress(netAddress, sourceAddress *appmessage.NetAddress, subnetworkID *externalapi.DomainSubnetworkID) { - // Filter out non-routable addresses. Note that non-routable - // also includes invalid and local addresses. - if !am.IsRoutable(netAddress) { - return - } - - addressKey := NetAddressKey(netAddress) - knownAddress := am.knownAddress(netAddress) - if knownAddress != nil { - // Update the last seen time and services. - // note that to prevent causing excess garbage on getaddr - // messages the netaddresses in addrmaanger are *immutable*, - // if we need to change them then we replace the pointer with a - // new copy so that we don't have to copy every netAddress for getaddress. - if netAddress.Timestamp.After(knownAddress.netAddress.Timestamp) || - (knownAddress.netAddress.Services&netAddress.Services) != - netAddress.Services { - - netAddressCopy := *knownAddress.netAddress - netAddressCopy.Timestamp = netAddress.Timestamp - netAddressCopy.AddService(netAddress.Services) - knownAddress.netAddress = &netAddressCopy - } - - // If already in tried, we have nothing to do here. - if knownAddress.tried { - return - } - - // Already at our max? - if knownAddress.referenceCount == newBucketsPerAddress { - return - } - - // The more entries we have, the less likely we are to add more. - // likelihood is 2N. - factor := int32(2 * knownAddress.referenceCount) - if am.random.Int31n(factor) != 0 { - return - } - } else { - // Make a copy of the net address to avoid races since it is - // updated elsewhere in the addressManager code and would otherwise - // change the actual netAddress on the peer. - netAddressCopy := *netAddress - knownAddress = &KnownAddress{netAddress: &netAddressCopy, sourceAddress: sourceAddress, subnetworkID: subnetworkID} - am.addressIndex[addressKey] = knownAddress - am.incrementNewAddressCount(subnetworkID) - } - - // Already exists? - newAddressBucketArray := am.newAddressBucketArray(knownAddress.subnetworkID) - newAddressBucketIndex := am.newAddressBucketIndex(netAddress, sourceAddress) - if newAddressBucketArray != nil { - if _, ok := newAddressBucketArray[newAddressBucketIndex][addressKey]; ok { - return - } - } - - // Enforce max addresses. - if newAddressBucketArray != nil && len(newAddressBucketArray[newAddressBucketIndex]) > newBucketSize { - log.Tracef("new bucket is full, expiring old") - am.expireNew(knownAddress.subnetworkID, newAddressBucketIndex) - } - - // Add to new bucket. - knownAddress.referenceCount++ - am.updateAddrNew(newAddressBucketIndex, addressKey, knownAddress) - - totalAddressCount := am.newAddressCount(knownAddress.subnetworkID) + am.triedAddressCount(knownAddress.subnetworkID) - log.Tracef("Added new address %s for a total of %d addresses", addressKey, totalAddressCount) - -} - -func (am *AddressManager) updateAddrNew(bucket int, addressKey AddressKey, knownAddress *KnownAddress) { - if knownAddress.subnetworkID == nil { - am.fullNodeNewAddressBucketArray[bucket][addressKey] = knownAddress - return - } - - if _, ok := am.subnetworkNewAddressBucketArrays[*knownAddress.subnetworkID]; !ok { - am.subnetworkNewAddressBucketArrays[*knownAddress.subnetworkID] = &newAddressBucketArray{} - for i := range am.subnetworkNewAddressBucketArrays[*knownAddress.subnetworkID] { - am.subnetworkNewAddressBucketArrays[*knownAddress.subnetworkID][i] = make(map[AddressKey]*KnownAddress) - } - } - am.subnetworkNewAddressBucketArrays[*knownAddress.subnetworkID][bucket][addressKey] = knownAddress -} - -func (am *AddressManager) updateAddrTried(bucketIndex int, knownAddress *KnownAddress) { - if knownAddress.subnetworkID == nil { - am.fullNodeTriedAddressBucketArray[bucketIndex] = append(am.fullNodeTriedAddressBucketArray[bucketIndex], knownAddress) - return - } - - if _, ok := am.subnetworkTriedAddresBucketArrays[*knownAddress.subnetworkID]; !ok { - am.subnetworkTriedAddresBucketArrays[*knownAddress.subnetworkID] = &triedAddressBucketArray{} - for i := range am.subnetworkTriedAddresBucketArrays[*knownAddress.subnetworkID] { - am.subnetworkTriedAddresBucketArrays[*knownAddress.subnetworkID][i] = nil - } - } - am.subnetworkTriedAddresBucketArrays[*knownAddress.subnetworkID][bucketIndex] = append(am.subnetworkTriedAddresBucketArrays[*knownAddress.subnetworkID][bucketIndex], knownAddress) -} - -// expireNew makes space in the new buckets by expiring the really bad entries. -// If no bad entries are available we look at a few and remove the oldest. -func (am *AddressManager) expireNew(subnetworkID *externalapi.DomainSubnetworkID, bucketIndex int) { - // First see if there are any entries that are so bad we can just throw - // them away. otherwise we throw away the oldest entry in the cache. - // We keep track of oldest in the initial traversal and use that - // information instead. - var oldest *KnownAddress - newAddressBucketArray := am.newAddressBucketArray(subnetworkID) - for addressKey, knownAddress := range newAddressBucketArray[bucketIndex] { - if knownAddress.isBad() { - log.Tracef("expiring bad address %s", addressKey) - delete(newAddressBucketArray[bucketIndex], addressKey) - knownAddress.referenceCount-- - if knownAddress.referenceCount == 0 { - am.decrementNewAddressCount(subnetworkID) - delete(am.addressIndex, addressKey) - } - continue - } - if oldest == nil { - oldest = knownAddress - } else if !knownAddress.netAddress.Timestamp.After(oldest.netAddress.Timestamp) { - oldest = knownAddress - } - } - - if oldest != nil { - addressKey := NetAddressKey(oldest.netAddress) - log.Tracef("expiring oldest address %s", addressKey) - - delete(newAddressBucketArray[bucketIndex], addressKey) - oldest.referenceCount-- - if oldest.referenceCount == 0 { - am.decrementNewAddressCount(subnetworkID) - delete(am.addressIndex, addressKey) - } - } -} - -// pickTried selects an address from the tried bucket to be evicted. -// We just choose the eldest. -func (am *AddressManager) pickTried(subnetworkID *externalapi.DomainSubnetworkID, bucketIndex int) ( - knownAddress *KnownAddress, knownAddressIndex int) { - - var oldest *KnownAddress - oldestIndex := -1 - triedAddressBucketArray := am.triedAddressBucketArray(subnetworkID) - for i, address := range triedAddressBucketArray[bucketIndex] { - if oldest == nil || oldest.netAddress.Timestamp.After(address.netAddress.Timestamp) { - oldestIndex = i - oldest = address - } - } - return oldest, oldestIndex -} - -func (am *AddressManager) newAddressBucketIndex(netAddress, srcAddress *appmessage.NetAddress) int { - // doublesha256(key + sourcegroup + int64(doublesha256(key + group + sourcegroup))%bucket_per_source_group) % num_new_buckets - - data1 := []byte{} - data1 = append(data1, am.key[:]...) - data1 = append(data1, []byte(am.GroupKey(netAddress))...) - data1 = append(data1, []byte(am.GroupKey(srcAddress))...) - hash1 := hashes.HashData(data1) - hash64 := binary.LittleEndian.Uint64(hash1[:]) - hash64 %= newBucketsPerGroup - var hashbuf [8]byte - binary.LittleEndian.PutUint64(hashbuf[:], hash64) - data2 := []byte{} - data2 = append(data2, am.key[:]...) - data2 = append(data2, am.GroupKey(srcAddress)...) - data2 = append(data2, hashbuf[:]...) - - hash2 := hashes.HashData(data2) - return int(binary.LittleEndian.Uint64(hash2[:]) % NewBucketCount) -} - -func (am *AddressManager) triedAddressBucketIndex(netAddress *appmessage.NetAddress) int { - // doublesha256(key + group + truncate_to_64bits(doublesha256(key)) % buckets_per_group) % num_buckets - data1 := []byte{} - data1 = append(data1, am.key[:]...) - data1 = append(data1, []byte(NetAddressKey(netAddress))...) - hash1 := hashes.HashData(data1) - hash64 := binary.LittleEndian.Uint64(hash1[:]) - hash64 %= triedBucketsPerGroup - var hashbuf [8]byte - binary.LittleEndian.PutUint64(hashbuf[:], hash64) - data2 := []byte{} - data2 = append(data2, am.key[:]...) - data2 = append(data2, am.GroupKey(netAddress)...) - data2 = append(data2, hashbuf[:]...) - - hash2 := hashes.HashData(data2) - return int(binary.LittleEndian.Uint64(hash2[:]) % TriedBucketCount) -} - -// addressHandler is the main handler for the address manager. It must be run -// as a goroutine. -func (am *AddressManager) addressHandler() { - dumpAddressTicker := time.NewTicker(dumpAddressInterval) - defer dumpAddressTicker.Stop() - -out: - for { - select { - case <-dumpAddressTicker.C: - err := am.savePeers() - if err != nil { - panic(errors.Wrap(err, "error saving peers")) - } - - case <-am.quit: - break out - } - } - err := am.savePeers() - if err != nil { - panic(errors.Wrap(err, "error saving peers")) - } - am.wg.Done() - log.Trace("Address handler done") -} - -// savePeers saves all the known addresses to the database so they can be read back -// in at next run. -func (am *AddressManager) savePeers() error { - serializedPeersState, err := am.serializePeersState() - if err != nil { - return err - } - - return am.database.Put(peersDBKey, serializedPeersState) -} - -func (am *AddressManager) serializePeersState() ([]byte, error) { - peersState, err := am.PeersStateForSerialization() +func New(cfg *Config) (*AddressManager, error) { + localAddresses, err := newLocalAddressManager(cfg) if err != nil { return nil, err } - buffer := &bytes.Buffer{} - encoder := gob.NewEncoder(buffer) - err = encoder.Encode(&peersState) - if err != nil { - return nil, errors.Wrap(err, "failed to encode peers state") - } - - return buffer.Bytes(), nil + return &AddressManager{ + addresses: map[AddressKey]*appmessage.NetAddress{}, + bannedAddresses: map[AddressKey]*appmessage.NetAddress{}, + localAddresses: localAddresses, + random: NewAddressRandomize(), + cfg: cfg, + }, nil } -// PeersStateForSerialization returns the data model that is used to serialize the peers state to any encoding. -func (am *AddressManager) PeersStateForSerialization() (*PeersStateForSerialization, error) { +func (am *AddressManager) addAddressNoLock(address *appmessage.NetAddress) { + if !IsRoutable(address, am.cfg.AcceptUnroutable) { + return + } + + key := netAddressKey(address) + _, ok := am.addresses[key] + if !ok { + am.addresses[key] = address + } +} + +// AddAddress adds address to the address manager +func (am *AddressManager) AddAddress(address *appmessage.NetAddress) { am.mutex.Lock() defer am.mutex.Unlock() - // First we make a serializable data structure so we can encode it to - // gob. - peersState := new(PeersStateForSerialization) - peersState.Version = serializationVersion - copy(peersState.Key[:], am.key[:]) - - peersState.Addresses = make([]*serializedKnownAddress, len(am.addressIndex)) - i := 0 - for addressKey, knownAddress := range am.addressIndex { - serializedAddress := new(serializedKnownAddress) - serializedAddress.Address = addressKey - if knownAddress.subnetworkID == nil { - serializedAddress.SubnetworkID = "" - } else { - serializedAddress.SubnetworkID = knownAddress.subnetworkID.String() - } - serializedAddress.TimeStamp = knownAddress.netAddress.Timestamp.UnixMilliseconds() - serializedAddress.SourceAddress = NetAddressKey(knownAddress.sourceAddress) - serializedAddress.Attempts = knownAddress.attempts - serializedAddress.LastAttempt = knownAddress.lastAttempt.UnixMilliseconds() - serializedAddress.LastSuccess = knownAddress.lastSuccess.UnixMilliseconds() - serializedAddress.IsBanned = knownAddress.isBanned - serializedAddress.BannedTime = knownAddress.bannedTime.UnixMilliseconds() - // Tried and referenceCount are implicit in the rest of the structure - // and will be worked out from context on unserialisation. - peersState.Addresses[i] = serializedAddress - i++ - } - - peersState.SubnetworkNewAddressBucketArrays = make(map[string]*serializedNewAddressBucketArray) - for subnetworkID := range am.subnetworkNewAddressBucketArrays { - subnetworkIDStr := subnetworkID.String() - peersState.SubnetworkNewAddressBucketArrays[subnetworkIDStr] = &serializedNewAddressBucketArray{} - - for i := range am.subnetworkNewAddressBucketArrays[subnetworkID] { - peersState.SubnetworkNewAddressBucketArrays[subnetworkIDStr][i] = make([]AddressKey, len(am.subnetworkNewAddressBucketArrays[subnetworkID][i])) - j := 0 - for k := range am.subnetworkNewAddressBucketArrays[subnetworkID][i] { - peersState.SubnetworkNewAddressBucketArrays[subnetworkIDStr][i][j] = k - j++ - } - } - } - - for i := range am.fullNodeNewAddressBucketArray { - peersState.FullNodeNewAddressBucketArray[i] = make([]AddressKey, len(am.fullNodeNewAddressBucketArray[i])) - j := 0 - for k := range am.fullNodeNewAddressBucketArray[i] { - peersState.FullNodeNewAddressBucketArray[i][j] = k - j++ - } - } - - peersState.SubnetworkTriedAddressBucketArrays = make(map[string]*serializedTriedAddressBucketArray) - for subnetworkID := range am.subnetworkTriedAddresBucketArrays { - subnetworkIDStr := subnetworkID.String() - peersState.SubnetworkTriedAddressBucketArrays[subnetworkIDStr] = &serializedTriedAddressBucketArray{} - - for i := range am.subnetworkTriedAddresBucketArrays[subnetworkID] { - peersState.SubnetworkTriedAddressBucketArrays[subnetworkIDStr][i] = make([]AddressKey, len(am.subnetworkTriedAddresBucketArrays[subnetworkID][i])) - j := 0 - for _, knownAddress := range am.subnetworkTriedAddresBucketArrays[subnetworkID][i] { - peersState.SubnetworkTriedAddressBucketArrays[subnetworkIDStr][i][j] = NetAddressKey(knownAddress.netAddress) - j++ - } - } - } - - for i := range am.fullNodeTriedAddressBucketArray { - peersState.FullNodeTriedAddressBucketArray[i] = make([]AddressKey, len(am.fullNodeTriedAddressBucketArray[i])) - j := 0 - for _, knownAddress := range am.fullNodeTriedAddressBucketArray[i] { - peersState.FullNodeTriedAddressBucketArray[i][j] = NetAddressKey(knownAddress.netAddress) - j++ - } - } - - return peersState, nil + am.addAddressNoLock(address) } -// loadPeers loads the known address from the database. If missing, -// just don't load anything and start fresh. -func (am *AddressManager) loadPeers() error { - am.mutex.Lock() - defer am.mutex.Unlock() - - serializedPeerState, err := am.database.Get(peersDBKey) - if database.IsNotFoundError(err) { - am.reset() - log.Info("No peers state was found in the database. Created a new one", am.totalNumAddresses()) - return nil - } - if err != nil { - return err - } - - err = am.deserializePeersState(serializedPeerState) - if err != nil { - return err - } - - log.Infof("Loaded %d addresses from database", am.totalNumAddresses()) - return nil -} - -func (am *AddressManager) deserializePeersState(serializedPeerState []byte) error { - var peersState PeersStateForSerialization - r := bytes.NewBuffer(serializedPeerState) - dec := gob.NewDecoder(r) - err := dec.Decode(&peersState) - if err != nil { - return errors.Wrap(err, "error deserializing peers state") - } - - if peersState.Version != serializationVersion { - return errors.Errorf("unknown version %d in serialized "+ - "peers state", peersState.Version) - } - copy(am.key[:], peersState.Key[:]) - - for _, serializedKnownAddress := range peersState.Addresses { - knownAddress := new(KnownAddress) - knownAddress.netAddress, err = am.DeserializeNetAddress(serializedKnownAddress.Address) - if err != nil { - return errors.Errorf("failed to deserialize netaddress "+ - "%s: %s", serializedKnownAddress.Address, err) - } - knownAddress.sourceAddress, err = am.DeserializeNetAddress(serializedKnownAddress.SourceAddress) - if err != nil { - return errors.Errorf("failed to deserialize netaddress "+ - "%s: %s", serializedKnownAddress.SourceAddress, err) - } - if serializedKnownAddress.SubnetworkID != "" { - knownAddress.subnetworkID, err = subnetworks.FromString(serializedKnownAddress.SubnetworkID) - if err != nil { - return errors.Errorf("failed to deserialize subnetwork id "+ - "%s: %s", serializedKnownAddress.SubnetworkID, err) - } - } - knownAddress.attempts = serializedKnownAddress.Attempts - knownAddress.lastAttempt = mstime.UnixMilliseconds(serializedKnownAddress.LastAttempt) - knownAddress.lastSuccess = mstime.UnixMilliseconds(serializedKnownAddress.LastSuccess) - knownAddress.isBanned = serializedKnownAddress.IsBanned - knownAddress.bannedTime = mstime.UnixMilliseconds(serializedKnownAddress.BannedTime) - am.addressIndex[NetAddressKey(knownAddress.netAddress)] = knownAddress - } - - for subnetworkIDStr := range peersState.SubnetworkNewAddressBucketArrays { - subnetworkID, err := subnetworks.FromString(subnetworkIDStr) - if err != nil { - return err - } - for i, subnetworkNewAddressBucket := range peersState.SubnetworkNewAddressBucketArrays[subnetworkIDStr] { - for _, addressKey := range subnetworkNewAddressBucket { - knownAddress, ok := am.addressIndex[addressKey] - if !ok { - return errors.Errorf("newbucket contains %s but "+ - "none in address list", addressKey) - } - - if knownAddress.referenceCount == 0 { - am.subnetworkNewAddressCounts[*subnetworkID]++ - } - knownAddress.referenceCount++ - am.updateAddrNew(i, addressKey, knownAddress) - } - } - } - - for i, fullNodeNewAddressBucket := range peersState.FullNodeNewAddressBucketArray { - for _, addressKey := range fullNodeNewAddressBucket { - knownAddress, ok := am.addressIndex[addressKey] - if !ok { - return errors.Errorf("full nodes newbucket contains %s but "+ - "none in address list", addressKey) - } - - if knownAddress.referenceCount == 0 { - am.fullNodeNewAddressCount++ - } - knownAddress.referenceCount++ - am.updateAddrNew(i, addressKey, knownAddress) - } - } - - for subnetworkIDString := range peersState.SubnetworkTriedAddressBucketArrays { - subnetworkID, err := subnetworks.FromString(subnetworkIDString) - if err != nil { - return err - } - for i, subnetworkTriedAddressBucket := range peersState.SubnetworkTriedAddressBucketArrays[subnetworkIDString] { - for _, addressKey := range subnetworkTriedAddressBucket { - knownAddress, ok := am.addressIndex[addressKey] - if !ok { - return errors.Errorf("Tried bucket contains %s but "+ - "none in address list", addressKey) - } - - knownAddress.tried = true - am.subnetworkTriedAddressCounts[*subnetworkID]++ - am.subnetworkTriedAddresBucketArrays[*subnetworkID][i] = append(am.subnetworkTriedAddresBucketArrays[*subnetworkID][i], knownAddress) - } - } - } - - for i, fullNodeTriedAddressBucket := range peersState.FullNodeTriedAddressBucketArray { - for _, addressKey := range fullNodeTriedAddressBucket { - knownAddress, ok := am.addressIndex[addressKey] - if !ok { - return errors.Errorf("Full nodes tried bucket contains %s but "+ - "none in address list", addressKey) - } - - knownAddress.tried = true - am.fullNodeTriedAddressCount++ - am.fullNodeTriedAddressBucketArray[i] = append(am.fullNodeTriedAddressBucketArray[i], knownAddress) - } - } - - // Sanity checking. - for addressKey, knownAddress := range am.addressIndex { - if knownAddress.referenceCount == 0 && !knownAddress.tried { - return errors.Errorf("address %s after serialisation "+ - "with no references", addressKey) - } - - if knownAddress.referenceCount > 0 && knownAddress.tried { - return errors.Errorf("address %s after serialisation "+ - "which is both new and tried!", addressKey) - } - } - - return nil -} - -// DeserializeNetAddress converts a given address string to a *appmessage.NetAddress -func (am *AddressManager) DeserializeNetAddress(addressKey AddressKey) (*appmessage.NetAddress, error) { - host, portString, err := net.SplitHostPort(string(addressKey)) - if err != nil { - return nil, err - } - port, err := strconv.ParseUint(portString, 10, 16) - if err != nil { - return nil, err - } - - return am.HostToNetAddress(host, uint16(port), appmessage.SFNodeNetwork) -} - -// Start begins the core address handler which manages a pool of known -// addresses, timeouts, and interval based writes. -func (am *AddressManager) Start() error { - // Already started? - if atomic.AddInt32(&am.started, 1) != 1 { - return nil - } - - log.Trace("Starting address manager") - - // Load peers we already know about from the database. - err := am.loadPeers() - if err != nil { - return err - } - - // Start the address ticker to save addresses periodically. - am.wg.Add(1) - spawn("addressManager.addressHandler", am.addressHandler) - return nil -} - -// Stop gracefully shuts down the address manager by stopping the main handler. -func (am *AddressManager) Stop() error { - if atomic.AddInt32(&am.shutdown, 1) != 1 { - log.Warnf("Address manager is already in the process of " + - "shutting down") - return nil - } - - log.Infof("Address manager shutting down") - close(am.quit) - am.wg.Wait() - return nil -} - -// AddAddresses adds new addresses to the address manager. It enforces a max -// number of addresses and silently ignores duplicate addresses. It is -// safe for concurrent access. -func (am *AddressManager) AddAddresses(addresses []*appmessage.NetAddress, sourceAddress *appmessage.NetAddress, subnetworkID *externalapi.DomainSubnetworkID) { +// AddAddresses adds addresses to the address manager +func (am *AddressManager) AddAddresses(addresses ...*appmessage.NetAddress) { am.mutex.Lock() defer am.mutex.Unlock() for _, address := range addresses { - am.updateAddress(address, sourceAddress, subnetworkID) + am.addAddressNoLock(address) } } -// AddAddress adds a new address to the address manager. It enforces a max -// number of addresses and silently ignores duplicate addresses. It is -// safe for concurrent access. -func (am *AddressManager) AddAddress(address, sourceAddress *appmessage.NetAddress, subnetworkID *externalapi.DomainSubnetworkID) { +// RemoveAddress removes addresses from the address manager +func (am *AddressManager) RemoveAddress(address *appmessage.NetAddress) { am.mutex.Lock() defer am.mutex.Unlock() - am.updateAddress(address, sourceAddress, subnetworkID) + key := netAddressKey(address) + delete(am.addresses, key) + delete(am.bannedAddresses, key) } -// numAddresses returns the number of addresses that belongs to a specific subnetwork id -// which are known to the address manager. -func (am *AddressManager) numAddresses(subnetworkID *externalapi.DomainSubnetworkID) int { - if subnetworkID == nil { - return am.fullNodeNewAddressCount + am.fullNodeTriedAddressCount - } - return am.subnetworkTriedAddressCounts[*subnetworkID] + am.subnetworkNewAddressCounts[*subnetworkID] -} - -// totalNumAddresses returns the number of addresses known to the address manager. -func (am *AddressManager) totalNumAddresses() int { - total := am.fullNodeNewAddressCount + am.fullNodeTriedAddressCount - for _, numAddresses := range am.subnetworkTriedAddressCounts { - total += numAddresses - } - for _, numAddresses := range am.subnetworkNewAddressCounts { - total += numAddresses - } - return total -} - -// TotalNumAddresses returns the number of addresses known to the address manager. -func (am *AddressManager) TotalNumAddresses() int { +// Addresses returns all addresses +func (am *AddressManager) Addresses() []*appmessage.NetAddress { am.mutex.Lock() defer am.mutex.Unlock() - return am.totalNumAddresses() + result := make([]*appmessage.NetAddress, 0, len(am.addresses)) + for _, address := range am.addresses { + result = append(result, address) + } + + return result } -// NeedMoreAddresses returns whether or not the address manager needs more -// addresses. -func (am *AddressManager) NeedMoreAddresses() bool { +// BannedAddresses returns all banned addresses +func (am *AddressManager) BannedAddresses() []*appmessage.NetAddress { am.mutex.Lock() defer am.mutex.Unlock() - allAddresses := am.numAddresses(am.localSubnetworkID) - if am.localSubnetworkID != nil { - allAddresses += am.numAddresses(nil) + result := make([]*appmessage.NetAddress, 0, len(am.bannedAddresses)) + for _, address := range am.bannedAddresses { + result = append(result, address) } - return allAddresses < needAddressThreshold + + return result } -// AddressCache returns the current address cache. It must be treated as -// read-only (but since it is a copy now, this is not as dangerous). -func (am *AddressManager) AddressCache(includeAllSubnetworks bool, subnetworkID *externalapi.DomainSubnetworkID) []*appmessage.NetAddress { +// NotBannedAddressesWithException returns all not banned addresses with excpetion +func (am *AddressManager) NotBannedAddressesWithException(exceptions []*appmessage.NetAddress) []*appmessage.NetAddress { + exceptionsKeys := netAddressesKeys(exceptions) am.mutex.Lock() defer am.mutex.Unlock() - if len(am.addressIndex) == 0 { - return nil - } - - allAddresses := []*appmessage.NetAddress{} - // Iteration order is undefined here, but we randomise it anyway. - for _, v := range am.addressIndex { - if includeAllSubnetworks || *v.SubnetworkID() == *subnetworkID { - allAddresses = append(allAddresses, v.netAddress) + result := make([]*appmessage.NetAddress, 0, len(am.addresses)-len(exceptions)) + for key, address := range am.addresses { + if !exceptionsKeys[key] { + result = append(result, address) } } - numAddresses := len(allAddresses) * getAddrPercent / 100 - if numAddresses > GetAddressesMax { - numAddresses = GetAddressesMax - } - if len(allAddresses) < getAddrMin { - numAddresses = len(allAddresses) - } - if len(allAddresses) > getAddrMin && numAddresses < getAddrMin { - numAddresses = getAddrMin - } - - // Fisher-Yates shuffle the array. We only need to do the first - // `numAddresses' since we are throwing the rest. - for i := 0; i < numAddresses; i++ { - // pick a number between current index and the end - j := rand.Intn(len(allAddresses)-i) + i - allAddresses[i], allAddresses[j] = allAddresses[j], allAddresses[i] - } - - // slice off the limit we are willing to share. - return allAddresses[0:numAddresses] + return result } -// reset resets the address manager by reinitialising the random source -// and allocating fresh empty bucket storage. -func (am *AddressManager) reset() { - am.addressIndex = make(map[AddressKey]*KnownAddress) - - // fill key with bytes from a good random source. - io.ReadFull(crand.Reader, am.key[:]) - am.subnetworkNewAddressBucketArrays = make(map[externalapi.DomainSubnetworkID]*newAddressBucketArray) - am.subnetworkTriedAddresBucketArrays = make(map[externalapi.DomainSubnetworkID]*triedAddressBucketArray) - - am.subnetworkNewAddressCounts = make(map[externalapi.DomainSubnetworkID]int) - am.subnetworkTriedAddressCounts = make(map[externalapi.DomainSubnetworkID]int) - - for i := range am.fullNodeNewAddressBucketArray { - am.fullNodeNewAddressBucketArray[i] = make(map[AddressKey]*KnownAddress) - } - for i := range am.fullNodeTriedAddressBucketArray { - am.fullNodeTriedAddressBucketArray[i] = nil - } - am.fullNodeNewAddressCount = 0 - am.fullNodeTriedAddressCount = 0 +// RandomAddress returns a random address that isn't banned and isn't in exceptions +func (am *AddressManager) RandomAddress(exceptions []*appmessage.NetAddress) *appmessage.NetAddress { + validAddresses := am.NotBannedAddressesWithException(exceptions) + return am.random.RandomAddress(validAddresses) } -// HostToNetAddress returns a netaddress given a host address. If -// the host is not an IP address it will be resolved. -func (am *AddressManager) HostToNetAddress(host string, port uint16, services appmessage.ServiceFlag) (*appmessage.NetAddress, error) { - ip := net.ParseIP(host) - if ip == nil { - ips, err := am.lookupFunc(host) - if err != nil { - return nil, err - } - if len(ips) == 0 { - return nil, errors.Errorf("no addresses found for %s", host) - } - ip = ips[0] - } - - return appmessage.NewNetAddressIPPort(ip, port, services), nil +// RandomAddresses returns count addresses at random that aren't banned and aren't in exceptions +func (am *AddressManager) RandomAddresses(count int, exceptions []*appmessage.NetAddress) []*appmessage.NetAddress { + validAddresses := am.NotBannedAddressesWithException(exceptions) + return am.random.RandomAddresses(validAddresses, count) } -// NetAddressKey returns a key in the form of ip:port for IPv4 addresses -// or [ip]:port for IPv6 addresses for use as keys in maps. -func NetAddressKey(netAddress *appmessage.NetAddress) AddressKey { - port := strconv.FormatUint(uint64(netAddress.Port), 10) - - return AddressKey(net.JoinHostPort(netAddress.IP.String(), port)) -} - -// GetAddress returns a single address that should be routable. It picks a -// random one from the possible addresses with preference given to ones that -// have not been used recently and should not pick 'close' addresses -// consecutively. -func (am *AddressManager) GetAddress() *KnownAddress { - // Protect concurrent access. - am.mutex.Lock() - defer am.mutex.Unlock() - - triedAddressBucketArray := am.triedAddressBucketArray(am.localSubnetworkID) - triedAddressCount := am.triedAddressCount(am.localSubnetworkID) - newAddressBucketArray := am.newAddressBucketArray(am.localSubnetworkID) - newAddressCount := am.newAddressCount(am.localSubnetworkID) - knownAddress := am.getAddress(triedAddressBucketArray, triedAddressCount, newAddressBucketArray, newAddressCount) - - return knownAddress - -} - -// getAddress returns a single address that should be routable. -// See GetAddress for further details. -func (am *AddressManager) getAddress(triedAddressBucketArray *triedAddressBucketArray, triedAddressCount int, - newAddressBucketArray *newAddressBucketArray, newAddressCount int) *KnownAddress { - - // Use a 50% chance for choosing between tried and new addresses. - var bucketArray addressBucketArray - if triedAddressCount > 0 && (newAddressCount == 0 || am.random.Intn(2) == 0) { - bucketArray = triedAddressBucketArray - } else if newAddressCount > 0 { - bucketArray = newAddressBucketArray - } else { - // There aren't any addresses in any of the buckets - return nil - } - - // Pick a random bucket - randomBucket := bucketArray.randomBucket(am.random) - - // Get the sum of all chances - totalChance := float64(0) - for _, knownAddress := range randomBucket { - totalChance += knownAddress.chance() - } - - // Pick a random address weighted by chance - randomValue := am.random.Float64() - accumulatedChance := float64(0) - for _, knownAddress := range randomBucket { - normalizedChance := knownAddress.chance() / totalChance - accumulatedChance += normalizedChance - if randomValue < accumulatedChance { - return knownAddress - } - } - - panic("randomValue is equal to or greater than 1, which cannot happen") -} - -type addressBucketArray interface { - name() string - randomBucket(random *rand.Rand) []*KnownAddress -} - -func (nb *newAddressBucketArray) randomBucket(random *rand.Rand) []*KnownAddress { - nonEmptyBuckets := make([]map[AddressKey]*KnownAddress, 0, NewBucketCount) - for _, bucket := range nb { - if len(bucket) > 0 { - nonEmptyBuckets = append(nonEmptyBuckets, bucket) - } - } - randomIndex := random.Intn(len(nonEmptyBuckets)) - randomBucket := nonEmptyBuckets[randomIndex] - - // Collect the known addresses into a slice - randomBucketSlice := make([]*KnownAddress, 0, len(randomBucket)) - for _, knownAddress := range randomBucket { - randomBucketSlice = append(randomBucketSlice, knownAddress) - } - return randomBucketSlice -} - -func (nb *newAddressBucketArray) name() string { - return "new" -} - -func (tb *triedAddressBucketArray) randomBucket(random *rand.Rand) []*KnownAddress { - nonEmptyBuckets := make([][]*KnownAddress, 0, TriedBucketCount) - for _, bucket := range tb { - if len(bucket) > 0 { - nonEmptyBuckets = append(nonEmptyBuckets, bucket) - } - } - randomIndex := random.Intn(len(nonEmptyBuckets)) - return nonEmptyBuckets[randomIndex] -} - -func (tb *triedAddressBucketArray) name() string { - return "tried" -} - -func (am *AddressManager) knownAddress(address *appmessage.NetAddress) *KnownAddress { - return am.addressIndex[NetAddressKey(address)] -} - -// Attempt increases the given address' attempt counter and updates -// the last attempt time. -func (am *AddressManager) Attempt(address *appmessage.NetAddress) { - am.mutex.Lock() - defer am.mutex.Unlock() - - // find address. - // Surely address will be in tried by now? - knownAddress := am.knownAddress(address) - if knownAddress == nil { - return - } - // set last tried time to now - knownAddress.attempts++ - knownAddress.lastAttempt = mstime.Now() -} - -// Connected Marks the given address as currently connected and working at the -// current time. The address must already be known to AddressManager else it will -// be ignored. -func (am *AddressManager) Connected(address *appmessage.NetAddress) { - am.mutex.Lock() - defer am.mutex.Unlock() - - knownAddress := am.knownAddress(address) - if knownAddress == nil { - return - } - - // Update the time as long as it has been 20 minutes since last we did - // so. - now := mstime.Now() - if now.After(knownAddress.netAddress.Timestamp.Add(time.Minute * 20)) { - // knownAddress.netAddress is immutable, so replace it. - netAddressCopy := *knownAddress.netAddress - netAddressCopy.Timestamp = mstime.Now() - knownAddress.netAddress = &netAddressCopy - } -} - -// Good marks the given address as good. To be called after a successful -// connection and version exchange. If the address is unknown to the address -// manager it will be ignored. -func (am *AddressManager) Good(address *appmessage.NetAddress, subnetworkID *externalapi.DomainSubnetworkID) { - am.mutex.Lock() - defer am.mutex.Unlock() - - knownAddress := am.knownAddress(address) - if knownAddress == nil { - return - } - oldSubnetworkID := knownAddress.subnetworkID - - // knownAddress.Timestamp is not updated here to avoid leaking information - // about currently connected peers. - now := mstime.Now() - knownAddress.lastSuccess = now - knownAddress.lastAttempt = now - knownAddress.attempts = 0 - knownAddress.subnetworkID = subnetworkID - - addressKey := NetAddressKey(address) - triedAddressBucketIndex := am.triedAddressBucketIndex(knownAddress.netAddress) - - if knownAddress.tried { - // If this address was already tried, and subnetworkID didn't change - don't do anything - if *subnetworkID == *oldSubnetworkID { - return - } - - // If this address was already tried, but subnetworkID was changed - - // update subnetworkID, than continue as though this is a new address - bucket := am.subnetworkTriedAddresBucketArrays[*oldSubnetworkID][triedAddressBucketIndex] - var toRemoveIndex int - toRemoveIndexFound := false - for i, knownAddress := range bucket { - if NetAddressKey(knownAddress.NetAddress()) == addressKey { - toRemoveIndex = i - toRemoveIndexFound = true - break - } - } - if toRemoveIndexFound { - am.subnetworkTriedAddresBucketArrays[*oldSubnetworkID][triedAddressBucketIndex] = - append(bucket[:toRemoveIndex], bucket[toRemoveIndex+1:]...) - } - } - - // Ok, need to move it to tried. - - // Remove from all new buckets. - // Record one of the buckets in question and call it the `oldBucketIndex' - var oldBucketIndex int - oldBucketIndexFound := false - if !knownAddress.tried { - newAddressBucketArray := am.newAddressBucketArray(oldSubnetworkID) - for i := range newAddressBucketArray { - // we check for existence so we can record the first one - if _, ok := newAddressBucketArray[i][addressKey]; ok { - if !oldBucketIndexFound { - oldBucketIndex = i - oldBucketIndexFound = true - } - - delete(newAddressBucketArray[i], addressKey) - knownAddress.referenceCount-- - } - } - - am.decrementNewAddressCount(oldSubnetworkID) - } - - // Room in this tried bucket? - triedAddressBucketArray := am.triedAddressBucketArray(knownAddress.subnetworkID) - triedAddressCount := am.triedAddressCount(knownAddress.subnetworkID) - if triedAddressCount == 0 || len(triedAddressBucketArray[triedAddressBucketIndex]) < triedBucketSize { - knownAddress.tried = true - am.updateAddrTried(triedAddressBucketIndex, knownAddress) - am.incrementTriedAddressCount(knownAddress.subnetworkID) - return - } - - // No room, we have to evict something else. - knownAddressToRemove, knownAddressToRemoveIndex := am.pickTried(knownAddress.subnetworkID, triedAddressBucketIndex) - - // First bucket index it would have been put in. - newAddressBucketIndex := am.newAddressBucketIndex(knownAddressToRemove.netAddress, knownAddressToRemove.sourceAddress) - - // If no room in the original bucket, we put it in a bucket we just - // freed up a space in. - newAddressBucketArray := am.newAddressBucketArray(knownAddress.subnetworkID) - if len(newAddressBucketArray[newAddressBucketIndex]) >= newBucketSize { - if !oldBucketIndexFound { - // If address was a tried bucket with updated subnetworkID - oldBucketIndex will be equal to -1. - // In that case - find some non-full bucket. - // If no such bucket exists - throw knownAddressToRemove away - for newBucket := range newAddressBucketArray { - if len(newAddressBucketArray[newBucket]) < newBucketSize { - break - } - } - } else { - newAddressBucketIndex = oldBucketIndex - } - } - - // Replace with knownAddress in the slice - knownAddress.tried = true - triedAddressBucketArray[triedAddressBucketIndex][knownAddressToRemoveIndex] = knownAddress - - knownAddressToRemove.tried = false - knownAddressToRemove.referenceCount++ - - // We don't touch a.subnetworkTriedAddressCounts here since the number of tried stays the same - // but we decremented new above, raise it again since we're putting - // something back. - am.incrementNewAddressCount(knownAddress.subnetworkID) - - knownAddressToRemoveKey := NetAddressKey(knownAddressToRemove.netAddress) - log.Tracef("Replacing %s with %s in tried", knownAddressToRemoveKey, addressKey) - - // We made sure there is space here just above. - newAddressBucketArray[newAddressBucketIndex][knownAddressToRemoveKey] = knownAddressToRemove -} - -func (am *AddressManager) newAddressBucketArray(subnetworkID *externalapi.DomainSubnetworkID) *newAddressBucketArray { - if subnetworkID == nil { - return &am.fullNodeNewAddressBucketArray - } - return am.subnetworkNewAddressBucketArrays[*subnetworkID] -} - -func (am *AddressManager) triedAddressBucketArray(subnetworkID *externalapi.DomainSubnetworkID) *triedAddressBucketArray { - if subnetworkID == nil { - return &am.fullNodeTriedAddressBucketArray - } - return am.subnetworkTriedAddresBucketArrays[*subnetworkID] -} - -func (am *AddressManager) incrementNewAddressCount(subnetworkID *externalapi.DomainSubnetworkID) { - if subnetworkID == nil { - am.fullNodeNewAddressCount++ - return - } - am.subnetworkNewAddressCounts[*subnetworkID]++ -} - -func (am *AddressManager) decrementNewAddressCount(subnetworkID *externalapi.DomainSubnetworkID) { - if subnetworkID == nil { - am.fullNodeNewAddressCount-- - return - } - am.subnetworkNewAddressCounts[*subnetworkID]-- -} - -func (am *AddressManager) triedAddressCount(subnetworkID *externalapi.DomainSubnetworkID) int { - if subnetworkID == nil { - return am.fullNodeTriedAddressCount - } - return am.subnetworkTriedAddressCounts[*subnetworkID] -} - -func (am *AddressManager) newAddressCount(subnetworkID *externalapi.DomainSubnetworkID) int { - if subnetworkID == nil { - return am.fullNodeNewAddressCount - } - return am.subnetworkNewAddressCounts[*subnetworkID] -} - -func (am *AddressManager) incrementTriedAddressCount(subnetworkID *externalapi.DomainSubnetworkID) { - if subnetworkID == nil { - am.fullNodeTriedAddressCount++ - return - } - am.subnetworkTriedAddressCounts[*subnetworkID]++ -} - -// AddLocalAddress adds netAddress to the list of known local addresses to advertise -// with the given priority. -func (am *AddressManager) AddLocalAddress(netAddress *appmessage.NetAddress, priority AddressPriority) error { - if !am.IsRoutable(netAddress) { - return errors.Errorf("address %s is not routable", netAddress.IP) - } - - am.localAddressesLock.Lock() - defer am.localAddressesLock.Unlock() - - addressKey := NetAddressKey(netAddress) - address, ok := am.localAddresses[addressKey] - if !ok || address.score < priority { - if ok { - address.score = priority + 1 - } else { - am.localAddresses[addressKey] = &localAddress{ - netAddress: netAddress, - score: priority, - } - } - } - return nil -} - -// getReachabilityFrom returns the relative reachability of the provided local -// address to the provided remote address. -func (am *AddressManager) getReachabilityFrom(localAddress, remoteAddress *appmessage.NetAddress) int { - const ( - Unreachable = 0 - Default = iota - Teredo - Ipv6Weak - Ipv4 - Ipv6Strong - Private - ) - - if !am.IsRoutable(remoteAddress) { - return Unreachable - } - - if IsRFC4380(remoteAddress) { - if !am.IsRoutable(localAddress) { - return Default - } - - if IsRFC4380(localAddress) { - return Teredo - } - - if IsIPv4(localAddress) { - return Ipv4 - } - - return Ipv6Weak - } - - if IsIPv4(remoteAddress) { - if am.IsRoutable(localAddress) && IsIPv4(localAddress) { - return Ipv4 - } - return Unreachable - } - - /* ipv6 */ - var tunnelled bool - // Is our v6 is tunnelled? - if IsRFC3964(localAddress) || IsRFC6052(localAddress) || IsRFC6145(localAddress) { - tunnelled = true - } - - if !am.IsRoutable(localAddress) { - return Default - } - - if IsRFC4380(localAddress) { - return Teredo - } - - if IsIPv4(localAddress) { - return Ipv4 - } - - if tunnelled { - // only prioritise ipv6 if we aren't tunnelling it. - return Ipv6Weak - } - - return Ipv6Strong -} - -// GetBestLocalAddress returns the most appropriate local address to use +// BestLocalAddress returns the most appropriate local address to use // for the given remote address. -func (am *AddressManager) GetBestLocalAddress(remoteAddress *appmessage.NetAddress) *appmessage.NetAddress { - am.localAddressesLock.Lock() - defer am.localAddressesLock.Unlock() - - bestReach := 0 - var bestScore AddressPriority - var bestAddress *appmessage.NetAddress - for _, localAddress := range am.localAddresses { - reach := am.getReachabilityFrom(localAddress.netAddress, remoteAddress) - if reach > bestReach || - (reach == bestReach && localAddress.score > bestScore) { - bestReach = reach - bestScore = localAddress.score - bestAddress = localAddress.netAddress - } - } - if bestAddress != nil { - log.Debugf("Suggesting address %s:%d for %s:%d", bestAddress.IP, - bestAddress.Port, remoteAddress.IP, remoteAddress.Port) - } else { - log.Debugf("No worthy address for %s:%d", remoteAddress.IP, - remoteAddress.Port) - - // Send something unroutable if nothing suitable. - var ip net.IP - if !IsIPv4(remoteAddress) { - ip = net.IPv6zero - } else { - ip = net.IPv4zero - } - services := appmessage.SFNodeNetwork | appmessage.SFNodeBloom - bestAddress = appmessage.NewNetAddressIPPort(ip, 0, services) - } - - return bestAddress +func (am *AddressManager) BestLocalAddress(remoteAddress *appmessage.NetAddress) *appmessage.NetAddress { + return am.localAddresses.bestLocalAddress(remoteAddress) } // Ban marks the given address as banned func (am *AddressManager) Ban(address *appmessage.NetAddress) error { - return am.setBanned(address, true, mstime.Now()) -} + am.mutex.Lock() + defer am.mutex.Unlock() -// Unban marks the given address as not banned -func (am *AddressManager) Unban(address *appmessage.NetAddress) error { - return am.setBanned(address, false, mstime.Time{}) -} - -func (am *AddressManager) setBanned(address *appmessage.NetAddress, isBanned bool, bannedTime mstime.Time) error { - am.localAddressesLock.Lock() - defer am.localAddressesLock.Unlock() - - knownAddress := am.knownAddress(address) - if knownAddress == nil { + key := netAddressKey(address) + addressToBan, ok := am.addresses[key] + if !ok { return errors.Wrapf(ErrAddressNotFound, "address %s "+ "is not registered with the address manager", address.TCPAddress()) } - knownAddress.isBanned = isBanned - knownAddress.bannedTime = bannedTime + + delete(am.addresses, key) + am.bannedAddresses[key] = addressToBan + return nil + +} + +// Unban unmarks the given address as banned +func (am *AddressManager) Unban(address *appmessage.NetAddress) error { + am.mutex.Lock() + defer am.mutex.Unlock() + + key := netAddressKey(address) + bannedAddress, ok := am.bannedAddresses[key] + if !ok { + return errors.Wrapf(ErrAddressNotFound, "address %s "+ + "is not registered with the address manager as banned", address.TCPAddress()) + } + + delete(am.bannedAddresses, key) + am.addresses[key] = bannedAddress return nil } -// IsBanned returns whether the given address is banned +// IsBanned returns true if the given address is marked as banned func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) { - am.localAddressesLock.Lock() - defer am.localAddressesLock.Unlock() + am.mutex.Lock() + defer am.mutex.Unlock() - knownAddress := am.knownAddress(address) - if knownAddress == nil { - return false, errors.Wrapf(ErrAddressNotFound, "address %s "+ - "is not registered with the address manager", address.TCPAddress()) - } - return knownAddress.isBanned, nil -} - -// initListeners initializes the configured net listeners and adds any bound -// addresses to the address manager -func (am *AddressManager) initListeners() error { - if len(am.cfg.ExternalIPs) != 0 { - defaultPort, err := strconv.ParseUint(am.cfg.NetParams().DefaultPort, 10, 16) - if err != nil { - log.Errorf("Can not parse default port %s for active DAG: %s", - am.cfg.NetParams().DefaultPort, err) - return err - } - - for _, sip := range am.cfg.ExternalIPs { - eport := uint16(defaultPort) - host, portstr, err := net.SplitHostPort(sip) - if err != nil { - // no port, use default. - host = sip - } else { - port, err := strconv.ParseUint(portstr, 10, 16) - if err != nil { - log.Warnf("Can not parse port from %s for "+ - "externalip: %s", sip, err) - continue - } - eport = uint16(port) - } - na, err := am.HostToNetAddress(host, eport, appmessage.DefaultServices) - if err != nil { - log.Warnf("Not adding %s as externalip: %s", sip, err) - continue - } - - err = am.AddLocalAddress(na, ManualPrio) - if err != nil { - log.Warnf("Skipping specified external IP: %s", err) - } - } - } else { - // Listen for TCP connections at the configured addresses - netAddrs, err := parseListeners(am.cfg.Listeners) - if err != nil { - return err - } - - // Add bound addresses to address manager to be advertised to peers. - for _, addr := range netAddrs { - listener, err := net.Listen(addr.Network(), addr.String()) - if err != nil { - log.Warnf("Can't listen on %s: %s", addr, err) - continue - } - addr := listener.Addr().String() - err = listener.Close() - if err != nil { - return err - } - err = am.addLocalAddress(addr) - if err != nil { - log.Warnf("Skipping bound address %s: %s", addr, err) - } + key := netAddressKey(address) + if _, ok := am.bannedAddresses[key]; !ok { + if _, ok = am.addresses[key]; !ok { + return false, errors.Wrapf(ErrAddressNotFound, "address %s "+ + "is not registered with the address manager", address.TCPAddress()) } + return false, nil } - return nil + return true, nil + } - -// parseListeners determines whether each listen address is IPv4 and IPv6 and -// returns a slice of appropriate net.Addrs to listen on with TCP. It also -// properly detects addresses which apply to "all interfaces" and adds the -// address as both IPv4 and IPv6. -func parseListeners(addrs []string) ([]net.Addr, error) { - netAddrs := make([]net.Addr, 0, len(addrs)*2) - for _, addr := range addrs { - host, _, err := net.SplitHostPort(addr) - if err != nil { - // Shouldn't happen due to already being normalized. - return nil, err - } - - // Empty host or host of * on plan9 is both IPv4 and IPv6. - if host == "" || (host == "*" && runtime.GOOS == "plan9") { - netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr}) - netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr}) - continue - } - - // Strip IPv6 zone id if present since net.ParseIP does not - // handle it. - zoneIndex := strings.LastIndex(host, "%") - if zoneIndex > 0 { - host = host[:zoneIndex] - } - - // Parse the IP. - ip := net.ParseIP(host) - if ip == nil { - hostAddrs, err := net.LookupHost(host) - if err != nil { - return nil, err - } - ip = net.ParseIP(hostAddrs[0]) - if ip == nil { - return nil, errors.Errorf("Cannot resolve IP address for host '%s'", host) - } - } - - // To4 returns nil when the IP is not an IPv4 address, so use - // this determine the address type. - if ip.To4() == nil { - netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr}) - } else { - netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr}) - } - } - return netAddrs, nil -} - -// addLocalAddress adds an address that this node is listening on to the -// address manager so that it may be relayed to peers. -func (am *AddressManager) addLocalAddress(addr string) error { - host, portStr, err := net.SplitHostPort(addr) - if err != nil { - return err - } - port, err := strconv.ParseUint(portStr, 10, 16) - if err != nil { - return err - } - - if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() { - // If bound to unspecified address, advertise all local interfaces - addrs, err := net.InterfaceAddrs() - if err != nil { - return err - } - - for _, addr := range addrs { - ifaceIP, _, err := net.ParseCIDR(addr.String()) - if err != nil { - continue - } - - // If bound to 0.0.0.0, do not add IPv6 interfaces and if bound to - // ::, do not add IPv4 interfaces. - if (ip.To4() == nil) != (ifaceIP.To4() == nil) { - continue - } - - netAddr := appmessage.NewNetAddressIPPort(ifaceIP, uint16(port), appmessage.DefaultServices) - am.AddLocalAddress(netAddr, BoundPrio) - } - } else { - netAddr, err := am.HostToNetAddress(host, uint16(port), appmessage.DefaultServices) - if err != nil { - return err - } - - am.AddLocalAddress(netAddr, BoundPrio) - } - - return nil -} - -// simpleAddr implements the net.Addr interface with two struct fields -type simpleAddr struct { - net, addr string -} - -// String returns the address. -// -// This is part of the net.Addr interface. -func (a simpleAddr) String() string { - return a.addr -} - -// Network returns the network. -// -// This is part of the net.Addr interface. -func (a simpleAddr) Network() string { - return a.net -} - -// Ensure simpleAddr implements the net.Addr interface. -var _ net.Addr = simpleAddr{} diff --git a/infrastructure/network/addressmanager/addressmanager_test.go b/infrastructure/network/addressmanager/addressmanager_test.go index fae16e415..1a5564a5f 100644 --- a/infrastructure/network/addressmanager/addressmanager_test.go +++ b/infrastructure/network/addressmanager/addressmanager_test.go @@ -5,523 +5,27 @@ package addressmanager import ( - "fmt" - "io/ioutil" "net" - "reflect" "testing" - "time" - - "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - - "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/infrastructure/config" - "github.com/kaspanet/kaspad/util/mstime" - - "github.com/pkg/errors" ) -// naTest is used to describe a test to be performed against the NetAddressKey -// method. -type naTest struct { - in appmessage.NetAddress - want AddressKey -} - -// naTests houses all of the tests to be performed against the NetAddressKey -// method. -var naTests = make([]naTest, 0) - -// Put some IP in here for convenience. Points to google. -var someIP = "173.194.115.66" - -// addNaTests -func addNaTests() { - // IPv4 - // Localhost - addNaTest("127.0.0.1", 16111, "127.0.0.1:16111") - addNaTest("127.0.0.1", 16110, "127.0.0.1:16110") - - // Class A - addNaTest("1.0.0.1", 16111, "1.0.0.1:16111") - addNaTest("2.2.2.2", 16110, "2.2.2.2:16110") - addNaTest("27.253.252.251", 8335, "27.253.252.251:8335") - addNaTest("123.3.2.1", 8336, "123.3.2.1:8336") - - // Private Class A - addNaTest("10.0.0.1", 16111, "10.0.0.1:16111") - addNaTest("10.1.1.1", 16110, "10.1.1.1:16110") - addNaTest("10.2.2.2", 8335, "10.2.2.2:8335") - addNaTest("10.10.10.10", 8336, "10.10.10.10:8336") - - // Class B - addNaTest("128.0.0.1", 16111, "128.0.0.1:16111") - addNaTest("129.1.1.1", 16110, "129.1.1.1:16110") - addNaTest("180.2.2.2", 8335, "180.2.2.2:8335") - addNaTest("191.10.10.10", 8336, "191.10.10.10:8336") - - // Private Class B - addNaTest("172.16.0.1", 16111, "172.16.0.1:16111") - addNaTest("172.16.1.1", 16110, "172.16.1.1:16110") - addNaTest("172.16.2.2", 8335, "172.16.2.2:8335") - addNaTest("172.16.172.172", 8336, "172.16.172.172:8336") - - // Class C - addNaTest("193.0.0.1", 16111, "193.0.0.1:16111") - addNaTest("200.1.1.1", 16110, "200.1.1.1:16110") - addNaTest("205.2.2.2", 8335, "205.2.2.2:8335") - addNaTest("223.10.10.10", 8336, "223.10.10.10:8336") - - // Private Class C - addNaTest("192.168.0.1", 16111, "192.168.0.1:16111") - addNaTest("192.168.1.1", 16110, "192.168.1.1:16110") - addNaTest("192.168.2.2", 8335, "192.168.2.2:8335") - addNaTest("192.168.192.192", 8336, "192.168.192.192:8336") - - // IPv6 - // Localhost - addNaTest("::1", 16111, "[::1]:16111") - addNaTest("fe80::1", 16110, "[fe80::1]:16110") - - // Link-local - addNaTest("fe80::1:1", 16111, "[fe80::1:1]:16111") - addNaTest("fe91::2:2", 16110, "[fe91::2:2]:16110") - addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335") - addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336") - - // Site-local - addNaTest("fec0::1:1", 16111, "[fec0::1:1]:16111") - addNaTest("fed1::2:2", 16110, "[fed1::2:2]:16110") - addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335") - addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336") -} - -func addNaTest(ip string, port uint16, want AddressKey) { - nip := net.ParseIP(ip) - na := *appmessage.NewNetAddressIPPort(nip, port, appmessage.SFNodeNetwork) - test := naTest{na, want} - naTests = append(naTests, test) -} - -func lookupFuncForTest(host string) ([]net.IP, error) { - return nil, errors.New("not implemented") -} - -func newAddrManagerForTest(t *testing.T, testName string, - localSubnetworkID *externalapi.DomainSubnetworkID) (addressManager *AddressManager, teardown func()) { - +func newAddrManagerForTest(t *testing.T, testName string) (addressManager *AddressManager, teardown func()) { cfg := config.DefaultConfig() - cfg.SubnetworkID = localSubnetworkID - dbPath, err := ioutil.TempDir("", testName) - if err != nil { - t.Fatalf("Error creating temporary directory: %s", err) - } - - databaseContext, err := ldb.NewLevelDB(dbPath) - if err != nil { - t.Fatalf("error creating db: %s", err) - } - - addressManager, err = New(cfg, databaseContext) + addressManager, err := New(NewConfig(cfg)) if err != nil { t.Fatalf("error creating address manager: %s", err) } return addressManager, func() { - err := databaseContext.Close() - if err != nil { - t.Fatalf("error closing the database: %s", err) - } } } -func TestStartStop(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestStartStop", nil) - defer teardown() - err := amgr.Start() - if err != nil { - t.Fatalf("Address Manager failed to start: %v", err) - } - err = amgr.Stop() - if err != nil { - t.Fatalf("Address Manager failed to stop: %v", err) - } -} - -func TestAddAddressByIP(t *testing.T) { - fmtErr := errors.Errorf("") - addrErr := &net.AddrError{} - var tests = []struct { - addrIP string - err error - }{ - { - someIP + ":16111", - nil, - }, - { - someIP, - addrErr, - }, - { - someIP[:12] + ":8333", - fmtErr, - }, - { - someIP + ":abcd", - fmtErr, - }, - } - - amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil) - defer teardown() - for i, test := range tests { - err := AddAddressByIP(amgr, test.addrIP, nil) - if test.err != nil && err == nil { - t.Errorf("TestAddAddressByIP test %d failed expected an error and got none", i) - continue - } - if test.err == nil && err != nil { - t.Errorf("TestAddAddressByIP test %d failed expected no error and got one", i) - continue - } - if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("TestAddAddressByIP test %d failed got %v, want %v", i, - reflect.TypeOf(err), reflect.TypeOf(test.err)) - continue - } - } -} - -func TestAddLocalAddress(t *testing.T) { - var tests = []struct { - address appmessage.NetAddress - priority AddressPriority - valid bool - }{ - { - appmessage.NetAddress{IP: net.ParseIP("192.168.0.100")}, - InterfacePrio, - false, - }, - { - appmessage.NetAddress{IP: net.ParseIP("204.124.1.1")}, - InterfacePrio, - true, - }, - { - appmessage.NetAddress{IP: net.ParseIP("204.124.1.1")}, - BoundPrio, - true, - }, - { - appmessage.NetAddress{IP: net.ParseIP("::1")}, - InterfacePrio, - false, - }, - { - appmessage.NetAddress{IP: net.ParseIP("fe80::1")}, - InterfacePrio, - false, - }, - { - appmessage.NetAddress{IP: net.ParseIP("2620:100::1")}, - InterfacePrio, - true, - }, - } - amgr, teardown := newAddrManagerForTest(t, "TestAddLocalAddress", nil) - defer teardown() - for x, test := range tests { - result := amgr.AddLocalAddress(&test.address, test.priority) - if result == nil && !test.valid { - t.Errorf("TestAddLocalAddress test #%d failed: %s should have "+ - "been accepted", x, test.address.IP) - continue - } - if result != nil && test.valid { - t.Errorf("TestAddLocalAddress test #%d failed: %s should not have "+ - "been accepted", x, test.address.IP) - continue - } - } -} - -func TestAttempt(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestAttempt", nil) - defer teardown() - - // Add a new address and get it - err := AddAddressByIP(amgr, someIP+":8333", nil) - if err != nil { - t.Fatalf("Adding address failed: %v", err) - } - ka := amgr.GetAddress() - - if !ka.LastAttempt().IsZero() { - t.Errorf("Address should not have attempts, but does") - } - - na := ka.NetAddress() - amgr.Attempt(na) - - if ka.LastAttempt().IsZero() { - t.Errorf("Address should have an attempt, but does not") - } -} - -func TestConnected(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestConnected", nil) - defer teardown() - - // Add a new address and get it - err := AddAddressByIP(amgr, someIP+":8333", nil) - if err != nil { - t.Fatalf("Adding address failed: %v", err) - } - ka := amgr.GetAddress() - na := ka.NetAddress() - // make it an hour ago - na.Timestamp = mstime.Now().Add(time.Hour * -1) - - amgr.Connected(na) - - if !ka.NetAddress().Timestamp.After(na.Timestamp) { - t.Errorf("Address should have a new timestamp, but does not") - } -} - -func TestNeedMoreAddresses(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestNeedMoreAddresses", nil) - defer teardown() - addrsToAdd := 1500 - b := amgr.NeedMoreAddresses() - if !b { - t.Errorf("Expected that we need more addresses") - } - addrs := make([]*appmessage.NetAddress, addrsToAdd) - - var err error - for i := 0; i < addrsToAdd; i++ { - s := AddressKey(fmt.Sprintf("%d.%d.173.147:8333", i/128+60, i%128+60)) - addrs[i], err = amgr.DeserializeNetAddress(s) - if err != nil { - t.Errorf("Failed to turn %s into an address: %v", s, err) - } - } - - srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0) - - amgr.AddAddresses(addrs, srcAddr, nil) - numAddrs := amgr.TotalNumAddresses() - if numAddrs > addrsToAdd { - t.Errorf("Number of addresses is too many %d vs %d", numAddrs, addrsToAdd) - } - - b = amgr.NeedMoreAddresses() - if b { - t.Errorf("Expected that we don't need more addresses") - } -} - -func TestGood(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestGood", nil) - defer teardown() - addrsToAdd := 64 * 64 - addrs := make([]*appmessage.NetAddress, addrsToAdd) - subnetworkCount := 32 - subnetworkIDs := make([]*externalapi.DomainSubnetworkID, subnetworkCount) - - var err error - for i := 0; i < addrsToAdd; i++ { - s := AddressKey(fmt.Sprintf("%d.173.147.%d:8333", i/64+60, i%64+60)) - addrs[i], err = amgr.DeserializeNetAddress(s) - if err != nil { - t.Errorf("Failed to turn %s into an address: %v", s, err) - } - } - - for i := 0; i < subnetworkCount; i++ { - subnetworkIDs[i] = &externalapi.DomainSubnetworkID{0xff - byte(i)} - } - - srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0) - - amgr.AddAddresses(addrs, srcAddr, nil) - for i, addr := range addrs { - amgr.Good(addr, subnetworkIDs[i%subnetworkCount]) - } - - numAddrs := amgr.TotalNumAddresses() - if numAddrs >= addrsToAdd { - t.Errorf("Number of addresses is too many: %d vs %d", numAddrs, addrsToAdd) - } - - numCache := len(amgr.AddressCache(true, nil)) - if numCache == 0 || numCache >= numAddrs/4 { - t.Errorf("Number of addresses in cache: got %d, want positive and less than %d", - numCache, numAddrs/4) - } - - for i := 0; i < subnetworkCount; i++ { - numCache = len(amgr.AddressCache(false, subnetworkIDs[i])) - if numCache == 0 || numCache >= numAddrs/subnetworkCount { - t.Errorf("Number of addresses in subnetwork cache: got %d, want positive and less than %d", - numCache, numAddrs/4/subnetworkCount) - } - } -} - -func TestGoodChangeSubnetworkID(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestGoodChangeSubnetworkID", nil) - defer teardown() - addr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0) - addrKey := NetAddressKey(addr) - srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0) - - oldSubnetwork := &subnetworks.SubnetworkIDNative - amgr.AddAddress(addr, srcAddr, oldSubnetwork) - amgr.Good(addr, oldSubnetwork) - - // make sure address was saved to addressIndex under oldSubnetwork - ka := amgr.knownAddress(addr) - if ka == nil { - t.Fatalf("Address was not found after first time .Good called") - } - if *ka.SubnetworkID() != *oldSubnetwork { - t.Fatalf("Address index did not point to oldSubnetwork") - } - - // make sure address was added to correct bucket under oldSubnetwork - bucket := amgr.subnetworkTriedAddresBucketArrays[*oldSubnetwork][amgr.triedAddressBucketIndex(addr)] - wasFound := false - for _, ka := range bucket { - if NetAddressKey(ka.NetAddress()) == addrKey { - wasFound = true - } - } - if !wasFound { - t.Fatalf("Address was not found in the correct bucket in oldSubnetwork") - } - - // now call .Good again with a different subnetwork - newSubnetwork := &subnetworks.SubnetworkIDRegistry - amgr.Good(addr, newSubnetwork) - - // make sure address was updated in addressIndex under newSubnetwork - ka = amgr.knownAddress(addr) - if ka == nil { - t.Fatalf("Address was not found after second time .Good called") - } - if *ka.SubnetworkID() != *newSubnetwork { - t.Fatalf("Address index did not point to newSubnetwork") - } - - // make sure address was removed from bucket under oldSubnetwork - bucket = amgr.subnetworkTriedAddresBucketArrays[*oldSubnetwork][amgr.triedAddressBucketIndex(addr)] - wasFound = false - for _, ka := range bucket { - if NetAddressKey(ka.NetAddress()) == addrKey { - wasFound = true - } - } - if wasFound { - t.Fatalf("Address was not removed from bucket in oldSubnetwork") - } - - // make sure address was added to correct bucket under newSubnetwork - bucket = amgr.subnetworkTriedAddresBucketArrays[*newSubnetwork][amgr.triedAddressBucketIndex(addr)] - wasFound = false - for _, ka := range bucket { - if NetAddressKey(ka.NetAddress()) == addrKey { - wasFound = true - } - } - if !wasFound { - t.Fatalf("Address was not found in the correct bucket in newSubnetwork") - } -} - -func TestGetAddress(t *testing.T) { - localSubnetworkID := &externalapi.DomainSubnetworkID{0xff} - amgr, teardown := newAddrManagerForTest(t, "TestGetAddress", localSubnetworkID) - defer teardown() - - // Get an address from an empty set (should error) - if rv := amgr.GetAddress(); rv != nil { - t.Errorf("GetAddress failed: got: %v want: %v\n", rv, nil) - } - - // Add a new address and get it - err := AddAddressByIP(amgr, someIP+":8332", localSubnetworkID) - if err != nil { - t.Fatalf("Adding address failed: %v", err) - } - ka := amgr.GetAddress() - if ka == nil { - t.Fatalf("Did not get an address where there is one in the pool") - } - amgr.Attempt(ka.NetAddress()) - - // Checks that we don't get it if we find that it has other subnetwork ID than expected. - actualSubnetworkID := &externalapi.DomainSubnetworkID{0xfe} - amgr.Good(ka.NetAddress(), actualSubnetworkID) - ka = amgr.GetAddress() - if ka != nil { - t.Errorf("Didn't expect to get an address because there shouldn't be any address from subnetwork ID %s or nil", localSubnetworkID) - } - - // Checks that the total number of addresses incremented although the new address is not full node or a partial node of the same subnetwork as the local node. - numAddrs := amgr.TotalNumAddresses() - if numAddrs != 1 { - t.Errorf("Wrong number of addresses: got %d, want %d", numAddrs, 1) - } - - // Now we repeat the same process, but now the address has the expected subnetwork ID. - - // Add a new address and get it - err = AddAddressByIP(amgr, someIP+":8333", localSubnetworkID) - if err != nil { - t.Fatalf("Adding address failed: %v", err) - } - ka = amgr.GetAddress() - if ka == nil { - t.Fatalf("Did not get an address where there is one in the pool") - } - if ka.NetAddress().IP.String() != someIP { - t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP) - } - if *ka.SubnetworkID() != *localSubnetworkID { - t.Errorf("Wrong Subnetwork ID: got %v, want %v", *ka.SubnetworkID(), localSubnetworkID) - } - amgr.Attempt(ka.NetAddress()) - - // Mark this as a good address and get it - amgr.Good(ka.NetAddress(), localSubnetworkID) - ka = amgr.GetAddress() - if ka == nil { - t.Fatalf("Did not get an address where there is one in the pool") - } - if ka.NetAddress().IP.String() != someIP { - t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP) - } - if *ka.SubnetworkID() != *localSubnetworkID { - t.Errorf("Wrong Subnetwork ID: got %v, want %v", ka.SubnetworkID(), localSubnetworkID) - } - - numAddrs = amgr.TotalNumAddresses() - if numAddrs != 2 { - t.Errorf("Wrong number of addresses: got %d, want %d", numAddrs, 1) - } -} - -func TestGetBestLocalAddress(t *testing.T) { +func TestBestLocalAddress(t *testing.T) { localAddrs := []appmessage.NetAddress{ {IP: net.ParseIP("192.168.0.100")}, {IP: net.ParseIP("::1")}, @@ -562,12 +66,12 @@ func TestGetBestLocalAddress(t *testing.T) { }, } - amgr, teardown := newAddrManagerForTest(t, "TestGetBestLocalAddress", nil) + amgr, teardown := newAddrManagerForTest(t, "TestGetBestLocalAddress") defer teardown() // Test against default when there's no address for x, test := range tests { - got := amgr.GetBestLocalAddress(&test.remoteAddr) + got := amgr.BestLocalAddress(&test.remoteAddr) if !test.want0.IP.Equal(got.IP) { t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s", x, test.remoteAddr.IP, test.want1.IP, got.IP) @@ -576,12 +80,12 @@ func TestGetBestLocalAddress(t *testing.T) { } for _, localAddr := range localAddrs { - amgr.AddLocalAddress(&localAddr, InterfacePrio) + amgr.localAddresses.addLocalNetAddress(&localAddr, InterfacePrio) } // Test against want1 for x, test := range tests { - got := amgr.GetBestLocalAddress(&test.remoteAddr) + got := amgr.BestLocalAddress(&test.remoteAddr) if !test.want1.IP.Equal(got.IP) { t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s", x, test.remoteAddr.IP, test.want1.IP, got.IP) @@ -591,42 +95,15 @@ func TestGetBestLocalAddress(t *testing.T) { // Add a public IP to the list of local addresses. localAddr := appmessage.NetAddress{IP: net.ParseIP("204.124.8.100")} - amgr.AddLocalAddress(&localAddr, InterfacePrio) + amgr.localAddresses.addLocalNetAddress(&localAddr, InterfacePrio) // Test against want2 for x, test := range tests { - got := amgr.GetBestLocalAddress(&test.remoteAddr) + got := amgr.BestLocalAddress(&test.remoteAddr) if !test.want2.IP.Equal(got.IP) { t.Errorf("TestGetBestLocalAddress test2 #%d failed for remote address %s: want %s got %s", x, test.remoteAddr.IP, test.want2.IP, got.IP) continue } } - /* - // Add a Tor generated IP address - localAddr = appmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")} - amgr.AddLocalAddress(&localAddr, ManualPrio) - // Test against want3 - for x, test := range tests { - got := amgr.GetBestLocalAddress(&test.remoteAddr) - if !test.want3.IP.Equal(got.IP) { - t.Errorf("TestGetBestLocalAddress test3 #%d failed for remote address %s: want %s got %s", - x, test.remoteAddr.IP, test.want3.IP, got.IP) - continue - } - } - */ -} - -func TestNetAddressKey(t *testing.T) { - addNaTests() - - t.Logf("Running %d tests", len(naTests)) - for i, test := range naTests { - key := NetAddressKey(&test.in) - if key != test.want { - t.Errorf("NetAddressKey #%d\n got: %s want: %s", i, key, test.want) - continue - } - } } diff --git a/infrastructure/network/addressmanager/addressrandomize.go b/infrastructure/network/addressmanager/addressrandomize.go new file mode 100644 index 000000000..35c296293 --- /dev/null +++ b/infrastructure/network/addressmanager/addressrandomize.go @@ -0,0 +1,43 @@ +package addressmanager + +import ( + "math/rand" + "time" + + "github.com/kaspanet/kaspad/app/appmessage" +) + +// AddressRandomize implement AddressRandomizer interface +type AddressRandomize struct { + random *rand.Rand +} + +// NewAddressRandomize returns a new RandomizeAddress. +func NewAddressRandomize() *AddressRandomize { + return &AddressRandomize{ + random: rand.New(rand.NewSource(time.Now().UnixNano())), + } +} + +// RandomAddress returns a random address from input list +func (amc *AddressRandomize) RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress { + if len(addresses) > 0 { + randomIndex := rand.Intn(len(addresses)) + return addresses[randomIndex] + } + + return nil +} + +// RandomAddresses returns count addresses at random from input list +func (amc *AddressRandomize) RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress { + result := make([]*appmessage.NetAddress, 0, count) + if len(addresses) > 0 { + randomIndexes := rand.Perm(len(addresses)) + for i := 0; i < count; i++ { + result = append(result, addresses[randomIndexes[i]]) + } + } + + return result +} diff --git a/infrastructure/network/addressmanager/config.go b/infrastructure/network/addressmanager/config.go new file mode 100644 index 000000000..3e707044c --- /dev/null +++ b/infrastructure/network/addressmanager/config.go @@ -0,0 +1,27 @@ +package addressmanager + +import ( + "net" + + "github.com/kaspanet/kaspad/infrastructure/config" +) + +// Config is a descriptor which specifies the AddressManager instance configuration. +type Config struct { + AcceptUnroutable bool + DefaultPort string + ExternalIPs []string + Listeners []string + Lookup func(string) ([]net.IP, error) +} + +// NewConfig returns a new address manager Config. +func NewConfig(cfg *config.Config) *Config { + return &Config{ + AcceptUnroutable: cfg.NetParams().AcceptUnroutable, + DefaultPort: cfg.NetParams().DefaultPort, + ExternalIPs: cfg.ExternalIPs, + Listeners: cfg.Listeners, + Lookup: cfg.Lookup, + } +} diff --git a/infrastructure/network/addressmanager/internal_test.go b/infrastructure/network/addressmanager/internal_test.go deleted file mode 100644 index 51500f26f..000000000 --- a/infrastructure/network/addressmanager/internal_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package addressmanager - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/util/mstime" -) - -func TstKnownAddressIsBad(ka *KnownAddress) bool { - return ka.isBad() -} - -func TstKnownAddressChance(ka *KnownAddress) float64 { - return ka.chance() -} - -func TstNewKnownAddress(na *appmessage.NetAddress, attempts int, - lastattempt, lastsuccess mstime.Time, tried bool, refs int) *KnownAddress { - return &KnownAddress{netAddress: na, attempts: attempts, lastAttempt: lastattempt, - lastSuccess: lastsuccess, tried: tried, referenceCount: refs} -} diff --git a/infrastructure/network/addressmanager/knownaddress.go b/infrastructure/network/addressmanager/knownaddress.go deleted file mode 100644 index cb2f68257..000000000 --- a/infrastructure/network/addressmanager/knownaddress.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2013-2014 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package addressmanager - -import ( - "time" - - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util/mstime" -) - -// KnownAddress tracks information about a known network address that is used -// to determine how viable an address is. -type KnownAddress struct { - netAddress *appmessage.NetAddress - sourceAddress *appmessage.NetAddress - attempts int - lastAttempt mstime.Time - lastSuccess mstime.Time - tried bool - referenceCount int // reference count of new buckets - subnetworkID *externalapi.DomainSubnetworkID - isBanned bool - bannedTime mstime.Time -} - -// NetAddress returns the underlying appmessage.NetAddress associated with the -// known address. -func (ka *KnownAddress) NetAddress() *appmessage.NetAddress { - return ka.netAddress -} - -// SubnetworkID returns the subnetwork ID of the known address. -func (ka *KnownAddress) SubnetworkID() *externalapi.DomainSubnetworkID { - return ka.subnetworkID -} - -// LastAttempt returns the last time the known address was attempted. -func (ka *KnownAddress) LastAttempt() mstime.Time { - return ka.lastAttempt -} - -// chance returns the selection probability for a known address. The priority -// depends upon how recently the address has been seen, how recently it was last -// attempted and how often attempts to connect to it have failed. -func (ka *KnownAddress) chance() float64 { - now := mstime.Now() - lastAttempt := now.Sub(ka.lastAttempt) - - if lastAttempt < 0 { - lastAttempt = 0 - } - - c := 1.0 - - // Very recent attempts are less likely to be retried. - if lastAttempt < 10*time.Minute { - c *= 0.01 - } - - // Failed attempts deprioritise. - for i := ka.attempts; i > 0; i-- { - c /= 1.5 - } - - return c -} - -// isBad returns true if the address in question has not been tried in the last -// minute and meets one of the following criteria: -// 1) It claims to be from the future -// 2) It hasn't been seen in over a month -// 3) It has failed at least three times and never succeeded -// 4) It has failed ten times in the last week -// All addresses that meet these criteria are assumed to be worthless and not -// worth keeping hold of. -func (ka *KnownAddress) isBad() bool { - if ka.lastAttempt.After(mstime.Now().Add(-1 * time.Minute)) { - return false - } - - // From the future? - if ka.netAddress.Timestamp.After(mstime.Now().Add(10 * time.Minute)) { - return true - } - - // Over a month old? - if ka.netAddress.Timestamp.Before(mstime.Now().Add(-1 * numMissingDays * time.Hour * 24)) { - return true - } - - // Never succeeded? - if ka.lastSuccess.IsZero() && ka.attempts >= numRetries { - return true - } - - // Hasn't succeeded in too long? - if !ka.lastSuccess.After(mstime.Now().Add(-1*minBadDays*time.Hour*24)) && - ka.attempts >= maxFailures { - return true - } - - return false -} diff --git a/infrastructure/network/addressmanager/knownaddress_test.go b/infrastructure/network/addressmanager/knownaddress_test.go deleted file mode 100644 index 5a439d5a4..000000000 --- a/infrastructure/network/addressmanager/knownaddress_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package addressmanager_test - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/util/mstime" - "math" - "testing" - "time" - - "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" -) - -func TestChance(t *testing.T) { - now := mstime.Now() - var tests = []struct { - addr *addressmanager.KnownAddress - expected float64 - }{ - { - //Test normal case - addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)}, - 0, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0), - 1.0, - }, { - //Test case in which lastseen < 0 - addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(20 * time.Second)}, - 0, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0), - 1.0, - }, { - //Test case in which lastAttempt < 0 - addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)}, - 0, mstime.Now().Add(30*time.Minute), mstime.Now(), false, 0), - 1.0 * .01, - }, { - //Test case in which lastAttempt < ten minutes - addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)}, - 0, mstime.Now().Add(-5*time.Minute), mstime.Now(), false, 0), - 1.0 * .01, - }, { - //Test case with several failed attempts. - addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)}, - 2, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0), - 1 / 1.5 / 1.5, - }, - } - - err := .0001 - for i, test := range tests { - chance := addressmanager.TstKnownAddressChance(test.addr) - if math.Abs(test.expected-chance) >= err { - t.Errorf("case %d: got %f, expected %f", i, chance, test.expected) - } - } -} - -func TestIsBad(t *testing.T) { - now := mstime.Now() - future := now.Add(35 * time.Minute) - monthOld := now.Add(-43 * time.Hour * 24) - secondsOld := now.Add(-2 * time.Second) - minutesOld := now.Add(-27 * time.Minute) - hoursOld := now.Add(-5 * time.Hour) - zeroTime := mstime.Time{} - - futureNa := &appmessage.NetAddress{Timestamp: future} - minutesOldNa := &appmessage.NetAddress{Timestamp: minutesOld} - monthOldNa := &appmessage.NetAddress{Timestamp: monthOld} - currentNa := &appmessage.NetAddress{Timestamp: secondsOld} - - //Test addresses that have been tried in the last minute. - if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(futureNa, 3, secondsOld, zeroTime, false, 0)) { - t.Errorf("test case 1: addresses that have been tried in the last minute are not bad.") - } - if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(monthOldNa, 3, secondsOld, zeroTime, false, 0)) { - t.Errorf("test case 2: addresses that have been tried in the last minute are not bad.") - } - if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(currentNa, 3, secondsOld, zeroTime, false, 0)) { - t.Errorf("test case 3: addresses that have been tried in the last minute are not bad.") - } - if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(currentNa, 3, secondsOld, monthOld, true, 0)) { - t.Errorf("test case 4: addresses that have been tried in the last minute are not bad.") - } - if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(currentNa, 2, secondsOld, secondsOld, true, 0)) { - t.Errorf("test case 5: addresses that have been tried in the last minute are not bad.") - } - - //Test address that claims to be from the future. - if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(futureNa, 0, minutesOld, hoursOld, true, 0)) { - t.Errorf("test case 6: addresses that claim to be from the future are bad.") - } - - //Test address that has not been seen in over a month. - if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(monthOldNa, 0, minutesOld, hoursOld, true, 0)) { - t.Errorf("test case 7: addresses more than a month old are bad.") - } - - //It has failed at least three times and never succeeded. - if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(minutesOldNa, 3, minutesOld, zeroTime, true, 0)) { - t.Errorf("test case 8: addresses that have never succeeded are bad.") - } - - //It has failed ten times in the last week - if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(minutesOldNa, 10, minutesOld, monthOld, true, 0)) { - t.Errorf("test case 9: addresses that have not succeeded in too long are bad.") - } - - //Test an address that should work. - if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(minutesOldNa, 2, minutesOld, hoursOld, true, 0)) { - t.Errorf("test case 10: This should be a valid address.") - } -} diff --git a/infrastructure/network/addressmanager/localaddressmanager.go b/infrastructure/network/addressmanager/localaddressmanager.go new file mode 100644 index 000000000..d9274a432 --- /dev/null +++ b/infrastructure/network/addressmanager/localaddressmanager.go @@ -0,0 +1,400 @@ +package addressmanager + +import ( + "net" + "runtime" + "strconv" + "strings" + "sync" + + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/pkg/errors" +) + +// AddressPriority type is used to describe the hierarchy of local address +// discovery methods. +type AddressPriority int + +const ( + // InterfacePrio signifies the address is on a local interface + InterfacePrio AddressPriority = iota + + // BoundPrio signifies the address has been explicitly bounded to. + BoundPrio + + // UpnpPrio signifies the address was obtained from UPnP. + UpnpPrio + + // HTTPPrio signifies the address was obtained from an external HTTP service. + HTTPPrio + + // ManualPrio signifies the address was provided by --externalip. + ManualPrio +) + +type localAddress struct { + netAddress *appmessage.NetAddress + score AddressPriority +} + +type localAddressManager struct { + localAddresses map[AddressKey]*localAddress + lookupFunc func(string) ([]net.IP, error) + cfg *Config + mutex sync.Mutex +} + +func newLocalAddressManager(cfg *Config) (*localAddressManager, error) { + localAddressManager := localAddressManager{ + localAddresses: map[AddressKey]*localAddress{}, + cfg: cfg, + lookupFunc: cfg.Lookup, + } + + err := localAddressManager.initListeners() + if err != nil { + return nil, err + } + + return &localAddressManager, nil +} + +// addLocalNetAddress adds netAddress to the list of known local addresses to advertise +// with the given priority. +func (lam *localAddressManager) addLocalNetAddress(netAddress *appmessage.NetAddress, priority AddressPriority) error { + if !IsRoutable(netAddress, lam.cfg.AcceptUnroutable) { + return errors.Errorf("address %s is not routable", netAddress.IP) + } + + lam.mutex.Lock() + defer lam.mutex.Unlock() + + addressKey := netAddressKey(netAddress) + address, ok := lam.localAddresses[addressKey] + if !ok || address.score < priority { + if ok { + address.score = priority + 1 + } else { + lam.localAddresses[addressKey] = &localAddress{ + netAddress: netAddress, + score: priority, + } + } + } + return nil +} + +// bestLocalAddress returns the most appropriate local address to use +// for the given remote address. +func (lam *localAddressManager) bestLocalAddress(remoteAddress *appmessage.NetAddress) *appmessage.NetAddress { + lam.mutex.Lock() + defer lam.mutex.Unlock() + + bestReach := 0 + var bestScore AddressPriority + var bestAddress *appmessage.NetAddress + for _, localAddress := range lam.localAddresses { + reach := reachabilityFrom(localAddress.netAddress, remoteAddress, lam.cfg.AcceptUnroutable) + if reach > bestReach || + (reach == bestReach && localAddress.score > bestScore) { + bestReach = reach + bestScore = localAddress.score + bestAddress = localAddress.netAddress + } + } + + if bestAddress == nil { + // Send something unroutable if nothing suitable. + var ip net.IP + if !IsIPv4(remoteAddress) { + ip = net.IPv6zero + } else { + ip = net.IPv4zero + } + services := appmessage.SFNodeNetwork | appmessage.SFNodeBloom + bestAddress = appmessage.NewNetAddressIPPort(ip, 0, services) + } + + return bestAddress +} + +// addLocalAddress adds an address that this node is listening on to the +// address manager so that it may be relayed to peers. +func (lam *localAddressManager) addLocalAddress(addr string) error { + host, portStr, err := net.SplitHostPort(addr) + if err != nil { + return err + } + port, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + return err + } + + if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() { + // If bound to unspecified address, advertise all local interfaces + addrs, err := net.InterfaceAddrs() + if err != nil { + return err + } + + for _, addr := range addrs { + ifaceIP, _, err := net.ParseCIDR(addr.String()) + if err != nil { + continue + } + + // If bound to 0.0.0.0, do not add IPv6 interfaces and if bound to + // ::, do not add IPv4 interfaces. + if (ip.To4() == nil) != (ifaceIP.To4() == nil) { + continue + } + + netAddr := appmessage.NewNetAddressIPPort(ifaceIP, uint16(port), appmessage.DefaultServices) + lam.addLocalNetAddress(netAddr, BoundPrio) + } + } else { + netAddr, err := lam.hostToNetAddress(host, uint16(port), appmessage.DefaultServices) + if err != nil { + return err + } + + lam.addLocalNetAddress(netAddr, BoundPrio) + } + + return nil +} + +// initListeners initializes the configured net listeners and adds any bound +// addresses to the address manager +func (lam *localAddressManager) initListeners() error { + if len(lam.cfg.ExternalIPs) != 0 { + defaultPort, err := strconv.ParseUint(lam.cfg.DefaultPort, 10, 16) + if err != nil { + log.Errorf("Can not parse default port %s for active DAG: %s", + lam.cfg.DefaultPort, err) + return err + } + + for _, sip := range lam.cfg.ExternalIPs { + eport := uint16(defaultPort) + host, portstr, err := net.SplitHostPort(sip) + if err != nil { + // no port, use default. + host = sip + } else { + port, err := strconv.ParseUint(portstr, 10, 16) + if err != nil { + log.Warnf("Can not parse port from %s for "+ + "externalip: %s", sip, err) + continue + } + eport = uint16(port) + } + na, err := lam.hostToNetAddress(host, eport, appmessage.DefaultServices) + if err != nil { + log.Warnf("Not adding %s as externalip: %s", sip, err) + continue + } + + err = lam.addLocalNetAddress(na, ManualPrio) + if err != nil { + log.Warnf("Skipping specified external IP: %s", err) + } + } + } else { + // Listen for TCP connections at the configured addresses + netAddrs, err := parseListeners(lam.cfg.Listeners) + if err != nil { + return err + } + + // Add bound addresses to address manager to be advertised to peers. + for _, addr := range netAddrs { + listener, err := net.Listen(addr.Network(), addr.String()) + if err != nil { + log.Warnf("Can't listen on %s: %s", addr, err) + continue + } + addr := listener.Addr().String() + err = listener.Close() + if err != nil { + return err + } + err = lam.addLocalAddress(addr) + if err != nil { + log.Warnf("Skipping bound address %s: %s", addr, err) + } + } + } + + return nil +} + +// hostToNetAddress returns a netaddress given a host address. If +// the host is not an IP address it will be resolved. +func (lam *localAddressManager) hostToNetAddress(host string, port uint16, services appmessage.ServiceFlag) (*appmessage.NetAddress, error) { + ip := net.ParseIP(host) + if ip == nil { + ips, err := lam.lookupFunc(host) + if err != nil { + return nil, err + } + if len(ips) == 0 { + return nil, errors.Errorf("no addresses found for %s", host) + } + ip = ips[0] + } + + return appmessage.NewNetAddressIPPort(ip, port, services), nil +} + +// parseListeners determines whether each listen address is IPv4 and IPv6 and +// returns a slice of appropriate net.Addrs to listen on with TCP. It also +// properly detects addresses which apply to "all interfaces" and adds the +// address as both IPv4 and IPv6. +func parseListeners(addrs []string) ([]net.Addr, error) { + netAddrs := make([]net.Addr, 0, len(addrs)*2) + for _, addr := range addrs { + host, _, err := net.SplitHostPort(addr) + if err != nil { + // Shouldn't happen due to already being normalized. + return nil, err + } + + // Empty host or host of * on plan9 is both IPv4 and IPv6. + if host == "" || (host == "*" && runtime.GOOS == "plan9") { + netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr}) + netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr}) + continue + } + + // Strip IPv6 zone id if present since net.ParseIP does not + // handle it. + zoneIndex := strings.LastIndex(host, "%") + if zoneIndex > 0 { + host = host[:zoneIndex] + } + + // Parse the IP. + ip := net.ParseIP(host) + if ip == nil { + hostAddrs, err := net.LookupHost(host) + if err != nil { + return nil, err + } + ip = net.ParseIP(hostAddrs[0]) + if ip == nil { + return nil, errors.Errorf("Cannot resolve IP address for host '%s'", host) + } + } + + // To4 returns nil when the IP is not an IPv4 address, so use + // this determine the address type. + if ip.To4() == nil { + netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr}) + } else { + netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr}) + } + } + return netAddrs, nil +} + +// reachabilityFrom returns the relative reachability of the provided local +// address to the provided remote address. +func reachabilityFrom(localAddress, remoteAddress *appmessage.NetAddress, acceptUnroutable bool) int { + const ( + Unreachable = 0 + Default = iota + Teredo + Ipv6Weak + Ipv4 + Ipv6Strong + Private + ) + + IsRoutable := func(na *appmessage.NetAddress) bool { + if acceptUnroutable { + return !IsLocal(na) + } + + return IsValid(na) && !(IsRFC1918(na) || IsRFC2544(na) || + IsRFC3927(na) || IsRFC4862(na) || IsRFC3849(na) || + IsRFC4843(na) || IsRFC5737(na) || IsRFC6598(na) || + IsLocal(na) || (IsRFC4193(na))) + } + + if !IsRoutable(remoteAddress) { + return Unreachable + } + + if IsRFC4380(remoteAddress) { + if !IsRoutable(localAddress) { + return Default + } + + if IsRFC4380(localAddress) { + return Teredo + } + + if IsIPv4(localAddress) { + return Ipv4 + } + + return Ipv6Weak + } + + if IsIPv4(remoteAddress) { + if IsRoutable(localAddress) && IsIPv4(localAddress) { + return Ipv4 + } + return Unreachable + } + + /* ipv6 */ + var tunnelled bool + // Is our v6 is tunnelled? + if IsRFC3964(localAddress) || IsRFC6052(localAddress) || IsRFC6145(localAddress) { + tunnelled = true + } + + if !IsRoutable(localAddress) { + return Default + } + + if IsRFC4380(localAddress) { + return Teredo + } + + if IsIPv4(localAddress) { + return Ipv4 + } + + if tunnelled { + // only prioritise ipv6 if we aren't tunnelling it. + return Ipv6Weak + } + + return Ipv6Strong +} + +// simpleAddr implements the net.Addr interface with two struct fields +type simpleAddr struct { + net, addr string +} + +// String returns the address. +// +// This is part of the net.Addr interface. +func (a simpleAddr) String() string { + return a.addr +} + +// Network returns the network. +// +// This is part of the net.Addr interface. +func (a simpleAddr) Network() string { + return a.net +} + +// Ensure simpleAddr implements the net.Addr interface. +var _ net.Addr = simpleAddr{} diff --git a/infrastructure/network/addressmanager/network.go b/infrastructure/network/addressmanager/network.go index 262409354..acdd94fee 100644 --- a/infrastructure/network/addressmanager/network.go +++ b/infrastructure/network/addressmanager/network.go @@ -5,8 +5,9 @@ package addressmanager import ( - "github.com/kaspanet/kaspad/app/appmessage" "net" + + "github.com/kaspanet/kaspad/app/appmessage" ) var ( @@ -77,6 +78,13 @@ var ( heNet = ipNet("2001:470::", 32, 128) ) +const ( + // GetAddressesMax is the most addresses that we will send in response + // to a getAddress (in practise the most addresses we will return from a + // call to AddressCache()). + GetAddressesMax = 2500 +) + // ipNet returns a net.IPNet struct given the passed IP address string, number // of one bits to include at the start of the mask, and the total number of bits // for the mask. @@ -199,8 +207,8 @@ func IsValid(na *appmessage.NetAddress) bool { // IsRoutable returns whether or not the passed address is routable over // the public internet. This is true as long as the address is valid and is not // in any reserved ranges. -func (am *AddressManager) IsRoutable(na *appmessage.NetAddress) bool { - if am.cfg.NetParams().AcceptUnroutable { +func IsRoutable(na *appmessage.NetAddress, acceptUnroutable bool) bool { + if acceptUnroutable { return !IsLocal(na) } @@ -218,7 +226,7 @@ func (am *AddressManager) GroupKey(na *appmessage.NetAddress) string { if IsLocal(na) { return "local" } - if !am.IsRoutable(na) { + if !IsRoutable(na, am.cfg.AcceptUnroutable) { return "unroutable" } if IsIPv4(na) { diff --git a/infrastructure/network/addressmanager/network_test.go b/infrastructure/network/addressmanager/network_test.go index e66c7750a..6d47062ff 100644 --- a/infrastructure/network/addressmanager/network_test.go +++ b/infrastructure/network/addressmanager/network_test.go @@ -5,15 +5,16 @@ package addressmanager import ( - "github.com/kaspanet/kaspad/app/appmessage" "net" "testing" + + "github.com/kaspanet/kaspad/app/appmessage" ) // TestIPTypes ensures the various functions which determine the type of an IP // address based on RFCs work as intended. func TestIPTypes(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil) + amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP") defer teardown() type ipTest struct { in appmessage.NetAddress @@ -136,7 +137,7 @@ func TestIPTypes(t *testing.T) { t.Errorf("IsValid %s\n got: %v want: %v", test.in.IP, rv, test.valid) } - if rv := amgr.IsRoutable(&test.in); rv != test.routable { + if rv := IsRoutable(&test.in, amgr.cfg.AcceptUnroutable); rv != test.routable { t.Errorf("IsRoutable %s\n got: %v want: %v", test.in.IP, rv, test.routable) } } @@ -145,7 +146,7 @@ func TestIPTypes(t *testing.T) { // TestGroupKey tests the GroupKey function to ensure it properly groups various // IP addresses. func TestGroupKey(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil) + amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP") defer teardown() tests := []struct { diff --git a/infrastructure/network/addressmanager/test_utils.go b/infrastructure/network/addressmanager/test_utils.go index fc129aba1..e86713997 100644 --- a/infrastructure/network/addressmanager/test_utils.go +++ b/infrastructure/network/addressmanager/test_utils.go @@ -27,6 +27,6 @@ func AddAddressByIP(am *AddressManager, addressIP string, subnetworkID *external return errors.Errorf("invalid port %s: %s", portString, err) } netAddress := appmessage.NewNetAddressIPPort(ip, uint16(port), 0) - am.AddAddress(netAddress, netAddress, subnetworkID) + am.AddAddresses(netAddress) return nil } diff --git a/infrastructure/network/connmanager/outgoing_connections.go b/infrastructure/network/connmanager/outgoing_connections.go index e9a3bf0fd..5b46e287a 100644 --- a/infrastructure/network/connmanager/outgoing_connections.go +++ b/infrastructure/network/connmanager/outgoing_connections.go @@ -1,5 +1,7 @@ package connmanager +import "github.com/kaspanet/kaspad/app/appmessage" + // checkOutgoingConnections goes over all activeOutgoing and makes sure they are still active. // Then it opens connections so that we have targetOutgoing active connections func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) { @@ -14,6 +16,12 @@ func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) { delete(c.activeOutgoing, address) } + connections := c.netAdapter.P2PConnections() + connectedAddresses := make([]*appmessage.NetAddress, len(connections)) + for i, connection := range connections { + connectedAddresses[i] = connection.NetAddress() + } + liveConnections := len(c.activeOutgoing) if c.targetOutgoing == liveConnections { return @@ -23,47 +31,21 @@ func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) { liveConnections, c.targetOutgoing, c.targetOutgoing-liveConnections) connectionsNeededCount := c.targetOutgoing - len(c.activeOutgoing) - connectionAttempts := connectionsNeededCount * 2 - for i := 0; i < connectionAttempts; i++ { - // Return in case we've already reached or surpassed our target - if len(c.activeOutgoing) >= c.targetOutgoing { - return - } + netAddresses := c.addressManager.RandomAddresses(connectionsNeededCount, connectedAddresses) - address := c.addressManager.GetAddress() - if address == nil { - log.Warnf("No more addresses available") - return - } + for _, netAddress := range netAddresses { + addressString := netAddress.TCPAddress().String() - netAddress := address.NetAddress() - tcpAddress := netAddress.TCPAddress() - addressString := tcpAddress.String() - - if c.connectionExists(addressString) { - log.Debugf("Fetched address %s from address manager but it's already connected. Skipping...", addressString) - continue - } - - isBanned, err := c.addressManager.IsBanned(netAddress) - if err != nil { - log.Infof("Couldn't resolve whether %s is banned: %s", addressString, err) - continue - } - if isBanned { - continue - } - - c.addressManager.Attempt(netAddress) log.Debugf("Connecting to %s because we have %d outgoing connections and the target is "+ "%d", addressString, len(c.activeOutgoing), c.targetOutgoing) - err = c.initiateConnection(addressString) + + err := c.initiateConnection(addressString) if err != nil { log.Infof("Couldn't connect to %s: %s", addressString, err) + c.addressManager.RemoveAddress(netAddress) continue } - c.addressManager.Connected(netAddress) c.activeOutgoing[addressString] = struct{}{} } } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 2dbc3ad32..6b98ea962 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -3465,8 +3465,9 @@ type GetPeerAddressesResponseMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Addresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` + Addresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` + BannedAddresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,2,rep,name=bannedAddresses,proto3" json:"bannedAddresses,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } func (x *GetPeerAddressesResponseMessage) Reset() { @@ -3508,6 +3509,13 @@ func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnow return nil } +func (x *GetPeerAddressesResponseMessage) GetBannedAddresses() []*GetPeerAddressesKnownAddressMessage { + if x != nil { + return x.BannedAddresses + } + return nil +} + func (x *GetPeerAddressesResponseMessage) GetError() *RPCError { if x != nil { return x.Error @@ -7030,417 +7038,423 @@ var file_messages_proto_rawDesc = []byte{ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x9b, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, - 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x05, 0x65, + 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, + 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, - 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, - 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, - 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xff, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, - 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, + 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, - 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, - 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, - 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, - 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, - 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, - 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, + 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, + 0x66, 0x65, 0x65, 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, 0x02, 0x20, + 0x01, 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, 0x22, 0x33, + 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, + 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, + 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, + 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, + 0x66, 0x6f, 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, + 0xff, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, + 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, + 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, + 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, + 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, + 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, + 0x72, 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, 0x1f, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x4d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x12, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, + 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 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, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 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, 0x9e, 0x01, - 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, - 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, + 0x6f, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 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, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, + 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, + 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, - 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, 0x6a, - 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, + 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, 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, + 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, 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, 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, 0x22, 0x00, 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, + 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, 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, 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, + 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 ( @@ -7668,49 +7682,50 @@ var file_messages_proto_depIdxs = []int32{ 34, // 112: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError 10, // 113: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage 46, // 114: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 34, // 115: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 34, // 116: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 69, // 117: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 49, // 118: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 34, // 119: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 49, // 120: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 34, // 121: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 56, // 122: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 34, // 123: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 124: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 5, // 125: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage - 34, // 126: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 34, // 127: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError - 64, // 128: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 65, // 129: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 68, // 130: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 131: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 69, // 132: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 70, // 133: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 72, // 134: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 71, // 135: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 73, // 136: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 34, // 137: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 64, // 138: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 68, // 139: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 140: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 68, // 141: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 142: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 34, // 143: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 34, // 144: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 145: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 34, // 146: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 34, // 147: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 34, // 148: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 0, // 149: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 150: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 151: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 152: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 151, // [151:153] is the sub-list for method output_type - 149, // [149:151] is the sub-list for method input_type - 149, // [149:149] is the sub-list for extension type_name - 149, // [149:149] is the sub-list for extension extendee - 0, // [0:149] is the sub-list for field type_name + 46, // 115: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 34, // 116: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 34, // 117: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 69, // 118: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 49, // 119: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 34, // 120: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 49, // 121: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 34, // 122: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 56, // 123: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 34, // 124: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 125: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 5, // 126: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage + 34, // 127: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 34, // 128: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError + 64, // 129: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 65, // 130: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 68, // 131: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 132: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 69, // 133: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 70, // 134: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 72, // 135: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 71, // 136: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 73, // 137: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 34, // 138: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 64, // 139: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 68, // 140: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 141: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 68, // 142: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 143: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 34, // 144: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 34, // 145: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 146: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 34, // 147: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 34, // 148: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 34, // 149: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 0, // 150: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 151: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 152: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 153: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 152, // [152:154] is the sub-list for method output_type + 150, // [150:152] is the sub-list for method input_type + 150, // [150:150] is the sub-list for extension type_name + 150, // [150:150] is the sub-list for extension extendee + 0, // [0:150] is the sub-list for field type_name } func init() { file_messages_proto_init() } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 1984055f4..2076b6a7f 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -356,6 +356,7 @@ message GetPeerAddressesRequestMessage{ message GetPeerAddressesResponseMessage{ repeated GetPeerAddressesKnownAddressMessage addresses = 1; + repeated GetPeerAddressesKnownAddressMessage bannedAddresses = 2; RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_peer_addresses.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_peer_addresses.go index cf3e7b3cc..f000ada1c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_peer_addresses.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_peer_addresses.go @@ -19,9 +19,14 @@ func (x *KaspadMessage_GetPeerAddressesResponse) toAppMessage() (appmessage.Mess for i, address := range x.GetPeerAddressesResponse.Addresses { addresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: address.Addr} } + bannedAddresses := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(x.GetPeerAddressesResponse.BannedAddresses)) + for i, address := range x.GetPeerAddressesResponse.BannedAddresses { + bannedAddresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: address.Addr} + } return &appmessage.GetPeerAddressesResponseMessage{ - Addresses: addresses, - Error: err, + Addresses: addresses, + BannedAddresses: bannedAddresses, + Error: err, }, nil } @@ -34,9 +39,14 @@ func (x *KaspadMessage_GetPeerAddressesResponse) fromAppMessage(message *appmess for i, address := range message.Addresses { addresses[i] = &GetPeerAddressesKnownAddressMessage{Addr: address.Addr} } + bannedAddresses := make([]*GetPeerAddressesKnownAddressMessage, len(message.BannedAddresses)) + for i, address := range message.BannedAddresses { + bannedAddresses[i] = &GetPeerAddressesKnownAddressMessage{Addr: address.Addr} + } x.GetPeerAddressesResponse = &GetPeerAddressesResponseMessage{ - Addresses: addresses, - Error: err, + Addresses: addresses, + BannedAddresses: bannedAddresses, + Error: err, } return nil } From eef5e3768c0625dad124d463eb03963d833f7468 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 12 Nov 2020 15:19:39 +0200 Subject: [PATCH 017/351] [NOD-1518] Fix genesis block insertion and integration tests (#1013) * Revert "[NOD-1500] Delete integration tests" This reverts commit fcb57a206690a884fa6afb69d5d493282954a8bf. * [NOD-1518] hashserialization -> consenusserialization * [NOD-1518] Fix add genesis to virtual * [NOD-1518] Fix a bug in SerializeCoinbasePayload. * [NOD-1518] Fix a loop error and make pastMedianTime behave correctly everywhere on genesis. * [NOD-1518] Fix another bug and an infinite loop. * [NOD-1518] Fix uninitialized slice. * [NOD-1518] Fix bad should-commit checks and another infinite loop. * [NOD-1518] Fix nil serialization. * [NOD-1518] Rename blockHash to currentBlockHash. * [NOD-1518] Move the check whether stagedVirtualUTXOSet != nil to the top of commitVirtualUTXODiff. * [NOD-1518] Simplify utxoDiffStore.Commit. * [NOD-1518] Unextract resolveBlockStatusAndCheckFinality. * [NOD-1518] Move no-transactions logic into CalculateIDMerkleRoot. * [NOD-1518] Remove redundant is-staged check. * [NOD-1518] Fix merge errors. * [NOD-1518] Don't write anything if utxoDiffChild is nil. * [NOD-1518] Stage virtualAcceptanceData and virtualMultiset. * [NOD-1518] Fix bugs in getBlockTemplate and submitBlock. * [NOD-1518] Fix bad validation order in validateHeaderInContext. * [NOD-1518] Fix bug in Next(). * [NOD-1518] Fix nil dereference of subnetworks in AddressCache. * [NOD-1518] Fix multisetStore.Get returning a pointer to a multiset that is changed in place. * [NOD-1518] Break on genesis in countSubtrees. * [NOD-1518] Fix createBlockLocator. * [NOD-1518] Fix MsgTxToDomainTransaction. * [NOD-1518] Set MaxTxVersion to 1. * [NOD-1518] Fix missing error handling, bug in MsgTxToDomainTransaction, and bad subnetwork equality check. * [NOD-1518] Fix bug in hasUTXOByOutpointFromStagedVirtualUTXODiff. * [NOD-1518] Remove irrelevant comments. * [NOD-1518] Generate transactions with sufficient fee in tx_relay_test. * [NOD-1518] Fix broken RPC handlers. * [NOD-1518] Fix merge errors. * [NOD-1518] Fix bad exists check in restorePastUTXO and missing genesis check in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Add a comment. * [NOD-1518] Use a regular mutex instead of a read-write mutex in consensus to avoid dealing with sneaky not-actually-read functions. * [NOD-1518] Fix a deadlock in GetVirtualSelectedParent. * [NOD-1518] Fix missing handler registration for CmdHeader. * [NOD-1518] Fix processHeader calling OnNewBlock and LogBlock. Also fix conversion errors in IBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad Command() in MsgIBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad SyncStateMissingUTXOSet logic in resolveSyncState. * [NOD-1518] Rename mode to syncState. * [NOD-1518] Fix headers-only blocks coming in after the consensus thinks it's synced. * [NOD-1518] Fix selectedChildIterator.Next not ignoring virtual, infinite loop in HashSet.Length(). * [NOD-1518] Fix not-properly wrapped IBD blocks. * [NOD-1518] Fix bad conversion in RequestIBDBlocks. * [NOD-1518] Fix bad string for CmdRequestHeaders. * [NOD-1518] Fix bad string for CmdDoneHeaders. * [NOD-1518] Fix bad Command() for MsgIBDRootNotFound. * [NOD-1518] Fix bad areHeaderTipsSyncedMaxTimeDifference value. * [NOD-1518] Add missing string for CmdRequestIBDBlocks. * [NOD-1518] Fix bad check for SyncStateMissingBlockBodies. * [NOD-1518] Fix bad timeout durations in tests. * [NOD-1518] Fix IBD blocks not calling OnNewBlock. * [NOD-1518] Change when IBD finishes. * [NOD-1518] Properly clone utxoDiffChild. * [NOD-1518] Fix merge errors. * [NOD-1518] Move call to LogBlock to into OnNewBlock. * [NOD-1518] Return "not implemented" in unimplemented RPC handlers. * [NOD-1518] Extract cloning of hashes to a method over DomainHash. * [NOD-1518] Use isHeaderOnlyBlock. * [NOD-1518] Use constants.TransactionVersion. * [NOD-1518] Break immediately if we reached the virtual in SelectedChildIterator. * [NOD-1518] Don't stage nil utxoDiffChild. * [NOD-1518] Properly check the genesis hash in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Explain why we break on current == nil in countSubtrees. * [NOD-1518] Add a comment explaining why we check against StatusValid in resolveSyncState. Co-authored-by: Mike Zak Co-authored-by: Ori Newman --- app/appmessage/domainconverters.go | 8 +- app/appmessage/message.go | 5 +- app/appmessage/p2p_ibdrootnotfound.go | 2 +- .../p2p_msgibdrootutxosetandblock.go | 2 +- app/protocol/flowcontext/blocks.go | 6 + .../flows/blockrelay/handle_relay_invs.go | 10 +- .../flows/ibd/handle_ibd_block_requests.go | 4 +- .../flows/ibd/handle_request_headers.go | 4 +- app/protocol/flows/ibd/ibd.go | 13 +- app/protocol/protocol.go | 3 +- app/rpc/rpc.go | 2 +- app/rpc/rpchandlers/get_block_count.go | 3 +- app/rpc/rpchandlers/get_block_template.go | 8 +- app/rpc/rpchandlers/get_blocks.go | 5 +- app/rpc/rpchandlers/get_chain_from_block.go | 4 +- app/rpc/rpchandlers/get_headers.go | 4 +- app/rpc/rpchandlers/get_mempool_entries.go | 4 +- app/rpc/rpchandlers/get_mempool_entry.go | 2 +- app/rpc/rpchandlers/get_subnetwork.go | 4 +- .../rpchandlers/resolve_finality_conflict.go | 4 +- domain/consensus/consensus.go | 62 ++++----- .../consensusstatestore/utxo.go | 21 ++- .../multisetstore/multisetstore.go | 2 +- .../utxodiffstore/utxodiffstore.go | 14 +- domain/consensus/factory.go | 6 +- domain/consensus/model/externalapi/hash.go | 8 ++ domain/consensus/model/externalapi/sync.go | 2 + domain/consensus/model/multiset.go | 1 + .../processes/blockbuilder/block_builder.go | 20 +-- .../blockbuilder/test_block_builder.go | 2 +- .../blockprocessor/validateandinsertblock.go | 51 ++++--- .../blockvalidator/block_body_in_context.go | 3 +- .../blockvalidator/block_header_in_context.go | 19 +-- .../add_block_to_virtual.go | 23 +-- .../calculate_past_utxo.go | 32 +++-- .../consensusstatemanager.go | 4 + .../consensusstatemanager/finality.go | 7 +- .../consensusstatemanager/multisets.go | 4 + .../pick_virtual_parents.go | 2 +- .../resolve_block_status.go | 6 +- .../set_pruning_utxo_set.go | 2 +- .../consensusstatemanager/update_virtual.go | 4 +- .../verify_and_build_utxo.go | 6 +- .../dagtraversalmanager.go | 10 +- .../selected_child_iterator.go | 4 + .../pastmediantimemanager.go | 32 ++++- .../processes/reachabilitymanager/tree.go | 7 + .../processes/syncmanager/blocklocator.go | 4 +- .../processes/syncmanager/syncinfo.go | 18 ++- .../transaction_in_isolation.go | 2 +- domain/consensus/utils/coinbase/payload.go | 14 +- domain/consensus/utils/hashset/hash_set.go | 2 +- domain/consensus/utils/merkle/merkle.go | 4 + domain/consensus/utils/multiset/multiset.go | 6 +- domain/dagconfig/genesis.go | 18 +-- .../blocktemplatebuilder.go | 11 +- domain/miningmanager/mempool/mempool.go | 27 ++-- domain/miningmanager/mempool/policy.go | 7 +- domain/miningmanager/miningmanager.go | 4 +- .../model/interface_blocktemplatebuilder.go | 2 +- .../p2p_ibd_root_utxo_set_and_block.go | 2 + .../protowire/p2p_request_ibd_blocks.go | 2 +- ...p2p_request_ibd_root_utxo_set_and_block.go | 2 + .../grpcserver/protowire/rpc_submit_block.go | 3 +- .../rpcclient/rpc_get_connected_peer_info.go | 8 +- .../64_incoming_connections_test.go | 61 ++++++++ testing/integration/address_exchange_test.go | 33 +++++ testing/integration/basic_sync_test.go | 55 ++++++++ testing/integration/config_test.go | 59 ++++++++ testing/integration/connect_test.go | 70 ++++++++++ testing/integration/ibd_test.go | 51 +++++++ testing/integration/log_test.go | 14 ++ testing/integration/main_test.go | 14 ++ testing/integration/mining_test.go | 46 ++++++ testing/integration/notifications_test.go | 14 ++ testing/integration/rpc_test.go | 24 ++++ testing/integration/setup_test.go | 131 ++++++++++++++++++ testing/integration/tx_relay_test.go | 125 +++++++++++++++++ 78 files changed, 1049 insertions(+), 235 deletions(-) create mode 100644 testing/integration/64_incoming_connections_test.go create mode 100644 testing/integration/address_exchange_test.go create mode 100644 testing/integration/basic_sync_test.go create mode 100644 testing/integration/config_test.go create mode 100644 testing/integration/connect_test.go create mode 100644 testing/integration/ibd_test.go create mode 100644 testing/integration/log_test.go create mode 100644 testing/integration/main_test.go create mode 100644 testing/integration/mining_test.go create mode 100644 testing/integration/notifications_test.go create mode 100644 testing/integration/rpc_test.go create mode 100644 testing/integration/setup_test.go create mode 100644 testing/integration/tx_relay_test.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 460dc9dcb..6a8116284 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -114,6 +114,12 @@ func MsgTxToDomainTransaction(msgTx *MsgTx) *externalapi.DomainTransaction { for _, txOut := range msgTx.TxOut { transactionOutputs = append(transactionOutputs, txOutToDomainTransactionOutput(txOut)) } + + payload := make([]byte, 0) + if msgTx.Payload != nil { + payload = msgTx.Payload + } + return &externalapi.DomainTransaction{ Version: msgTx.Version, Inputs: transactionInputs, @@ -122,7 +128,7 @@ func MsgTxToDomainTransaction(msgTx *MsgTx) *externalapi.DomainTransaction { SubnetworkID: msgTx.SubnetworkID, Gas: msgTx.Gas, PayloadHash: msgTx.PayloadHash, - Payload: msgTx.Payload, + Payload: payload, } } diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 9108242f0..f4f66016d 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -116,7 +116,7 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdVerAck: "VerAck", CmdRequestAddresses: "RequestAddresses", CmdAddresses: "Addresses", - CmdRequestHeaders: "RequestBlocks", + CmdRequestHeaders: "RequestHeaders", CmdBlock: "Block", CmdTx: "Tx", CmdPing: "Ping", @@ -130,13 +130,14 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdInvTransaction: "InvTransaction", CmdRequestTransactions: "RequestTransactions", CmdIBDBlock: "IBDBlock", - CmdDoneHeaders: "DoneIBDBlocks", + CmdDoneHeaders: "DoneHeaders", CmdTransactionNotFound: "TransactionNotFound", CmdReject: "Reject", CmdHeader: "Header", CmdRequestNextHeaders: "RequestNextHeaders", CmdRequestIBDRootUTXOSetAndBlock: "RequestPruningUTXOSetAndBlock", CmdIBDRootUTXOSetAndBlock: "IBDRootUTXOSetAndBlock", + CmdRequestIBDBlocks: "RequestIBDBlocks", CmdIBDRootNotFound: "IBDRootNotFound", } diff --git a/app/appmessage/p2p_ibdrootnotfound.go b/app/appmessage/p2p_ibdrootnotfound.go index d667a3de1..8a57e5ad6 100644 --- a/app/appmessage/p2p_ibdrootnotfound.go +++ b/app/appmessage/p2p_ibdrootnotfound.go @@ -12,7 +12,7 @@ type MsgIBDRootNotFound struct { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgIBDRootNotFound) Command() MessageCommand { - return CmdDoneHeaders + return CmdIBDRootNotFound } // NewMsgIBDRootNotFound returns a new kaspa IBDRootNotFound message that conforms to the diff --git a/app/appmessage/p2p_msgibdrootutxosetandblock.go b/app/appmessage/p2p_msgibdrootutxosetandblock.go index 556827216..d1d1d28a8 100644 --- a/app/appmessage/p2p_msgibdrootutxosetandblock.go +++ b/app/appmessage/p2p_msgibdrootutxosetandblock.go @@ -11,7 +11,7 @@ type MsgIBDRootUTXOSetAndBlock struct { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgIBDRootUTXOSetAndBlock) Command() MessageCommand { - return CmdRequestIBDRootUTXOSetAndBlock + return CmdIBDRootUTXOSetAndBlock } // NewMsgIBDRootUTXOSetAndBlock returns a new MsgIBDRootUTXOSetAndBlock. diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index ff16002d5..aeeb48360 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -1,6 +1,7 @@ package flowcontext import ( + "github.com/kaspanet/kaspad/app/protocol/blocklogger" "sync/atomic" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -14,6 +15,11 @@ import ( // relays newly unorphaned transactions and possibly rebroadcast // manually added transactions when not in IBD. func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { + err := blocklogger.LogBlock(block) + if err != nil { + return err + } + f.Domain().MiningManager().HandleNewBlockTransactions(block.Transactions) if f.onBlockAddedToDAGHandler != nil { diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 29458b46b..65d517327 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -2,7 +2,6 @@ package blockrelay import ( "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/protocol/blocklogger" "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" @@ -93,7 +92,6 @@ func (flow *handleRelayInvsFlow) start() error { } func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) { - if len(flow.invsQueue) > 0 { var inv *appmessage.MsgInvRelayBlock inv, flow.invsQueue = flow.invsQueue[0], flow.invsQueue[1:] @@ -180,9 +178,7 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err // readMsgBlock returns the next msgBlock in msgChan, and populates invsQueue with any inv messages that meanwhile arrive. // // Note: this function assumes msgChan can contain only appmessage.MsgInvRelayBlock and appmessage.MsgBlock messages. -func (flow *handleRelayInvsFlow) readMsgBlock() ( - msgBlock *appmessage.MsgBlock, err error) { - +func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock, err error) { for { message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) if err != nil { @@ -244,10 +240,6 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS return protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash) } - err = blocklogger.LogBlock(block) - if err != nil { - return err - } err = flow.Broadcast(appmessage.NewMsgInvBlock(blockHash)) if err != nil { return err diff --git a/app/protocol/flows/ibd/handle_ibd_block_requests.go b/app/protocol/flows/ibd/handle_ibd_block_requests.go index df232787c..794b66a5f 100644 --- a/app/protocol/flows/ibd/handle_ibd_block_requests.go +++ b/app/protocol/flows/ibd/handle_ibd_block_requests.go @@ -40,7 +40,9 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute // TODO (Partial nodes): Convert block to partial block if needed - err = outgoingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(block)) + blockMessage := appmessage.DomainBlockToMsgBlock(block) + ibdBlockMessage := appmessage.NewMsgIBDBlock(blockMessage) + err = outgoingRoute.Enqueue(ibdBlockMessage) if err != nil { return err } diff --git a/app/protocol/flows/ibd/handle_request_headers.go b/app/protocol/flows/ibd/handle_request_headers.go index cadfa2b84..4ac94450e 100644 --- a/app/protocol/flows/ibd/handle_request_headers.go +++ b/app/protocol/flows/ibd/handle_request_headers.go @@ -115,8 +115,8 @@ func (flow *handleRequestBlocksFlow) buildMsgBlockHeaders(lowHash *externalapi.D } func (flow *handleRequestBlocksFlow) sendHeaders(headers []*appmessage.MsgBlockHeader) error { - for _, msgIBDBlock := range headers { - err := flow.outgoingRoute.Enqueue(msgIBDBlock) + for _, msgBlockHeader := range headers { + err := flow.outgoingRoute.Enqueue(msgBlockHeader) if err != nil { return err } diff --git a/app/protocol/flows/ibd/ibd.go b/app/protocol/flows/ibd/ibd.go index 79053b5fd..edf80314a 100644 --- a/app/protocol/flows/ibd/ibd.go +++ b/app/protocol/flows/ibd/ibd.go @@ -2,7 +2,6 @@ package ibd import ( "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/protocol/blocklogger" "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" @@ -153,6 +152,10 @@ func (flow *handleIBDFlow) syncMissingBlockBodies() error { if err != nil { return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash) } + err = flow.OnNewBlock(block) + if err != nil { + return err + } } } @@ -348,13 +351,5 @@ func (flow *handleIBDFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHead return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) } - err = flow.OnNewBlock(block) - if err != nil { - return err - } - err = blocklogger.LogBlock(block) - if err != nil { - return err - } return nil } diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index b8c095c2f..2f0cdc665 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -180,7 +180,8 @@ func (m *Manager) registerIBDFlows(router *routerpkg.Router, isStopping *uint32, return []*flow{ m.registerFlow("HandleIBD", router, []appmessage.MessageCommand{appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, - appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock}, isStopping, errChan, + appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, appmessage.CmdHeader}, + isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return ibd.HandleIBD(m.context, incomingRoute, outgoingRoute, peer) }, diff --git a/app/rpc/rpc.go b/app/rpc/rpc.go index b4b346b7a..44ac3a8d3 100644 --- a/app/rpc/rpc.go +++ b/app/rpc/rpc.go @@ -32,7 +32,7 @@ var handlers = map[appmessage.MessageCommand]handler{ appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict, appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts, appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries, - appmessage.CmdShutDownRequestMessage: rpchandlers.HandleGetMempoolEntries, + appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown, appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders, } diff --git a/app/rpc/rpchandlers/get_block_count.go b/app/rpc/rpchandlers/get_block_count.go index 2d4b10d25..5988c5342 100644 --- a/app/rpc/rpchandlers/get_block_count.go +++ b/app/rpc/rpchandlers/get_block_count.go @@ -8,6 +8,7 @@ import ( // HandleGetBlockCount handles the respectively named RPC command func HandleGetBlockCount(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { - response := appmessage.NewGetBlockCountResponseMessage(0) // TODO + response := &appmessage.GetBlockCountResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") return response, nil } diff --git a/app/rpc/rpchandlers/get_block_template.go b/app/rpc/rpchandlers/get_block_template.go index 8196aa185..ff8429e41 100644 --- a/app/rpc/rpchandlers/get_block_template.go +++ b/app/rpc/rpchandlers/get_block_template.go @@ -27,7 +27,11 @@ func HandleGetBlockTemplate(context *rpccontext.Context, _ *router.Router, reque coinbaseData := &externalapi.DomainCoinbaseData{ScriptPublicKey: scriptPublicKey} - templateBlock := context.Domain.MiningManager().GetBlockTemplate(coinbaseData) + templateBlock, err := context.Domain.MiningManager().GetBlockTemplate(coinbaseData) + if err != nil { + return nil, err + } + msgBlock := appmessage.DomainBlockToMsgBlock(templateBlock) - return appmessage.DomainBlockToMsgBlock(templateBlock), nil + return appmessage.NewGetBlockTemplateResponseMessage(msgBlock), nil } diff --git a/app/rpc/rpchandlers/get_blocks.go b/app/rpc/rpchandlers/get_blocks.go index c819a9fce..8fa42245b 100644 --- a/app/rpc/rpchandlers/get_blocks.go +++ b/app/rpc/rpchandlers/get_blocks.go @@ -14,6 +14,7 @@ const ( // HandleGetBlocks handles the respectively named RPC command func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - - return nil, nil + response := &appmessage.GetBlocksResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") + return response, nil } diff --git a/app/rpc/rpchandlers/get_chain_from_block.go b/app/rpc/rpchandlers/get_chain_from_block.go index 6ce0af92f..321cc52f4 100644 --- a/app/rpc/rpchandlers/get_chain_from_block.go +++ b/app/rpc/rpchandlers/get_chain_from_block.go @@ -14,5 +14,7 @@ const ( // HandleGetChainFromBlock handles the respectively named RPC command func HandleGetChainFromBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - return nil, nil + response := &appmessage.GetChainFromBlockResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") + return response, nil } diff --git a/app/rpc/rpchandlers/get_headers.go b/app/rpc/rpchandlers/get_headers.go index ebf82f582..747bf120b 100644 --- a/app/rpc/rpchandlers/get_headers.go +++ b/app/rpc/rpchandlers/get_headers.go @@ -8,5 +8,7 @@ import ( // HandleGetHeaders handles the respectively named RPC command func HandleGetHeaders(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - return nil, nil + response := &appmessage.GetHeadersResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") + return response, nil } diff --git a/app/rpc/rpchandlers/get_mempool_entries.go b/app/rpc/rpchandlers/get_mempool_entries.go index 27488eb69..79b43062d 100644 --- a/app/rpc/rpchandlers/get_mempool_entries.go +++ b/app/rpc/rpchandlers/get_mempool_entries.go @@ -8,5 +8,7 @@ import ( // HandleGetMempoolEntries handles the respectively named RPC command func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { - return nil, nil + response := &appmessage.GetMempoolEntriesResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") + return response, nil } diff --git a/app/rpc/rpchandlers/get_mempool_entry.go b/app/rpc/rpchandlers/get_mempool_entry.go index 7492a7f83..104441a37 100644 --- a/app/rpc/rpchandlers/get_mempool_entry.go +++ b/app/rpc/rpchandlers/get_mempool_entry.go @@ -8,5 +8,5 @@ import ( // HandleGetMempoolEntry handles the respectively named RPC command func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - return nil, nil + return &appmessage.GetMempoolEntryResponseMessage{}, nil } diff --git a/app/rpc/rpchandlers/get_subnetwork.go b/app/rpc/rpchandlers/get_subnetwork.go index 64b7497cc..9d69b5da4 100644 --- a/app/rpc/rpchandlers/get_subnetwork.go +++ b/app/rpc/rpchandlers/get_subnetwork.go @@ -8,5 +8,7 @@ import ( // HandleGetSubnetwork handles the respectively named RPC command func HandleGetSubnetwork(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - return nil, nil + response := &appmessage.GetSubnetworkResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") + return response, nil } diff --git a/app/rpc/rpchandlers/resolve_finality_conflict.go b/app/rpc/rpchandlers/resolve_finality_conflict.go index 791e086cd..0b403149b 100644 --- a/app/rpc/rpchandlers/resolve_finality_conflict.go +++ b/app/rpc/rpchandlers/resolve_finality_conflict.go @@ -8,5 +8,7 @@ import ( // HandleResolveFinalityConflict handles the respectively named RPC command func HandleResolveFinalityConflict(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - return nil, nil + response := &appmessage.ResolveFinalityConflictResponseMessage{} + response.Error = appmessage.RPCErrorf("not implemented") + return response, nil } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 9b5137de8..03915010a 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -10,7 +10,7 @@ import ( ) type consensus struct { - lock *sync.RWMutex + lock *sync.Mutex databaseContext model.DBReader blockProcessor model.BlockProcessor @@ -48,8 +48,8 @@ type consensus struct { func (s *consensus) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.blockBuilder.BuildBlock(coinbaseData, transactions) } @@ -66,8 +66,8 @@ func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock) error // ValidateTransactionAndPopulateWithConsensusData validates the given transaction // and populates it with any missing consensus data func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction *externalapi.DomainTransaction) error { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() err := s.transactionValidator.ValidateTransactionInIsolation(transaction) if err != nil { @@ -79,11 +79,7 @@ func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction return err } - virtualGHOSTDAGData, err := s.ghostdagDataStore.Get(s.databaseContext, model.VirtualBlockHash) - if err != nil { - return err - } - virtualSelectedParentMedianTime, err := s.pastMedianTimeManager.PastMedianTime(virtualGHOSTDAGData.SelectedParent) + virtualSelectedParentMedianTime, err := s.pastMedianTimeManager.PastMedianTime(model.VirtualBlockHash) if err != nil { return err } @@ -93,22 +89,22 @@ func (s *consensus) ValidateTransactionAndPopulateWithConsensusData(transaction } func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.blockStore.Block(s.databaseContext, blockHash) } func (s *consensus) GetBlockHeader(blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.blockHeaderStore.BlockHeader(s.databaseContext, blockHash) } func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() blockInfo := &externalapi.BlockInfo{} @@ -137,22 +133,22 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap } func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.syncManager.GetHashesBetween(lowHash, highHash) } func (s *consensus) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.syncManager.GetMissingBlockBodyHashes(highHash) } func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi.DomainHash) ([]byte, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() pruningPointHash, err := s.pruningStore.PruningPoint(s.databaseContext) if err != nil { @@ -173,40 +169,40 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi } func (s *consensus) SetPruningPointUTXOSet(serializedUTXOSet []byte) error { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.consensusStateManager.SetPruningPointUTXOSet(serializedUTXOSet) } func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() virtualGHOSTDAGData, err := s.ghostdagDataStore.Get(s.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err } - return s.GetBlock(virtualGHOSTDAGData.SelectedParent) + return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent) } func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.syncManager.CreateBlockLocator(lowHash, highHash) } func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator) } func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { - s.lock.RLock() - defer s.lock.RUnlock() + s.lock.Lock() + defer s.lock.Unlock() return s.syncManager.GetSyncInfo() } diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index b99b7dbc0..f51dc6b9d 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -28,10 +28,6 @@ func (c *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODi } func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error { - if c.stagedVirtualUTXOSet != nil { - return errors.New("cannot commit virtual UTXO diff while virtual UTXO set is staged") - } - if c.stagedVirtualUTXODiff == nil { return nil } @@ -66,8 +62,8 @@ func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) er } func (c *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error { - if c.stagedVirtualUTXODiff != nil { - return errors.New("cannot commit virtual UTXO set while virtual UTXO diff is staged") + if c.stagedVirtualUTXOSet == nil { + return nil } for outpoint, utxoEntry := range c.stagedVirtualUTXOSet { @@ -143,11 +139,14 @@ func (c *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoi func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { - if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok { - return false, nil - } - if _, ok := c.stagedVirtualUTXODiff.ToAdd[*outpoint]; ok { - return true, nil + + if c.stagedVirtualUTXODiff != nil { + if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok { + return false, nil + } + if _, ok := c.stagedVirtualUTXODiff.ToAdd[*outpoint]; ok { + return true, nil + } } key, err := utxoKey(outpoint) diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go index a61932e61..176a1bfef 100644 --- a/domain/consensus/datastructures/multisetstore/multisetstore.go +++ b/domain/consensus/datastructures/multisetstore/multisetstore.go @@ -65,7 +65,7 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error { // Get gets the multiset associated with the given blockHash func (ms *multisetStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.Multiset, error) { if multiset, ok := ms.staging[*blockHash]; ok { - return multiset, nil + return multiset.Clone() } multisetBytes, err := dbContext.Get(ms.hashAsKey(blockHash)) diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index 786d0096f..d053d9d2a 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -29,13 +29,16 @@ func New() model.UTXODiffStore { // Stage stages the given utxoDiff for the given blockHash func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { - clone, err := uds.cloneUTXODiff(utxoDiff) + utxoDiffClone, err := uds.cloneUTXODiff(utxoDiff) if err != nil { return err } + uds.utxoDiffStaging[*blockHash] = utxoDiffClone - uds.utxoDiffStaging[*blockHash] = clone - uds.utxoDiffChildStaging[*blockHash] = &*utxoDiffChild + if utxoDiffChild != nil { + utxoDiffChildClone := uds.cloneUTXODiffChild(utxoDiffChild) + uds.utxoDiffChildStaging[*blockHash] = utxoDiffChildClone + } return nil } @@ -74,7 +77,6 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } - err = dbTx.Put(uds.utxoDiffHashAsKey(&hash), utxoDiffChildBytes) if err != nil { return err @@ -196,3 +198,7 @@ func (uds *utxoDiffStore) cloneUTXODiff(diff *model.UTXODiff) (*model.UTXODiff, return uds.deserializeUTXODiff(serialized) } + +func (uds *utxoDiffStore) cloneUTXODiffChild(diffChild *externalapi.DomainHash) *externalapi.DomainHash { + return diffChild.Clone() +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 3c7927706..017b565fb 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -98,7 +98,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagParams.TimestampDeviationTolerance, dbManager, dagTraversalManager, - blockHeaderStore) + blockHeaderStore, + ghostdagDataStore) transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity, dagParams.EnableNonNativeSubnetworks, dbManager, @@ -153,6 +154,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager, dagParams.FinalityDepth(), dagParams.PruningDepth(), + genesisHash, ghostdagManager, dagTopologyManager, dagTraversalManager, @@ -250,7 +252,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat headerTipsStore) c := &consensus{ - lock: &sync.RWMutex{}, + lock: &sync.Mutex{}, databaseContext: dbManager, blockProcessor: blockProcessor, diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index 40097d9d0..eb19869b6 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -17,6 +17,14 @@ func (hash DomainHash) String() string { return hex.EncodeToString(hash[:]) } +// Clone clones the hash +func (hash *DomainHash) Clone() *DomainHash { + if hash == nil { + return nil + } + return &*hash +} + // DomainHashesToStrings returns a slice of strings representing the hashes in the given slice of hashes func DomainHashesToStrings(hashes []*DomainHash) []string { strings := make([]string, len(hashes)) diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index d69db5fab..e57905c05 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -19,6 +19,8 @@ func (s SyncState) String() string { switch s { case SyncStateRelay: return "SyncStateRelay" + case SyncStateMissingGenesis: + return "SyncStateMissingGenesis" case SyncStateHeadersFirst: return "SyncStateHeadersFirst" case SyncStateMissingUTXOSet: diff --git a/domain/consensus/model/multiset.go b/domain/consensus/model/multiset.go index b10687068..bf176d0b4 100644 --- a/domain/consensus/model/multiset.go +++ b/domain/consensus/model/multiset.go @@ -8,4 +8,5 @@ type Multiset interface { Remove(data []byte) Hash() *externalapi.DomainHash Serialize() []byte + Clone() (Multiset, error) } diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 66f4cfab3..1c30f2135 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -95,7 +95,7 @@ func (bb *blockBuilder) newBlockCoinbaseTransaction( return bb.coinbaseManager.ExpectedCoinbaseTransaction(model.VirtualBlockHash, coinbaseData) } -func (bb blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) { +func (bb *blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) { parentHashes, err := bb.newBlockParentHashes() if err != nil { return nil, err @@ -104,7 +104,7 @@ func (bb blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction if err != nil { return nil, err } - timeInMilliseconds, err := bb.newBlockTime(virtualGHOSTDAGData) + timeInMilliseconds, err := bb.newBlockTime() if err != nil { return nil, err } @@ -133,7 +133,7 @@ func (bb blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction }, nil } -func (bb blockBuilder) newBlockParentHashes() ([]*externalapi.DomainHash, error) { +func (bb *blockBuilder) newBlockParentHashes() ([]*externalapi.DomainHash, error) { virtualBlockRelations, err := bb.blockRelationStore.BlockRelation(bb.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err @@ -142,7 +142,7 @@ func (bb blockBuilder) newBlockParentHashes() ([]*externalapi.DomainHash, error) return virtualBlockRelations.Parents, nil } -func (bb blockBuilder) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (int64, error) { +func (bb *blockBuilder) newBlockTime() (int64, error) { // The timestamp for the block must not be before the median timestamp // of the last several blocks. Thus, choose the maximum between the // current time and one second after the past median time. The current @@ -150,7 +150,7 @@ func (bb blockBuilder) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData // block timestamp does not supported a precision greater than one // millisecond. newTimestamp := mstime.Now().UnixMilliseconds() + 1 - minTimestamp, err := bb.pastMedianTimeManager.PastMedianTime(virtualGHOSTDAGData.SelectedParent) + minTimestamp, err := bb.pastMedianTimeManager.PastMedianTime(model.VirtualBlockHash) if err != nil { return 0, err } @@ -160,7 +160,7 @@ func (bb blockBuilder) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData return newTimestamp, nil } -func (bb blockBuilder) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) { +func (bb *blockBuilder) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) { virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash) if err != nil { return 0, err @@ -168,11 +168,11 @@ func (bb blockBuilder) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTD return bb.difficultyManager.RequiredDifficulty(virtualGHOSTDAGData.SelectedParent) } -func (bb blockBuilder) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { +func (bb *blockBuilder) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { return merkle.CalculateHashMerkleRoot(transactions) } -func (bb blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, error) { +func (bb *blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, error) { newBlockAcceptanceData, err := bb.acceptanceDataStore.Get(bb.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err @@ -181,7 +181,7 @@ func (bb blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, return bb.calculateAcceptedIDMerkleRoot(newBlockAcceptanceData) } -func (bb blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.AcceptanceData) (*externalapi.DomainHash, error) { +func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.AcceptanceData) (*externalapi.DomainHash, error) { var acceptedTransactions []*externalapi.DomainTransaction for _, blockAcceptanceData := range acceptanceData { for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData { @@ -200,7 +200,7 @@ func (bb blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.Accept return merkle.CalculateIDMerkleRoot(acceptedTransactions), nil } -func (bb blockBuilder) newBlockUTXOCommitment() (*externalapi.DomainHash, error) { +func (bb *blockBuilder) newBlockUTXOCommitment() (*externalapi.DomainHash, error) { newBlockMultiset, err := bb.multisetStore.Get(bb.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index e05175ba1..93995a28c 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -36,7 +36,7 @@ func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.Do if err != nil { return nil, err } - timeInMilliseconds, err := bb.newBlockTime(ghostdagData) + timeInMilliseconds, err := bb.newBlockTime() if err != nil { return nil, err } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 741b3511c..1c1fd7537 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -8,16 +8,20 @@ import ( ) func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error { - mode, err := bp.syncManager.GetSyncInfo() + syncInfo, err := bp.syncManager.GetSyncInfo() if err != nil { return err } + if isHeaderOnlyBlock(block) && syncInfo.State != externalapi.SyncStateRelay { + syncInfo.State = externalapi.SyncStateHeadersFirst + } + hash := consensusserialization.HeaderHash(block.Header) - if mode.State == externalapi.SyncStateMissingUTXOSet { + if syncInfo.State == externalapi.SyncStateMissingUTXOSet { if isHeaderOnlyBlock(block) { // Allow processing headers while in state SyncStateMissingUTXOSet - mode.State = externalapi.SyncStateHeadersFirst + syncInfo.State = externalapi.SyncStateHeadersFirst } else { headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint() if err != nil { @@ -26,24 +30,38 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) if *hash != *headerTipsPruningPoint { return errors.Errorf("cannot insert blocks other than the header pruning point "+ - "while in %s mode", mode.State) + "while in %s mode", syncInfo.State) } - mode.State = externalapi.SyncStateMissingBlockBodies + syncInfo.State = externalapi.SyncStateMissingBlockBodies } } - if mode.State == externalapi.SyncStateHeadersFirst && !isHeaderOnlyBlock(block) { - mode.State = externalapi.SyncStateRelay + if syncInfo.State == externalapi.SyncStateHeadersFirst && !isHeaderOnlyBlock(block) { + syncInfo.State = externalapi.SyncStateRelay log.Warnf("block %s contains transactions while validating in header only mode", hash) } - err = bp.checkBlockStatus(hash, mode) + if syncInfo.State == externalapi.SyncStateMissingBlockBodies { + headerTips, err := bp.headerTipsStore.Tips(bp.databaseContext) + if err != nil { + return err + } + selectedHeaderTip, err := bp.ghostdagManager.ChooseSelectedParent(headerTips...) + if err != nil { + return err + } + if *selectedHeaderTip == *hash { + syncInfo.State = externalapi.SyncStateRelay + } + } + + err = bp.checkBlockStatus(hash, syncInfo) if err != nil { return err } - err = bp.validateBlock(block, mode) + err = bp.validateBlock(block, syncInfo) if err != nil { bp.discardAllChanges() return err @@ -55,9 +73,9 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } if !hasHeader { - if mode.State == externalapi.SyncStateMissingBlockBodies { + if syncInfo.State == externalapi.SyncStateMissingBlockBodies { return errors.Wrapf(ruleerrors.ErrMissingBlockHeaderInIBD, "no block header is stored for block %s. "+ - "Every block we get during %s mode should have a pre-stored header", mode.State, hash) + "Every block we get during %s mode should have a pre-stored header", syncInfo.State, hash) } err = bp.reachabilityManager.AddBlock(hash) if err != nil { @@ -65,7 +83,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } } - if mode.State == externalapi.SyncStateHeadersFirst { + if syncInfo.State == externalapi.SyncStateHeadersFirst { bp.blockStatusStore.Stage(hash, externalapi.StatusHeaderOnly) } else { bp.blockStatusStore.Stage(hash, externalapi.StatusUTXOPendingVerification) @@ -92,12 +110,12 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } } - if mode.State == externalapi.SyncStateHeadersFirst || mode.State == externalapi.SyncStateMissingGenesis { + if syncInfo.State == externalapi.SyncStateHeadersFirst { err = bp.headerTipsManager.AddHeaderTip(hash) if err != nil { return err } - } else if mode.State == externalapi.SyncStateRelay { + } else if syncInfo.State == externalapi.SyncStateRelay || syncInfo.State == externalapi.SyncStateMissingGenesis { // Attempt to add the block to the virtual err = bp.consensusStateManager.AddBlockToVirtual(hash) if err != nil { @@ -114,14 +132,14 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } } - if mode.State != externalapi.SyncStateMissingGenesis { + if syncInfo.State != externalapi.SyncStateMissingGenesis { err = bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) if err != nil { return err } } - if mode.State == externalapi.SyncStateRelay { + if syncInfo.State == externalapi.SyncStateRelay { // Trigger pruning, which will check if the pruning point changed and delete the data if it did. err = bp.pruningManager.FindNextPruningPoint() if err != nil { @@ -133,7 +151,6 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error { - headersSelectedTip, err := bp.headerTipsManager.SelectedTip() if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index 139efb479..dcf281a2f 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -30,8 +30,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi. // If it's not genesis if len(block.Header.ParentHashes) != 0 { - - blockTime, err = v.pastMedianTimeManager.PastMedianTime(ghostdagData.SelectedParent) + blockTime, err = v.pastMedianTimeManager.PastMedianTime(blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 3db9baae9..3ce784998 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -21,11 +21,6 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa return err } - err = v.validateMedianTime(header) - if err != nil { - return err - } - isHeadersOnlyBlock, err := v.isHeadersOnlyBlock(blockHash) if err != nil { return err @@ -38,6 +33,11 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa } } + err = v.validateMedianTime(header) + if err != nil { + return err + } + err = v.checkMergeSizeLimit(blockHash) if err != nil { return err @@ -99,15 +99,10 @@ func (v *blockValidator) validateMedianTime(header *externalapi.DomainBlockHeade return nil } - hash := consensusserialization.HeaderHash(header) - ghostdagData, err := v.ghostdagDataStore.Get(v.databaseContext, hash) - if err != nil { - return err - } - // Ensure the timestamp for the block header is not before the // median time of the last several blocks (medianTimeBlocks). - pastMedianTime, err := v.pastMedianTimeManager.PastMedianTime(ghostdagData.SelectedParent) + hash := consensusserialization.HeaderHash(header) + pastMedianTime, err := v.pastMedianTimeManager.PastMedianTime(hash) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 137bf0eeb..01f2da2e4 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -14,17 +14,20 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai return err } - if isNextVirtualSelectedParent { - blockStatus, err := csm.resolveBlockStatus(blockHash) + if !isNextVirtualSelectedParent { + return nil + } + + blockStatus, err := csm.resolveBlockStatus(blockHash) + if err != nil { + return err + } + + if blockStatus == externalapi.StatusValid { + err = csm.checkFinalityViolation(blockHash) if err != nil { return err } - if blockStatus == externalapi.StatusValid { - err = csm.checkFinalityViolation(blockHash) - if err != nil { - return err - } - } } newTips, err := csm.addTip(blockHash) @@ -41,6 +44,10 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai } func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) { + if *blockHash == *csm.genesisHash { + return true, nil + } + virtualGhostdagData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) if err != nil { return false, err diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 4c267bde9..32a86b418 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -2,8 +2,8 @@ package consensusstatemanager import ( "errors" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -15,21 +15,23 @@ import ( func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( *model.UTXODiff, model.AcceptanceData, model.Multiset, error) { + // The genesis block has an empty UTXO diff, empty acceptance data, and a blank multiset + if *blockHash == *csm.genesisHash { + return &model.UTXODiff{}, model.AcceptanceData{}, multiset.New(), nil + } + blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash) if err != nil { return nil, nil, nil, err } - selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent) if err != nil { return nil, nil, nil, err } - acceptanceData, utxoDiff, err := csm.applyBlueBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err } - multiset, err := csm.calculateMultiset(acceptanceData, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err @@ -44,13 +46,21 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH // collect the UTXO diffs var utxoDiffs []*model.UTXODiff nextBlockHash := blockHash - for nextBlockHash != nil { + for { utxoDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, nextBlockHash) if err != nil { return nil, err } utxoDiffs = append(utxoDiffs, utxoDiff) + exists, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, nextBlockHash) + if err != nil { + return nil, err + } + if !exists { + break + } + nextBlockHash, err = csm.utxoDiffStore.UTXODiffChild(csm.databaseContext, nextBlockHash) if err != nil { return nil, err @@ -78,7 +88,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH return nil, nil, err } - selectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(ghostdagData.SelectedParent) + selectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(blockHash) if err != nil { return nil, nil, err } @@ -88,8 +98,8 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH accumulatedMass := uint64(0) for i, blueBlock := range blueBlocks { - blockAccepanceData := &model.BlockAcceptanceData{ - TransactionAcceptanceData: []*model.TransactionAcceptanceData{}, + blockAcceptanceData := &model.BlockAcceptanceData{ + TransactionAcceptanceData: make([]*model.TransactionAcceptanceData, len(blueBlock.Transactions)), } isSelectedParent := i == 0 @@ -103,13 +113,13 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH return nil, nil, err } - blockAccepanceData.TransactionAcceptanceData[j] = &model.TransactionAcceptanceData{ + blockAcceptanceData.TransactionAcceptanceData[j] = &model.TransactionAcceptanceData{ Transaction: transaction, Fee: fee, IsAccepted: isAccepted, } } - multiblockAcceptanceData[i] = blockAccepanceData + multiblockAcceptanceData[i] = blockAcceptanceData } return multiblockAcceptanceData, accumulatedUTXODiff, nil @@ -226,7 +236,7 @@ func newUTXOSetIterator(collection model.UTXOCollection) *utxoSetIterator { func (u utxoSetIterator) Next() bool { u.index++ - return u.index != len(u.pairs) + return u.index < len(u.pairs) } func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { diff --git a/domain/consensus/processes/consensusstatemanager/consensusstatemanager.go b/domain/consensus/processes/consensusstatemanager/consensusstatemanager.go index cdd59f814..c7f9342af 100644 --- a/domain/consensus/processes/consensusstatemanager/consensusstatemanager.go +++ b/domain/consensus/processes/consensusstatemanager/consensusstatemanager.go @@ -2,12 +2,14 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) // consensusStateManager manages the node's consensus state type consensusStateManager struct { finalityDepth uint64 pruningDepth uint64 + genesisHash *externalapi.DomainHash databaseContext model.DBManager ghostdagManager model.GHOSTDAGManager @@ -39,6 +41,7 @@ func New( databaseContext model.DBManager, finalityDepth uint64, pruningDepth uint64, + genesisHash *externalapi.DomainHash, ghostdagManager model.GHOSTDAGManager, dagTopologyManager model.DAGTopologyManager, dagTraversalManager model.DAGTraversalManager, @@ -63,6 +66,7 @@ func New( csm := &consensusStateManager{ finalityDepth: finalityDepth, pruningDepth: pruningDepth, + genesisHash: genesisHash, databaseContext: databaseContext, ghostdagManager: ghostdagManager, diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go index 5db849ad7..e6a94f430 100644 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ b/domain/consensus/processes/consensusstatemanager/finality.go @@ -24,8 +24,13 @@ func (csm *consensusStateManager) checkFinalityViolation( func (csm *consensusStateManager) virtualFinalityPoint(virtualGHOSTDAGData *model.BlockGHOSTDAGData) ( *externalapi.DomainHash, error) { + blueScore := virtualGHOSTDAGData.BlueScore - csm.finalityDepth + if virtualGHOSTDAGData.BlueScore < csm.finalityDepth { + blueScore = 0 + } + return csm.dagTraversalManager.HighestChainBlockBelowBlueScore( - model.VirtualBlockHash, virtualGHOSTDAGData.BlueScore-csm.finalityDepth) + model.VirtualBlockHash, blueScore) } func (csm *consensusStateManager) isViolatingFinality( diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index 08d808fd8..f1b131ea1 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -11,6 +11,10 @@ import ( func (csm *consensusStateManager) calculateMultiset( acceptanceData model.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) { + if blockGHOSTDAGData.SelectedParent == nil { + return multiset.New(), nil + } + ms, err := csm.multisetStore.Get(csm.databaseContext, blockGHOSTDAGData.SelectedParent) if err != nil { return nil, err diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index da0959f96..8fd94ff51 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -31,7 +31,7 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH mergeSetSize := 1 // starts counting from 1 because selectedParent is already in the mergeSet - for len(selectedVirtualParents) < constants.MaxBlockParents { + for candidatesHeap.Len() > 0 && len(selectedVirtualParents) < constants.MaxBlockParents { candidate := candidatesHeap.Pop() mergeSetIncrease, err := csm.mergeSetIncrease(candidate, selectedVirtualParents) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 3ecc2c3bc..398747989 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -16,7 +16,7 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma } // resolve the unverified blocks' statuses in opposite order - for i := len(unverifiedBlocks); i >= 0; i++ { + for i := len(unverifiedBlocks) - 1; i >= 0; i-- { unverifiedBlockHash := unverifiedBlocks[i] var blockStatus externalapi.BlockStatus @@ -47,6 +47,10 @@ func (csm *consensusStateManager) getUnverifiedChainBlocksAndSelectedParentStatu return nil, 0, err } + if ghostdagData.SelectedParent == nil { + return unverifiedBlocks, externalapi.StatusValid, nil + } + selectedParentStatus, err := csm.blockStatusStore.Get(csm.databaseContext, ghostdagData.SelectedParent) if err != nil { return nil, 0, err diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 2cef787f9..6b633d854 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -116,7 +116,7 @@ type protoUTXOSetIterator struct { func (p protoUTXOSetIterator) Next() bool { p.index++ - return p.index != len(p.utxoSet.Utxos) + return p.index < len(p.utxoSet.Utxos) } func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 0fac18352..d4b885195 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -23,10 +23,12 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain return err } - virtualUTXODiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash) + virtualUTXODiff, virtualAcceptanceData, virtualMultiset, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash) if err != nil { return err } + csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) + csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index fd017b26e..f5a718c0d 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -43,11 +43,7 @@ func (csm *consensusStateManager) verifyAndBuildUTXO(block *externalapi.DomainBl func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, err error) error { - ghostdagData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash) - if err != nil { - return err - } - selectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(ghostdagData.SelectedParent) + selectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 89190b0f7..a83c955eb 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -68,7 +68,7 @@ func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.Dom // blueScore in the block with the given highHash's selected // parent chain func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) { - blockHash := highHash + currentBlockHash := highHash chainBlock, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash) if err != nil { return nil, err @@ -82,15 +82,15 @@ func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *extern // If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore for chainBlock.BlueScore >= requiredBlueScore { if chainBlock.SelectedParent == nil { // genesis - return blockHash, nil + return currentBlockHash, nil } - blockHash = chainBlock.SelectedParent - chainBlock, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash) + currentBlockHash = chainBlock.SelectedParent + chainBlock, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash) if err != nil { return nil, err } } - return blockHash, nil + return currentBlockHash, nil } func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) { diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index f69eef1c3..5561a4d4a 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -20,6 +20,10 @@ func (s selectedChildIterator) Next() bool { } for _, child := range children { + if *child == *model.VirtualBlockHash { + break + } + isChildInSelectedParentChainOfHighHash, err := s.dagTopologyManager.IsInSelectedParentChainOf(child, s.highHash) if err != nil { panic(err) diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go index 2c019f386..a2d92dbbb 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go @@ -16,25 +16,47 @@ type pastMedianTimeManager struct { dagTraversalManager model.DAGTraversalManager - blockHeaderStore model.BlockHeaderStore + blockHeaderStore model.BlockHeaderStore + ghostdagDataStore model.GHOSTDAGDataStore } // New instantiates a new PastMedianTimeManager func New(timestampDeviationTolerance uint64, databaseContext model.DBReader, dagTraversalManager model.DAGTraversalManager, - blockHeaderStore model.BlockHeaderStore) model.PastMedianTimeManager { + blockHeaderStore model.BlockHeaderStore, + ghostdagDataStore model.GHOSTDAGDataStore) model.PastMedianTimeManager { + return &pastMedianTimeManager{ timestampDeviationTolerance: timestampDeviationTolerance, databaseContext: databaseContext, - dagTraversalManager: dagTraversalManager, - blockHeaderStore: blockHeaderStore, + + dagTraversalManager: dagTraversalManager, + + blockHeaderStore: blockHeaderStore, + ghostdagDataStore: ghostdagDataStore, } } // PastMedianTime returns the past median time for some block func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainHash) (int64, error) { - window, err := pmtm.dagTraversalManager.BlueWindow(blockHash, 2*pmtm.timestampDeviationTolerance-1) + blockGHOSTDAGData, err := pmtm.ghostdagDataStore.Get(pmtm.databaseContext, blockHash) + if err != nil { + return 0, err + } + selectedParentHash := blockGHOSTDAGData.SelectedParent + + // Genesis block + if selectedParentHash == nil { + header, err := pmtm.blockHeaderStore.BlockHeader(pmtm.databaseContext, blockHash) + if err != nil { + return 0, err + } + + return header.TimeInMilliseconds, nil + } + + window, err := pmtm.dagTraversalManager.BlueWindow(selectedParentHash, 2*pmtm.timestampDeviationTolerance-1) if err != nil { return 0, err } diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 6a40ec47c..746a22855 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -322,6 +322,13 @@ func (rt *reachabilityManager) countSubtrees(node *externalapi.DomainHash, subTr return err } + // If the current is now nil, it means that the previous + // `current` was the genesis block -- the only block that + // does not have parents + if current == nil { + break + } + calculatedChildrenCount[*current]++ currentChildren, err := rt.children(current) diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index 1ad2ecd01..a808e10ac 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -36,7 +36,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH // Nothing more to add once the low node has been added. if currentBlockBlueScore <= lowBlockBlueScore { - if currentHash != lowHash { + if *currentHash != *lowHash { return nil, errors.Errorf("highHash and lowHash are " + "not in the same selected parent chain.") } @@ -46,7 +46,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH // Calculate blueScore of previous node to include ensuring the // final node is lowNode. nextBlueScore := currentBlockBlueScore - step - if nextBlueScore < lowBlockGHOSTDAGData.BlueScore { + if currentBlockBlueScore < step { nextBlueScore = lowBlockGHOSTDAGData.BlueScore } diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 64437aba9..42c732d01 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -9,7 +9,7 @@ import ( // 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 +const areHeaderTipsSyncedMaxTimeDifference = 300_000 // 5 minutes func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { syncState, err := sm.resolveSyncState() @@ -36,7 +36,6 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { if err != nil { return 0, err } - if !hasTips { return externalapi.SyncStateMissingGenesis, nil } @@ -45,7 +44,6 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { if err != nil { return 0, err } - isSynced, err := sm.areHeaderTipsSynced(headerVirtualSelectedParentHash) if err != nil { return 0, err @@ -54,11 +52,21 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { return externalapi.SyncStateHeadersFirst, nil } - headerVirtualSelectedParentBlockStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerVirtualSelectedParentHash) + // 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 } - if headerVirtualSelectedParentBlockStatus != externalapi.StatusValid { + headerTipsPruningPointStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerTipsPruningPoint) + if err != nil { + return 0, err + } + if headerTipsPruningPointStatus != externalapi.StatusValid { return externalapi.SyncStateMissingUTXOSet, nil } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index 58617ffc6..b5dfd5af5 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -182,7 +182,7 @@ func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.Domain // If we are a partial node, only transactions on built in subnetworks // or our own subnetwork may have a payload isLocalNodeFull := subnetworkID == nil - shouldTxBeFull := subnetworks.IsBuiltIn(tx.SubnetworkID) || tx.SubnetworkID == *subnetworkID + shouldTxBeFull := subnetworks.IsBuiltIn(tx.SubnetworkID) || subnetworks.IsEqual(&tx.SubnetworkID, subnetworkID) if !isLocalNodeFull && !shouldTxBeFull && len(tx.Payload) > 0 { return errors.Wrapf(ruleerrors.ErrInvalidPayload, "transaction that was expected to be partial has a payload "+ diff --git a/domain/consensus/utils/coinbase/payload.go b/domain/consensus/utils/coinbase/payload.go index 5de841ac0..e1a677006 100644 --- a/domain/consensus/utils/coinbase/payload.go +++ b/domain/consensus/utils/coinbase/payload.go @@ -13,7 +13,7 @@ import ( var byteOrder = binary.LittleEndian const uint64Len = 8 -const scriptPubKeyLengthLength = 1 +const lengthOfscriptPubKeyLength = 1 // SerializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data. func SerializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) { @@ -23,14 +23,14 @@ func SerializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.Domain "longer than the max allowed length of %d", constants.CoinbasePayloadScriptPublicKeyMaxLength) } - payload := make([]byte, uint64Len+scriptPubKeyLengthLength+scriptPubKeyLength+len(coinbaseData.ExtraData)) + payload := make([]byte, uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength+len(coinbaseData.ExtraData)) byteOrder.PutUint64(payload[:uint64Len], blueScore) if len(coinbaseData.ScriptPublicKey) > math.MaxUint8 { return nil, errors.Errorf("script public key is bigger than %d", math.MaxUint8) } payload[uint64Len] = uint8(len(coinbaseData.ScriptPublicKey)) - copy(payload[uint64Len+scriptPubKeyLengthLength:], coinbaseData.ScriptPublicKey) - copy(payload[uint64Len+scriptPubKeyLengthLength+scriptPubKeyLength:], coinbaseData.ExtraData) + copy(payload[uint64Len+lengthOfscriptPubKeyLength:], coinbaseData.ScriptPublicKey) + copy(payload[uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength:], coinbaseData.ExtraData) return payload, nil } @@ -38,7 +38,7 @@ func SerializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.Domain func ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData, err error) { - minLength := uint64Len + scriptPubKeyLengthLength + minLength := uint64Len + lengthOfscriptPubKeyLength if len(coinbaseTx.Payload) < minLength { return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase payload is less than the minimum length of %d", minLength) @@ -58,7 +58,7 @@ func ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) } return blueScore, &externalapi.DomainCoinbaseData{ - ScriptPublicKey: coinbaseTx.Payload[uint64Len+scriptPubKeyLengthLength : uint64Len+scriptPubKeyLengthLength+scriptPubKeyLength], - ExtraData: coinbaseTx.Payload[uint64Len+scriptPubKeyLengthLength+scriptPubKeyLengthLength:], + ScriptPublicKey: coinbaseTx.Payload[uint64Len+lengthOfscriptPubKeyLength : uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength], + ExtraData: coinbaseTx.Payload[uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength:], }, nil } diff --git a/domain/consensus/utils/hashset/hash_set.go b/domain/consensus/utils/hashset/hash_set.go index c123ebc72..0e0b5bbfa 100644 --- a/domain/consensus/utils/hashset/hash_set.go +++ b/domain/consensus/utils/hashset/hash_set.go @@ -87,5 +87,5 @@ func (hs HashSet) ToSlice() []*externalapi.DomainHash { // Length returns the length of this HashSet func (hs HashSet) Length() int { - return hs.Length() + return len(hs) } diff --git a/domain/consensus/utils/merkle/merkle.go b/domain/consensus/utils/merkle/merkle.go index 06b95ce4c..5a86d0dcf 100644 --- a/domain/consensus/utils/merkle/merkle.go +++ b/domain/consensus/utils/merkle/merkle.go @@ -56,6 +56,10 @@ func CalculateHashMerkleRoot(transactions []*externalapi.DomainTransaction) *ext // CalculateIDMerkleRoot calculates the merkle root of a tree consisted of the given transaction IDs. // See `merkleRoot` for more info. func CalculateIDMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { + if len(transactions) == 0 { + return &externalapi.DomainHash{} + } + txIDs := make([]*externalapi.DomainHash, len(transactions)) for i, tx := range transactions { txIDs[i] = (*externalapi.DomainHash)(consensusserialization.TransactionID(tx)) diff --git a/domain/consensus/utils/multiset/multiset.go b/domain/consensus/utils/multiset/multiset.go index 315555e2b..cea53eee0 100644 --- a/domain/consensus/utils/multiset/multiset.go +++ b/domain/consensus/utils/multiset/multiset.go @@ -31,7 +31,11 @@ func (m multiset) Hash() *externalapi.DomainHash { } func (m multiset) Serialize() []byte { - return m.Serialize() + return m.ms.Serialize()[:] +} + +func (m multiset) Clone() (model.Multiset, error) { + return FromBytes(m.Serialize()) } // FromBytes deserializes the given bytes slice and returns a multiset. diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 9190ba4f0..c59d7b5c5 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -129,19 +129,19 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0xad, 0x47, 0xba, 0xd5, 0x6e, 0x1e, 0x62, 0x99, - 0x43, 0x81, 0xd2, 0xaf, 0xda, 0x1d, 0xe6, 0xda, - 0x0b, 0x50, 0xcb, 0x76, 0x8e, 0x5d, 0x9e, 0x41, - 0x20, 0x98, 0x28, 0xb1, 0x7e, 0x88, 0xb9, 0xb5, + 0x50, 0x01, 0x7e, 0x84, 0x55, 0xc0, 0xab, 0x9c, + 0xca, 0xf5, 0xc1, 0x5d, 0xbe, 0x57, 0x0a, 0x80, + 0x1f, 0x93, 0x00, 0x34, 0xe6, 0xee, 0xc2, 0xee, + 0xff, 0x57, 0xc1, 0x66, 0x2a, 0x63, 0x4b, 0x23, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. var simnetGenesisMerkleRoot = externalapi.DomainHash{ - 0x47, 0x52, 0xc7, 0x23, 0x70, 0x4d, 0x89, 0x17, - 0xbd, 0x44, 0x26, 0xfa, 0x82, 0x7e, 0x1b, 0xa9, - 0xc6, 0x46, 0x1a, 0x37, 0x5a, 0x73, 0x88, 0x09, - 0xe8, 0x17, 0xff, 0xb1, 0xdb, 0x1a, 0xb3, 0x3f, + 0x79, 0x77, 0x9c, 0xad, 0x8d, 0x5a, 0x37, 0x57, + 0x75, 0x8b, 0x2f, 0xa5, 0x82, 0x47, 0x2f, 0xb6, + 0xbe, 0x24, 0x5f, 0xcb, 0x21, 0x68, 0x21, 0x44, + 0x45, 0x39, 0x44, 0xaf, 0xab, 0x9f, 0x0f, 0xc1, } // simnetGenesisBlock defines the genesis block of the block DAG which serves as the @@ -155,7 +155,7 @@ var simnetGenesisBlock = externalapi.DomainBlock{ UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x173001df3d5, Bits: 0x207fffff, - Nonce: 0x0, + Nonce: 1, }, Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } diff --git a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go index 3e22f59b3..1f216f33f 100644 --- a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go +++ b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go @@ -104,7 +104,7 @@ func New(consensus consensusexternalapi.Consensus, mempool miningmanagerapi.Memp // | <= policy.BlockMinSize) | | // ----------------------------------- -- -func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) *consensusexternalapi.DomainBlock { +func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) { mempoolTransactions := btb.mempool.Transactions() candidateTxs := make([]*candidateTx, 0, len(mempoolTransactions)) for _, tx := range mempoolTransactions { @@ -141,15 +141,16 @@ func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexterna btb.mempool.RemoveTransactions(invalidTxs) // We can call this recursively without worry because this should almost never happen return btb.GetBlockTemplate(coinbaseData) - } else if err != nil { - log.Errorf("GetBlockTemplate: Failed building block: %s", err) - return nil + } + + if err != nil { + return nil, err } log.Debugf("Created new block template (%d transactions, %d in fees, %d mass, target difficulty %064x)", len(blk.Transactions), blockTxs.totalFees, blockTxs.totalMass, util.CompactToBig(blk.Header.Bits)) - return blk + return blk, nil } // calcTxValue calculates a value to be used in transaction selection. diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index d048c3bd4..3e014f77a 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -7,6 +7,7 @@ package mempool import ( "container/list" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "sync" "time" @@ -90,7 +91,7 @@ type mempool struct { // transactions until they are mined into a block. func New(consensus consensusexternalapi.Consensus) miningmanagermodel.Mempool { policy := policy{ - MaxTxVersion: 0, + MaxTxVersion: constants.TransactionVersion, AcceptNonStd: false, MaxOrphanTxs: 5, MaxOrphanTxSize: 100000, @@ -614,8 +615,11 @@ func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransac // This will populate the missing UTXOEntries. err = mp.consensus.ValidateTransactionAndPopulateWithConsensusData(tx) missingOutpoints := ruleerrors.ErrMissingTxOut{} - if errors.As(err, &missingOutpoints) { - return missingOutpoints.MissingOutpoints, nil, nil + if err != nil { + if errors.As(err, &missingOutpoints) { + return missingOutpoints.MissingOutpoints, nil, nil + } + return nil, nil, err } // Don't allow transactions with non-standard inputs if the network @@ -636,22 +640,7 @@ func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransac } } - //// NOTE: if you modify this code to accept non-standard transactions, - //// you should add code here to check that the transaction does a - //// reasonable number of ECDSA signature verifications. - // - - // Don't allow transactions with fees too low to get into a mined block. - // - // Most miners allow a free transaction area in blocks they mine to go - // alongside the area used for high-priority transactions as well as - // transactions with fees. A transaction size of up to 1000 bytes is - // considered safe to go into this section. Further, the minimum fee - // calculated below on its own would encourage several small - // transactions to avoid fees rather than one single larger transaction - // which is more desirable. Therefore, as long as the size of the - // transaction does not exceeed 1000 less than the reserved space for - // high-priority transactions, don't require a fee for it. + // Don't allow transactions with fees too low to get into a mined block serializedSize := int64(estimatedsize.TransactionEstimatedSerializedSize(tx)) minFee := uint64(calcMinRequiredTxRelayFee(serializedSize, mp.policy.MinRelayTxFee)) diff --git a/domain/miningmanager/mempool/policy.go b/domain/miningmanager/mempool/policy.go index 6d786564a..ddbae216f 100644 --- a/domain/miningmanager/mempool/policy.go +++ b/domain/miningmanager/mempool/policy.go @@ -55,10 +55,9 @@ const ( // pool and relayed. func calcMinRequiredTxRelayFee(serializedSize int64, minRelayTxFee util.Amount) int64 { // Calculate the minimum fee for a transaction to be allowed into the - // mempool and relayed by scaling the base fee (which is the minimum - // free transaction relay fee). minTxRelayFee is in sompi/kB so - // multiply by serializedSize (which is in bytes) and divide by 1000 to - // get minimum sompis. + // mempool and relayed by scaling the base fee. minTxRelayFee is in + // sompi/kB so multiply by serializedSize (which is in bytes) and + // divide by 1000 to get minimum sompis. minFee := (serializedSize * int64(minRelayTxFee)) / 1000 if minFee == 0 && minRelayTxFee > 0 { diff --git a/domain/miningmanager/miningmanager.go b/domain/miningmanager/miningmanager.go index 307173bfd..a9e166bff 100644 --- a/domain/miningmanager/miningmanager.go +++ b/domain/miningmanager/miningmanager.go @@ -8,7 +8,7 @@ import ( // MiningManager creates block templates for mining as well as maintaining // known transactions that have no yet been added to any block type MiningManager interface { - GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) *consensusexternalapi.DomainBlock + GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error @@ -20,7 +20,7 @@ type miningManager struct { } // GetBlockTemplate creates a block template for a miner to consume -func (mm *miningManager) GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) *consensusexternalapi.DomainBlock { +func (mm *miningManager) GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) { return mm.blockTemplateBuilder.GetBlockTemplate(coinbaseData) } diff --git a/domain/miningmanager/model/interface_blocktemplatebuilder.go b/domain/miningmanager/model/interface_blocktemplatebuilder.go index efe7c668b..fbb2bfc39 100644 --- a/domain/miningmanager/model/interface_blocktemplatebuilder.go +++ b/domain/miningmanager/model/interface_blocktemplatebuilder.go @@ -6,5 +6,5 @@ import ( // BlockTemplateBuilder builds block templates for miners to consume type BlockTemplateBuilder interface { - GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) *consensusexternalapi.DomainBlock + GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go index 895615b22..3ac16aa0b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go @@ -14,6 +14,8 @@ func (x *KaspadMessage_IbdRootUTXOSetAndBlock) toAppMessage() (appmessage.Messag } func (x *KaspadMessage_IbdRootUTXOSetAndBlock) fromAppMessage(msgIBDRootUTXOSetAndBlock *appmessage.MsgIBDRootUTXOSetAndBlock) error { + x.IbdRootUTXOSetAndBlock = &IBDRootUTXOSetAndBlockMessage{} x.IbdRootUTXOSetAndBlock.UtxoSet = msgIBDRootUTXOSetAndBlock.UTXOSet + x.IbdRootUTXOSetAndBlock.Block = &BlockMessage{} return x.IbdRootUTXOSetAndBlock.Block.fromAppMessage(msgIBDRootUTXOSetAndBlock.Block) } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go index 1f8784f33..20c0247f5 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go @@ -14,7 +14,7 @@ func (x *KaspadMessage_RequestIBDBlocks) toAppMessage() (appmessage.Message, err if err != nil { return nil, err } - return &appmessage.MsgRequestRelayBlocks{Hashes: hashes}, nil + return &appmessage.MsgRequestIBDBlocks{Hashes: hashes}, nil } func (x *KaspadMessage_RequestIBDBlocks) fromAppMessage(msgRequestIBDBlocks *appmessage.MsgRequestIBDBlocks) error { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go index 934d36c72..d8eb8d65e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go @@ -13,6 +13,8 @@ func (x *KaspadMessage_RequestIBDRootUTXOSetAndBlock) toAppMessage() (appmessage func (x *KaspadMessage_RequestIBDRootUTXOSetAndBlock) fromAppMessage( msgRequestIBDRootUTXOSetAndBlock *appmessage.MsgRequestIBDRootUTXOSetAndBlock) error { + + x.RequestIBDRootUTXOSetAndBlock = &RequestIBDRootUTXOSetAndBlockMessage{} x.RequestIBDRootUTXOSetAndBlock.IbdRoot = domainHashToProto(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go index 4ba9bd747..13d7ff9c1 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go @@ -14,8 +14,7 @@ func (x *KaspadMessage_SubmitBlockRequest) toAppMessage() (appmessage.Message, e } func (x *KaspadMessage_SubmitBlockRequest) fromAppMessage(message *appmessage.SubmitBlockRequestMessage) error { - - x.SubmitBlockRequest = &SubmitBlockRequestMessage{} + x.SubmitBlockRequest = &SubmitBlockRequestMessage{Block: &BlockMessage{}} return x.SubmitBlockRequest.Block.fromAppMessage(message.Block) } diff --git a/infrastructure/network/rpcclient/rpc_get_connected_peer_info.go b/infrastructure/network/rpcclient/rpc_get_connected_peer_info.go index 021b5ee70..3ea48b457 100644 --- a/infrastructure/network/rpcclient/rpc_get_connected_peer_info.go +++ b/infrastructure/network/rpcclient/rpc_get_connected_peer_info.go @@ -12,9 +12,9 @@ func (c *RPCClient) GetConnectedPeerInfo() (*appmessage.GetConnectedPeerInfoResp if err != nil { return nil, err } - getMempoolEntryResponse := response.(*appmessage.GetConnectedPeerInfoResponseMessage) - if getMempoolEntryResponse.Error != nil { - return nil, c.convertRPCError(getMempoolEntryResponse.Error) + getConnectedPeerInfoResponse := response.(*appmessage.GetConnectedPeerInfoResponseMessage) + if getConnectedPeerInfoResponse.Error != nil { + return nil, c.convertRPCError(getConnectedPeerInfoResponse.Error) } - return getMempoolEntryResponse, nil + return getConnectedPeerInfoResponse, nil } diff --git a/testing/integration/64_incoming_connections_test.go b/testing/integration/64_incoming_connections_test.go new file mode 100644 index 000000000..edc3055ca --- /dev/null +++ b/testing/integration/64_incoming_connections_test.go @@ -0,0 +1,61 @@ +package integration + +import ( + "fmt" + "sync" + "testing" + "time" + + "github.com/kaspanet/kaspad/util/locks" + + "github.com/kaspanet/kaspad/app/appmessage" +) + +func Test64IncomingConnections(t *testing.T) { + // Much more than 64 hosts creates a risk of running out of available file descriptors for leveldb + const numBullies = 64 + harnessesParams := make([]*harnessParams, numBullies+1) + for i := 0; i < numBullies+1; i++ { + harnessesParams[i] = &harnessParams{ + p2pAddress: fmt.Sprintf("127.0.0.1:%d", 12345+i), + rpcAddress: fmt.Sprintf("127.0.0.1:%d", 22345+i), + miningAddress: miningAddress1, + miningAddressPrivateKey: miningAddress1PrivateKey, + } + } + + appHarnesses, teardown := setupHarnesses(t, harnessesParams) + defer teardown() + + victim, bullies := appHarnesses[0], appHarnesses[1:] + + for _, bully := range bullies { + connect(t, victim, bully) + } + + blockAddedWG := sync.WaitGroup{} + blockAddedWG.Add(numBullies) + for _, bully := range bullies { + blockAdded := false + onBlockAdded := func(_ *appmessage.BlockAddedNotificationMessage) { + if blockAdded { + t.Fatalf("Single bully reported block added twice") + } + blockAdded = true + blockAddedWG.Done() + } + + err := bully.rpcClient.RegisterForBlockAddedNotifications(onBlockAdded) + if err != nil { + t.Fatalf("Error from RegisterForBlockAddedNotifications: %+v", err) + } + } + + _ = mineNextBlock(t, victim) + + select { + case <-time.After(defaultTimeout): + t.Fatalf("Timeout waiting for block added notification from the bullies") + case <-locks.ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }): + } +} diff --git a/testing/integration/address_exchange_test.go b/testing/integration/address_exchange_test.go new file mode 100644 index 000000000..fc59b268f --- /dev/null +++ b/testing/integration/address_exchange_test.go @@ -0,0 +1,33 @@ +package integration + +import ( + "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" + "testing" +) + +func TestAddressExchange(t *testing.T) { + appHarness1, appHarness2, appHarness3, teardown := standardSetup(t) + defer teardown() + + testAddress := "1.2.3.4:6789" + err := addressmanager.AddAddressByIP(appHarness1.app.AddressManager(), testAddress, nil) + if err != nil { + t.Fatalf("Error adding address to addressManager: %+v", err) + } + + connect(t, appHarness1, appHarness2) + connect(t, appHarness2, appHarness3) + + peerAddresses, err := appHarness3.rpcClient.GetPeerAddresses() + if err != nil { + t.Fatalf("Error getting peer addresses: %+v", err) + } + + for _, peerAddress := range peerAddresses.Addresses { + if peerAddress.Addr == testAddress { + return + } + } + + t.Errorf("Didn't find testAddress in list of addresses of appHarness3") +} diff --git a/testing/integration/basic_sync_test.go b/testing/integration/basic_sync_test.go new file mode 100644 index 000000000..4dbb05517 --- /dev/null +++ b/testing/integration/basic_sync_test.go @@ -0,0 +1,55 @@ +package integration + +import ( + "testing" + "time" + + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + + "github.com/kaspanet/kaspad/app/appmessage" +) + +func TestIntegrationBasicSync(t *testing.T) { + appHarness1, appHarness2, appHarness3, teardown := standardSetup(t) + defer teardown() + + // Connect nodes in chain: 1 <--> 2 <--> 3 + // So that node 3 doesn't directly get blocks from node 1 + connect(t, appHarness1, appHarness2) + connect(t, appHarness2, appHarness3) + + app2OnBlockAddedChan := make(chan *appmessage.MsgBlockHeader) + setOnBlockAddedHandler(t, appHarness2, func(notification *appmessage.BlockAddedNotificationMessage) { + app2OnBlockAddedChan <- ¬ification.Block.Header + }) + + app3OnBlockAddedChan := make(chan *appmessage.MsgBlockHeader) + setOnBlockAddedHandler(t, appHarness3, func(notification *appmessage.BlockAddedNotificationMessage) { + app3OnBlockAddedChan <- ¬ification.Block.Header + }) + + block := mineNextBlock(t, appHarness1) + + var header *appmessage.MsgBlockHeader + select { + case header = <-app2OnBlockAddedChan: + case <-time.After(defaultTimeout): + t.Fatalf("Timeout waiting for block added notification on node directly connected to miner") + } + + blockHash := consensusserialization.BlockHash(block) + if *header.BlockHash() != *blockHash { + t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash()) + } + + select { + case header = <-app3OnBlockAddedChan: + case <-time.After(defaultTimeout): + t.Fatalf("Timeout waiting for block added notification on node indirectly connected to miner") + } + + blockHash = consensusserialization.BlockHash(block) + if *header.BlockHash() != *blockHash { + t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash()) + } +} diff --git a/testing/integration/config_test.go b/testing/integration/config_test.go new file mode 100644 index 000000000..4089d6cf3 --- /dev/null +++ b/testing/integration/config_test.go @@ -0,0 +1,59 @@ +package integration + +import ( + "io/ioutil" + "testing" + "time" + + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/config" +) + +const ( + p2pAddress1 = "127.0.0.1:54321" + p2pAddress2 = "127.0.0.1:54322" + p2pAddress3 = "127.0.0.1:54323" + + rpcAddress1 = "127.0.0.1:12345" + rpcAddress2 = "127.0.0.1:12346" + rpcAddress3 = "127.0.0.1:12347" + + miningAddress1 = "kaspasim:qzmdkk8ay8sgvp8cnwts8gtdylz9j7572slwdh85qv" + miningAddress1PrivateKey = "be9e9884f03e687166479e22d21b064db7903d69b5a46878aae66521c01a6094" + + miningAddress2 = "kaspasim:qze20hwkc4lzq37jt0hrym5emlsxxs8j3qyf3y4ghs" + miningAddress2PrivateKey = "98bd8d8e1f7078abefd017839f83edd0e3c8226ed4989e4d7a8bceb5935de193" + + miningAddress3 = "kaspasim:qretklduvhg5h2aj7jd8w4heq7pvtkpv9q6w4sqfen" + miningAddress3PrivateKey = "eb0af684f2cdbb4ed2d85fbfe0b7f40654a7777fb2c47f142ffb5543b594d1e4" + + defaultTimeout = 10 * time.Second +) + +func setConfig(t *testing.T, harness *appHarness) { + harness.config = commonConfig() + harness.config.DataDir = randomDirectory(t) + harness.config.Listeners = []string{harness.p2pAddress} + harness.config.RPCListeners = []string{harness.rpcAddress} +} + +func commonConfig() *config.Config { + commonConfig := config.DefaultConfig() + + *commonConfig.ActiveNetParams = dagconfig.SimnetParams // Copy so that we can make changes safely + commonConfig.ActiveNetParams.BlockCoinbaseMaturity = 10 + commonConfig.TargetOutboundPeers = 0 + commonConfig.DisableDNSSeed = true + commonConfig.Simnet = true + + return commonConfig +} + +func randomDirectory(t *testing.T) string { + dir, err := ioutil.TempDir("", "integration-test") + if err != nil { + t.Fatalf("Error creating temporary directory for test: %+v", err) + } + + return dir +} diff --git a/testing/integration/connect_test.go b/testing/integration/connect_test.go new file mode 100644 index 000000000..9d13cf19f --- /dev/null +++ b/testing/integration/connect_test.go @@ -0,0 +1,70 @@ +package integration + +import ( + "testing" + "time" +) + +func connect(t *testing.T, incoming, outgoing *appHarness) { + err := outgoing.rpcClient.AddPeer(incoming.p2pAddress, false) + if err != nil { + t.Fatalf("Error connecting the nodes") + } + + onConnectedChan := make(chan struct{}) + abortConnectionChan := make(chan struct{}) + defer close(abortConnectionChan) + + spawn("integration.connect-Wait for connection", func() { + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + + for range ticker.C { + if isConnected(t, incoming, outgoing) { + close(onConnectedChan) + return + } + + select { + case <-abortConnectionChan: + return + default: + } + } + }) + + select { + case <-onConnectedChan: + case <-time.After(defaultTimeout): + t.Fatalf("Timed out waiting for the apps to connect") + } +} +func isConnected(t *testing.T, appHarness1, appHarness2 *appHarness) bool { + connectedPeerInfo1, err := appHarness1.rpcClient.GetConnectedPeerInfo() + if err != nil { + t.Fatalf("Error getting connected peer info for app1: %+v", err) + } + connectedPeerInfo2, err := appHarness2.rpcClient.GetConnectedPeerInfo() + if err != nil { + t.Fatalf("Error getting connected peer info for app2: %+v", err) + } + + var incomingConnected, outgoingConnected bool + app1ID, app2ID := appHarness1.app.P2PNodeID().String(), appHarness2.app.P2PNodeID().String() + + for _, connectedPeer := range connectedPeerInfo1.Infos { + if connectedPeer.ID == app2ID { + incomingConnected = true + break + } + } + + for _, connectedPeer := range connectedPeerInfo2.Infos { + if connectedPeer.ID == app1ID { + outgoingConnected = true + break + } + } + + return incomingConnected && outgoingConnected +} diff --git a/testing/integration/ibd_test.go b/testing/integration/ibd_test.go new file mode 100644 index 000000000..1fb26ca67 --- /dev/null +++ b/testing/integration/ibd_test.go @@ -0,0 +1,51 @@ +package integration + +import ( + "sync" + "testing" + "time" + + "github.com/kaspanet/kaspad/util/locks" + + "github.com/kaspanet/kaspad/app/appmessage" +) + +func TestIBD(t *testing.T) { + const numBlocks = 100 + + syncer, syncee, _, teardown := standardSetup(t) + defer teardown() + + for i := 0; i < numBlocks; i++ { + mineNextBlock(t, syncer) + } + + blockAddedWG := sync.WaitGroup{} + blockAddedWG.Add(numBlocks) + receivedBlocks := 0 + setOnBlockAddedHandler(t, syncee, func(_ *appmessage.BlockAddedNotificationMessage) { + receivedBlocks++ + blockAddedWG.Done() + }) + + connect(t, syncer, syncee) + + select { + case <-time.After(defaultTimeout): + t.Fatalf("Timeout waiting for IBD to finish. Received %d blocks out of %d", receivedBlocks, numBlocks) + case <-locks.ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }): + } + + tip1Hash, err := syncer.rpcClient.GetSelectedTipHash() + if err != nil { + t.Fatalf("Error getting tip for syncer") + } + tip2Hash, err := syncee.rpcClient.GetSelectedTipHash() + if err != nil { + t.Fatalf("Error getting tip for syncee") + } + + if tip1Hash.SelectedTipHash != tip2Hash.SelectedTipHash { + t.Errorf("Tips of syncer: '%s' and syncee '%s' are not equal", tip1Hash.SelectedTipHash, tip2Hash.SelectedTipHash) + } +} diff --git a/testing/integration/log_test.go b/testing/integration/log_test.go new file mode 100644 index 000000000..d0b28f9d7 --- /dev/null +++ b/testing/integration/log_test.go @@ -0,0 +1,14 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2017 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package integration + +import ( + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/kaspanet/kaspad/util/panics" +) + +var log, _ = logger.Get(logger.SubsystemTags.KASD) +var spawn = panics.GoroutineWrapperFunc(log) diff --git a/testing/integration/main_test.go b/testing/integration/main_test.go new file mode 100644 index 000000000..1b474c634 --- /dev/null +++ b/testing/integration/main_test.go @@ -0,0 +1,14 @@ +package integration + +import ( + "os" + "testing" + + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +func TestMain(m *testing.M) { + logger.SetLogLevels("debug") + + os.Exit(m.Run()) +} diff --git a/testing/integration/mining_test.go b/testing/integration/mining_test.go new file mode 100644 index 000000000..8e2281c82 --- /dev/null +++ b/testing/integration/mining_test.go @@ -0,0 +1,46 @@ +package integration + +import ( + "math/rand" + "testing" + + "github.com/kaspanet/kaspad/app/appmessage" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + + "github.com/kaspanet/kaspad/util" +) + +func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock { + targetDifficulty := util.CompactToBig(block.Header.Bits) + initialNonce := rand.Uint64() + for i := initialNonce; i != initialNonce-1; i++ { + block.Header.Nonce = i + hash := consensusserialization.BlockHash(block) + if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { + return block + } + } + + panic("Failed to solve block! This should never happen") +} + +func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock { + blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress) + if err != nil { + t.Fatalf("Error getting block template: %+v", err) + } + + block := appmessage.MsgBlockToDomainBlock(blockTemplate.MsgBlock) + + solveBlock(block) + + err = harness.rpcClient.SubmitBlock(block) + if err != nil { + t.Fatalf("Error submitting block: %s", err) + } + + return block +} diff --git a/testing/integration/notifications_test.go b/testing/integration/notifications_test.go new file mode 100644 index 000000000..368927955 --- /dev/null +++ b/testing/integration/notifications_test.go @@ -0,0 +1,14 @@ +package integration + +import ( + "testing" + + "github.com/kaspanet/kaspad/app/appmessage" +) + +func setOnBlockAddedHandler(t *testing.T, harness *appHarness, handler func(notification *appmessage.BlockAddedNotificationMessage)) { + err := harness.rpcClient.RegisterForBlockAddedNotifications(handler) + if err != nil { + t.Fatalf("Error from RegisterForBlockAddedNotifications: %s", err) + } +} diff --git a/testing/integration/rpc_test.go b/testing/integration/rpc_test.go new file mode 100644 index 000000000..3d07a1959 --- /dev/null +++ b/testing/integration/rpc_test.go @@ -0,0 +1,24 @@ +package integration + +import ( + "github.com/kaspanet/kaspad/infrastructure/network/rpcclient" + "time" +) + +const rpcTimeout = 1 * time.Second + +type testRPCClient struct { + *rpcclient.RPCClient +} + +func newTestRPCClient(rpcAddress string) (*testRPCClient, error) { + rpcClient, err := rpcclient.NewRPCClient(rpcAddress) + if err != nil { + return nil, err + } + rpcClient.SetTimeout(rpcTimeout) + + return &testRPCClient{ + RPCClient: rpcClient, + }, nil +} diff --git a/testing/integration/setup_test.go b/testing/integration/setup_test.go new file mode 100644 index 000000000..174d49603 --- /dev/null +++ b/testing/integration/setup_test.go @@ -0,0 +1,131 @@ +package integration + +import ( + "path/filepath" + "testing" + + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" + + "github.com/kaspanet/kaspad/infrastructure/db/database" + + "github.com/kaspanet/kaspad/app" + "github.com/kaspanet/kaspad/infrastructure/config" +) + +type appHarness struct { + app *app.ComponentManager + rpcClient *testRPCClient + p2pAddress string + rpcAddress string + miningAddress string + miningAddressPrivateKey string + config *config.Config + database database.Database +} + +type harnessParams struct { + p2pAddress string + rpcAddress string + miningAddress string + miningAddressPrivateKey string +} + +// setupHarness creates a single appHarness with given parameters +func setupHarness(t *testing.T, params *harnessParams) (harness *appHarness, teardownFunc func()) { + harness = &appHarness{ + p2pAddress: params.p2pAddress, + rpcAddress: params.rpcAddress, + miningAddress: params.miningAddress, + miningAddressPrivateKey: params.miningAddressPrivateKey, + } + + setConfig(t, harness) + setDatabaseContext(t, harness) + setApp(t, harness) + harness.app.Start() + setRPCClient(t, harness) + + return harness, func() { + teardownHarness(t, harness) + } +} + +// setupHarnesses creates multiple appHarnesses, according to number of parameters passed +func setupHarnesses(t *testing.T, harnessesParams []*harnessParams) (harnesses []*appHarness, teardownFunc func()) { + var teardowns []func() + for _, params := range harnessesParams { + harness, teardownFunc := setupHarness(t, params) + harnesses = append(harnesses, harness) + teardowns = append(teardowns, teardownFunc) + } + + return harnesses, func() { + for _, teardownFunc := range teardowns { + teardownFunc() + } + } +} + +// standardSetup creates a standard setup of 3 appHarnesses that should work for most tests +func standardSetup(t *testing.T) (appHarness1, appHarness2, appHarness3 *appHarness, teardownFunc func()) { + harnesses, teardown := setupHarnesses(t, []*harnessParams{ + { + p2pAddress: p2pAddress1, + rpcAddress: rpcAddress1, + miningAddress: miningAddress1, + miningAddressPrivateKey: miningAddress1PrivateKey, + }, + { + p2pAddress: p2pAddress2, + rpcAddress: rpcAddress2, + miningAddress: miningAddress2, + miningAddressPrivateKey: miningAddress2PrivateKey, + }, { + p2pAddress: p2pAddress3, + rpcAddress: rpcAddress3, + miningAddress: miningAddress3, + miningAddressPrivateKey: miningAddress3PrivateKey, + }, + }) + + return harnesses[0], harnesses[1], harnesses[2], teardown +} + +func setRPCClient(t *testing.T, harness *appHarness) { + var err error + harness.rpcClient, err = newTestRPCClient(harness.rpcAddress) + if err != nil { + t.Fatalf("Error getting RPC client %+v", err) + } +} + +func teardownHarness(t *testing.T, harness *appHarness) { + harness.rpcClient.Close() + harness.app.Stop() + + err := harness.database.Close() + if err != nil { + t.Errorf("Error closing database context: %+v", err) + } +} + +func setApp(t *testing.T, harness *appHarness) { + var err error + harness.app, err = app.NewComponentManager(harness.config, harness.database, make(chan struct{})) + if err != nil { + t.Fatalf("Error creating app: %+v", err) + } +} + +func setDatabaseContext(t *testing.T, harness *appHarness) { + var err error + harness.database, err = openDB(harness.config) + if err != nil { + t.Fatalf("Error openning database: %+v", err) + } +} + +func openDB(cfg *config.Config) (database.Database, error) { + dbPath := filepath.Join(cfg.DataDir, "db") + return ldb.NewLevelDB(dbPath) +} diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go new file mode 100644 index 000000000..f2c22425f --- /dev/null +++ b/testing/integration/tx_relay_test.go @@ -0,0 +1,125 @@ +package integration + +import ( + "encoding/hex" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "strings" + "testing" + "time" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/util" +) + +func TestTxRelay(t *testing.T) { + payer, mediator, payee, teardown := standardSetup(t) + defer teardown() + + // Connect nodes in chain: payer <--> mediator <--> payee + // So that payee doesn't directly get transactions from payer + connect(t, payer, mediator) + connect(t, mediator, payee) + + payeeBlockAddedChan := make(chan *appmessage.MsgBlockHeader) + setOnBlockAddedHandler(t, payee, func(notification *appmessage.BlockAddedNotificationMessage) { + payeeBlockAddedChan <- ¬ification.Block.Header + }) + // skip the first block because it's paying to genesis script + mineNextBlock(t, payer) + waitForPayeeToReceiveBlock(t, payeeBlockAddedChan) + // use the second block to get money to pay with + secondBlock := mineNextBlock(t, payer) + waitForPayeeToReceiveBlock(t, payeeBlockAddedChan) + + // Mine BlockCoinbaseMaturity more blocks for our money to mature + for i := uint64(0); i < payer.config.ActiveNetParams.BlockCoinbaseMaturity; i++ { + mineNextBlock(t, payer) + waitForPayeeToReceiveBlock(t, payeeBlockAddedChan) + } + + tx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee) + response, err := payer.rpcClient.SubmitTransaction(tx) + if err != nil { + t.Fatalf("Error submitting transaction: %+v", err) + } + txID := response.TxID + + txAddedToMempoolChan := make(chan struct{}) + + spawn("TestTxRelay-WaitForTransactionPropagation", func() { + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + + for range ticker.C { + _, err := payee.rpcClient.GetMempoolEntry(txID) + if err != nil { + if strings.Contains(err.Error(), "transaction is not in the pool") { + continue + } + + t.Fatalf("Error getting mempool entry: %+v", err) + } + close(txAddedToMempoolChan) + return + } + }) + + select { + case <-txAddedToMempoolChan: + case <-time.After(defaultTimeout): + t.Fatalf("Timeout waiting for transaction to be accepted into mempool") + } +} + +func waitForPayeeToReceiveBlock(t *testing.T, payeeBlockAddedChan chan *appmessage.MsgBlockHeader) { + select { + case <-payeeBlockAddedChan: + case <-time.After(defaultTimeout): + t.Fatalf("Timeout waiting for block added") + } +} + +func generateTx(t *testing.T, firstBlockCoinbase *externalapi.DomainTransaction, payer, payee *appHarness) *appmessage.MsgTx { + txIns := make([]*appmessage.TxIn, 1) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensusserialization.TransactionID(firstBlockCoinbase), 0), []byte{}) + + payeeAddress, err := util.DecodeAddress(payee.miningAddress, util.Bech32PrefixKaspaSim) + if err != nil { + t.Fatalf("Error decoding payeeAddress: %+v", err) + } + toScript, err := txscript.PayToAddrScript(payeeAddress) + if err != nil { + t.Fatalf("Error generating script: %+v", err) + } + + txOuts := []*appmessage.TxOut{appmessage.NewTxOut(firstBlockCoinbase.Outputs[0].Value-1000, toScript)} + + fromScript := firstBlockCoinbase.Outputs[0].ScriptPublicKey + + tx := appmessage.NewNativeMsgTx(constants.TransactionVersion, txIns, txOuts) + + privateKeyBytes, err := hex.DecodeString(payer.miningAddressPrivateKey) + if err != nil { + t.Fatalf("Error decoding private key: %+v", err) + } + privateKey, err := secp256k1.DeserializePrivateKeyFromSlice(privateKeyBytes) + if err != nil { + t.Fatalf("Error deserializing private key: %+v", err) + } + + signatureScript, err := txscript.SignatureScript(appmessage.MsgTxToDomainTransaction(tx), 0, + fromScript, txscript.SigHashAll, privateKey, true) + if err != nil { + t.Fatalf("Error signing transaction: %+v", err) + } + tx.TxIn[0].SignatureScript = signatureScript + + return tx +} From f320887bffbfa4483e08e9622aa9c736be06c118 Mon Sep 17 00:00:00 2001 From: stasatdaglabs Date: Sun, 15 Nov 2020 11:15:27 +0200 Subject: [PATCH 018/351] [NOD-1538] Fix bad allocation in notBannedAddressesWithException. --- .../network/addressmanager/addressmanager.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/infrastructure/network/addressmanager/addressmanager.go b/infrastructure/network/addressmanager/addressmanager.go index e78c321d6..bd53d1015 100644 --- a/infrastructure/network/addressmanager/addressmanager.go +++ b/infrastructure/network/addressmanager/addressmanager.go @@ -141,13 +141,13 @@ func (am *AddressManager) BannedAddresses() []*appmessage.NetAddress { return result } -// NotBannedAddressesWithException returns all not banned addresses with excpetion -func (am *AddressManager) NotBannedAddressesWithException(exceptions []*appmessage.NetAddress) []*appmessage.NetAddress { +// notBannedAddressesWithException returns all not banned addresses with excpetion +func (am *AddressManager) notBannedAddressesWithException(exceptions []*appmessage.NetAddress) []*appmessage.NetAddress { exceptionsKeys := netAddressesKeys(exceptions) am.mutex.Lock() defer am.mutex.Unlock() - result := make([]*appmessage.NetAddress, 0, len(am.addresses)-len(exceptions)) + result := make([]*appmessage.NetAddress, 0, len(am.addresses)) for key, address := range am.addresses { if !exceptionsKeys[key] { result = append(result, address) @@ -159,13 +159,13 @@ func (am *AddressManager) NotBannedAddressesWithException(exceptions []*appmessa // RandomAddress returns a random address that isn't banned and isn't in exceptions func (am *AddressManager) RandomAddress(exceptions []*appmessage.NetAddress) *appmessage.NetAddress { - validAddresses := am.NotBannedAddressesWithException(exceptions) + validAddresses := am.notBannedAddressesWithException(exceptions) return am.random.RandomAddress(validAddresses) } // RandomAddresses returns count addresses at random that aren't banned and aren't in exceptions func (am *AddressManager) RandomAddresses(count int, exceptions []*appmessage.NetAddress) []*appmessage.NetAddress { - validAddresses := am.NotBannedAddressesWithException(exceptions) + validAddresses := am.notBannedAddressesWithException(exceptions) return am.random.RandomAddresses(validAddresses, count) } From 8ccf381fc754c4f3220e2f6ae53135c6eda8ed03 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 15 Nov 2020 13:09:10 +0200 Subject: [PATCH 019/351] [NOD-1532] csm unit tests (#1059) * Revert "[NOD-1500] Delete integration tests" This reverts commit fcb57a206690a884fa6afb69d5d493282954a8bf. * [NOD-1518] hashserialization -> consenusserialization * [NOD-1518] Fix add genesis to virtual * [NOD-1518] Fix a bug in SerializeCoinbasePayload. * [NOD-1518] Fix a loop error and make pastMedianTime behave correctly everywhere on genesis. * [NOD-1518] Fix another bug and an infinite loop. * [NOD-1518] Fix uninitialized slice. * [NOD-1518] Fix bad should-commit checks and another infinite loop. * [NOD-1518] Fix nil serialization. * [NOD-1518] Rename blockHash to currentBlockHash. * [NOD-1518] Move the check whether stagedVirtualUTXOSet != nil to the top of commitVirtualUTXODiff. * [NOD-1518] Simplify utxoDiffStore.Commit. * [NOD-1518] Unextract resolveBlockStatusAndCheckFinality. * [NOD-1518] Move no-transactions logic into CalculateIDMerkleRoot. * [NOD-1518] Remove redundant is-staged check. * [NOD-1518] Fix merge errors. * [NOD-1518] Don't write anything if utxoDiffChild is nil. * [NOD-1518] Stage virtualAcceptanceData and virtualMultiset. * [NOD-1518] Fix bugs in getBlockTemplate and submitBlock. * [NOD-1518] Fix bad validation order in validateHeaderInContext. * [NOD-1518] Fix bug in Next(). * [NOD-1518] Fix nil dereference of subnetworks in AddressCache. * [NOD-1518] Fix multisetStore.Get returning a pointer to a multiset that is changed in place. * [NOD-1518] Break on genesis in countSubtrees. * [NOD-1518] Fix createBlockLocator. * [NOD-1518] Fix MsgTxToDomainTransaction. * [NOD-1518] Set MaxTxVersion to 1. * [NOD-1518] Fix missing error handling, bug in MsgTxToDomainTransaction, and bad subnetwork equality check. * [NOD-1518] Fix bug in hasUTXOByOutpointFromStagedVirtualUTXODiff. * [NOD-1518] Remove irrelevant comments. * [NOD-1518] Generate transactions with sufficient fee in tx_relay_test. * [NOD-1518] Fix broken RPC handlers. * [NOD-1518] Fix merge errors. * [NOD-1518] Fix bad exists check in restorePastUTXO and missing genesis check in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Add a comment. * [NOD-1518] Use a regular mutex instead of a read-write mutex in consensus to avoid dealing with sneaky not-actually-read functions. * [NOD-1518] Fix a deadlock in GetVirtualSelectedParent. * [NOD-1518] Fix missing handler registration for CmdHeader. * [NOD-1518] Fix processHeader calling OnNewBlock and LogBlock. Also fix conversion errors in IBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad Command() in MsgIBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad SyncStateMissingUTXOSet logic in resolveSyncState. * [NOD-1518] Rename mode to syncState. * [NOD-1518] Fix headers-only blocks coming in after the consensus thinks it's synced. * [NOD-1518] Fix selectedChildIterator.Next not ignoring virtual, infinite loop in HashSet.Length(). * [NOD-1518] Fix not-properly wrapped IBD blocks. * [NOD-1532] Add TestMultiset * [NOD-1518] Fix bad conversion in RequestIBDBlocks. * [NOD-1518] Fix bad string for CmdRequestHeaders. * [NOD-1518] Fix bad string for CmdDoneHeaders. * [NOD-1518] Fix bad Command() for MsgIBDRootNotFound. * [NOD-1532] Add TestPastUTXOMultiset * [NOD-1518] Fix bad areHeaderTipsSyncedMaxTimeDifference value. * [NOD-1532] Added TestDoubleSpends * [NOD-1518] Add missing string for CmdRequestIBDBlocks. * [NOD-1518] Fix bad check for SyncStateMissingBlockBodies. * [NOD-1518] Fix bad timeout durations in tests. * [NOD-1518] Fix IBD blocks not calling OnNewBlock. * [NOD-1518] Change when IBD finishes. * [NOD-1518] Properly clone utxoDiffChild. * [NOD-1532] Update hashes of blocks * [NOD-1532] Fix genesis blocks and a few more bugs * [NOD-1532] Bugfix: incorrect key passed to dbTx.Put * [NOD-1532] Make sure there's no nil payloads * [NOD-1532] Fix AddBlockToVirtual * [NOD-1532] Update tips and virtualDiffParents properly * [NOD-1532] Allow nil payload * [NOD-1532] Check for actual error and not just some RuleError * [NOD-1532] Get rid of SimpleCoinbaseData and make OpTrueScript P2SH * [NOD-1532] If coinbaseData is nil - fill in with generic coinbaseData Co-authored-by: Ori Newman Co-authored-by: stasatdaglabs --- .../consensusstatestore/tips.go | 4 + .../virtual_diff_parents.go | 4 + .../utxodiffstore/utxodiffstore.go | 24 ++- domain/consensus/factory.go | 9 +- .../model/externalapi/blockstatus.go | 12 ++ ...terface_processes_consensusstatemanager.go | 8 + .../consensus/model/testapi/test_consensus.go | 6 +- .../blockbuilder/test_block_builder.go | 2 +- .../add_block_to_virtual.go | 45 ++++-- .../calculate_past_utxo.go | 4 + .../calculate_past_utxo_test.go | 142 +++++++++++++++++ ...emanager.go => consensus_state_manager.go} | 0 .../resolve_block_status_test.go | 150 ++++++++++++++++++ .../test_consensus_state_manager.go | 24 +++ .../consensusstatemanager/update_virtual.go | 60 ++++--- .../processes/reachabilitymanager/tree.go | 5 +- .../transaction_in_isolation.go | 13 -- domain/consensus/test_consensus.go | 16 +- domain/consensus/test_consensus_getters.go | 17 +- .../utils/testutils/create_transaction.go | 39 +++++ .../consensus/utils/testutils/for_all_nets.go | 2 +- .../utils/testutils/op_true_script.go | 15 ++ domain/dagconfig/genesis.go | 62 ++++---- domain/miningmanager/mempool/mempool.go | 3 +- testing/integration/tx_relay_test.go | 3 +- 25 files changed, 559 insertions(+), 110 deletions(-) create mode 100644 domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go rename domain/consensus/processes/consensusstatemanager/{consensusstatemanager.go => consensus_state_manager.go} (100%) create mode 100644 domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go create mode 100644 domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go create mode 100644 domain/consensus/utils/testutils/create_transaction.go create mode 100644 domain/consensus/utils/testutils/op_true_script.go diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go index 1e64a9354..60fab19e3 100644 --- a/domain/consensus/datastructures/consensusstatestore/tips.go +++ b/domain/consensus/datastructures/consensusstatestore/tips.go @@ -34,6 +34,10 @@ func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) err } func (c *consensusStateStore) commitTips(dbTx model.DBTransaction) error { + if c.stagedTips == nil { + return nil + } + tipsBytes, err := c.serializeTips(c.stagedTips) if err != nil { return err diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go index 3a9b3ff3c..006353479 100644 --- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go +++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go @@ -34,6 +34,10 @@ func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.D } func (c *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { + if c.stagedVirtualDiffParents == nil { + return nil + } + virtualDiffParentsBytes, err := c.serializeVirtualDiffParents(c.stagedVirtualDiffParents) if err != nil { return err diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index d053d9d2a..584424009 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/pkg/errors" ) var utxoDiffBucket = dbkeys.MakeBucket([]byte("utxo-diffs")) @@ -73,11 +74,15 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { } } for hash, utxoDiffChild := range uds.utxoDiffChildStaging { + if utxoDiffChild == nil { + continue + } + utxoDiffChildBytes, err := uds.serializeUTXODiffChild(utxoDiffChild) if err != nil { return err } - err = dbTx.Put(uds.utxoDiffHashAsKey(&hash), utxoDiffChildBytes) + err = dbTx.Put(uds.utxoDiffChildHashAsKey(&hash), utxoDiffChildBytes) if err != nil { return err } @@ -163,28 +168,37 @@ func (uds *utxoDiffStore) utxoDiffChildHashAsKey(hash *externalapi.DomainHash) m } func (uds *utxoDiffStore) serializeUTXODiff(utxoDiff *model.UTXODiff) ([]byte, error) { - return proto.Marshal(serialization.UTXODiffToDBUTXODiff(utxoDiff)) + dbUtxoDiff := serialization.UTXODiffToDBUTXODiff(utxoDiff) + bytes, err := proto.Marshal(dbUtxoDiff) + if err != nil { + return nil, errors.WithStack(err) + } + return bytes, nil } func (uds *utxoDiffStore) deserializeUTXODiff(utxoDiffBytes []byte) (*model.UTXODiff, error) { dbUTXODiff := &serialization.DbUtxoDiff{} err := proto.Unmarshal(utxoDiffBytes, dbUTXODiff) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return serialization.DBUTXODiffToUTXODiff(dbUTXODiff) } func (uds *utxoDiffStore) serializeUTXODiffChild(utxoDiffChild *externalapi.DomainHash) ([]byte, error) { - return proto.Marshal(serialization.DomainHashToDbHash(utxoDiffChild)) + bytes, err := proto.Marshal(serialization.DomainHashToDbHash(utxoDiffChild)) + if err != nil { + return nil, errors.WithStack(err) + } + return bytes, nil } func (uds *utxoDiffStore) deserializeUTXODiffChild(utxoDiffChildBytes []byte) (*externalapi.DomainHash, error) { dbHash := &serialization.DbHash{} err := proto.Unmarshal(utxoDiffChildBytes, dbHash) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return serialization.DbHashToDomainHash(dbHash) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 017b565fb..3ad5c924b 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -120,7 +120,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore, acceptanceDataStore) headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore) - genesisHash := (*externalapi.DomainHash)(dagParams.GenesisHash) + genesisHash := dagParams.GenesisHash mergeDepthManager := mergedepthmanager.New( dagParams.FinalityDepth(), dbManager, @@ -317,9 +317,12 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) consensusAsImplementation := consensusAsInterface.(*consensus) + testBlockBuilder := blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder) + testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager) tc = &testConsensus{ - consensus: consensusAsImplementation, - testBlockBuilder: blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder), + consensus: consensusAsImplementation, + testBlockBuilder: testBlockBuilder, + testConsensusStateManager: testConsensusStateManager, } teardown = func() { db.Close() diff --git a/domain/consensus/model/externalapi/blockstatus.go b/domain/consensus/model/externalapi/blockstatus.go index 813e96115..50a9b848b 100644 --- a/domain/consensus/model/externalapi/blockstatus.go +++ b/domain/consensus/model/externalapi/blockstatus.go @@ -21,3 +21,15 @@ const ( // StatusHeaderOnly indicates that the block transactions are not held (pruned or wasn't added yet) StatusHeaderOnly ) + +var blockStatusStrings = map[BlockStatus]string{ + StatusInvalid: "Invalid", + StatusValid: "Valid", + StatusUTXOPendingVerification: "UTXOPendingVerification", + StatusDisqualifiedFromChain: "DisqualifiedFromChain", + StatusHeaderOnly: "HeaderOnly", +} + +func (bs BlockStatus) String() string { + return blockStatusStrings[bs] +} diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 5f4dc783e..78dc6c5d9 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -11,3 +11,11 @@ type ConsensusStateManager interface { HeaderTipsPruningPoint() (*externalapi.DomainHash, error) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (*UTXODiff, AcceptanceData, Multiset, error) } + +// TestConsensusStateManager adds to the main ConsensusStateManager methods required by tests +type TestConsensusStateManager interface { + ConsensusStateManager + AddUTXOToMultiset(multiset Multiset, entry *externalapi.UTXOEntry, + outpoint *externalapi.DomainOutpoint) error + ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) +} diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 1a1e994bc..0adee43b1 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -17,6 +17,8 @@ type TestConsensus interface { AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error) + DatabaseContext() model.DBReader + AcceptanceDataStore() model.AcceptanceDataStore BlockHeaderStore() model.BlockHeaderStore BlockRelationStore() model.BlockRelationStore @@ -30,11 +32,11 @@ type TestConsensus interface { ReachabilityDataStore() model.ReachabilityDataStore UTXODiffStore() model.UTXODiffStore - BlockBuilder() model.BlockBuilder + BlockBuilder() model.TestBlockBuilder BlockProcessor() model.BlockProcessor BlockValidator() model.BlockValidator CoinbaseManager() model.CoinbaseManager - ConsensusStateManager() model.ConsensusStateManager + ConsensusStateManager() model.TestConsensusStateManager DAGTopologyManager() model.DAGTopologyManager DAGTraversalManager() model.DAGTraversalManager DifficultyManager() model.DifficultyManager diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 93995a28c..9fc25779a 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -94,7 +94,7 @@ func (bb *testBlockBuilder) buildBlockWithParents( } transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...) - header, err := bb.buildHeaderWithParents(parentHashes, transactions, acceptanceData, multiset) + header, err := bb.buildHeaderWithParents(parentHashes, transactionsWithCoinbase, acceptanceData, multiset) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 01f2da2e4..3f9c80269 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -14,20 +14,18 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai return err } - if !isNextVirtualSelectedParent { - return nil - } - - blockStatus, err := csm.resolveBlockStatus(blockHash) - if err != nil { - return err - } - - if blockStatus == externalapi.StatusValid { - err = csm.checkFinalityViolation(blockHash) + if isNextVirtualSelectedParent { + blockStatus, err := csm.resolveBlockStatus(blockHash) if err != nil { return err } + + if blockStatus == externalapi.StatusValid { + err = csm.checkFinalityViolation(blockHash) + if err != nil { + return err + } + } } newTips, err := csm.addTip(blockHash) @@ -62,6 +60,24 @@ func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externa } func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (newTips []*externalapi.DomainHash, err error) { + newTips, err = csm.calculateNewTips(newTipHash) + if err != nil { + return nil, err + } + + err = csm.consensusStateStore.StageTips(newTips) + if err != nil { + return nil, err + } + + return newTips, nil +} + +func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + if *newTipHash == *csm.genesisHash { + return []*externalapi.DomainHash{newTipHash}, nil + } + currentTips, err := csm.consensusStateStore.Tips(csm.databaseContext) if err != nil { return nil, err @@ -72,7 +88,7 @@ func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (ne return nil, err } - newTips = []*externalapi.DomainHash{newTipHash} + newTips := []*externalapi.DomainHash{newTipHash} for _, currentTip := range currentTips { isCurrentTipInNewTipParents := false @@ -87,10 +103,5 @@ func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (ne } } - err = csm.consensusStateStore.StageTips(newTips) - if err != nil { - return nil, err - } - return newTips, nil } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 32a86b418..b6e14ed44 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -2,6 +2,7 @@ package consensusstatemanager import ( "errors" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" @@ -65,6 +66,9 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH if err != nil { return nil, err } + if nextBlockHash == nil { + break + } } // apply the diffs in reverse order diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go new file mode 100644 index 000000000..6de504f8f --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -0,0 +1,142 @@ +package consensusstatemanager_test + +import ( + "testing" + + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" +) + +func TestUTXOCommitment(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.BlockCoinbaseMaturity = 0 + factory := consensus.NewFactory() + + consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + // Build the following DAG: + // G <- A <- B <- D + // <- C <- + genesisHash := params.GenesisHash + + // Block A: + blockAHash, err := consensus.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating block A: %+v", err) + } + blockA, err := consensus.GetBlock(blockAHash) + if err != nil { + t.Fatalf("Error getting block A: %+v", err) + } + // Block B: + blockBHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating block B: %+v", err) + } + // Block C: + blockCTransaction, err := testutils.CreateTransaction(blockA.Transactions[0]) + if err != nil { + t.Fatalf("Error creating transaction: %+v", err) + } + blockCHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, + []*externalapi.DomainTransaction{blockCTransaction}) + if err != nil { + t.Fatalf("Error creating block C: %+v", err) + } + // Block D: + blockDHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash, blockCHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating block D: %+v", err) + } + blockD, err := consensus.GetBlock(blockDHash) + if err != nil { + t.Fatalf("Error getting block D: %+v", err) + } + + // Get the past UTXO set of block D + csm := consensus.ConsensusStateManager() + utxoSetIterator, err := csm.RestorePastUTXOSetIterator(blockDHash) + if err != nil { + t.Fatalf("Error restoring past UTXO of block D: %+v", err) + } + + // Build a Multiset for block D + ms := multiset.New() + for utxoSetIterator.Next() { + outpoint, entry, err := utxoSetIterator.Get() + if err != nil { + t.Fatalf("Error getting from UTXOSet iterator: %+v", err) + } + err = consensus.ConsensusStateManager().AddUTXOToMultiset(ms, entry, outpoint) + if err != nil { + t.Fatalf("Error adding utxo to multiset: %+v", err) + } + } + + // Turn the multiset into a UTXO commitment + utxoCommitment := ms.Hash() + + // Make sure that the two commitments are equal + if *utxoCommitment != blockD.Header.UTXOCommitment { + t.Fatalf("TestUTXOCommitment: calculated UTXO commitment and "+ + "actual UTXO commitment don't match. Want: %s, got: %s", + utxoCommitment, blockD.Header.UTXOCommitment) + } + }) +} + +func TestPastUTXOMultiset(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + + consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + // Build a short chain + currentHash := params.GenesisHash + for i := 0; i < 3; i++ { + currentHash, err = consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating block A: %+v", err) + } + } + + // Save the current tip's hash to be used lated + testedBlockHash := currentHash + + // Take testedBlock's multiset and hash + firstMultiset, err := consensus.MultisetStore().Get(consensus.DatabaseContext(), testedBlockHash) + if err != nil { + return + } + firstMultisetHash := firstMultiset.Hash() + + // Add another block on top of testedBlock + _, err = consensus.AddBlock([]*externalapi.DomainHash{testedBlockHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating block A: %+v", err) + } + + // Take testedBlock's multiset and hash again + secondMultiset, err := consensus.MultisetStore().Get(consensus.DatabaseContext(), testedBlockHash) + if err != nil { + return + } + secondMultisetHash := secondMultiset.Hash() + + // Make sure the multiset hasn't changed + if *firstMultisetHash != *secondMultisetHash { + t.Fatalf("TestPastUTXOMultiSet: selectedParentMultiset appears to have changed!") + } + }) +} diff --git a/domain/consensus/processes/consensusstatemanager/consensusstatemanager.go b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go similarity index 100% rename from domain/consensus/processes/consensusstatemanager/consensusstatemanager.go rename to domain/consensus/processes/consensusstatemanager/consensus_state_manager.go diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go new file mode 100644 index 000000000..cafb4e8ce --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -0,0 +1,150 @@ +package consensusstatemanager_test + +import ( + "errors" + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + + "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/consensus/utils/transactionhelper" + "github.com/kaspanet/kaspad/domain/dagconfig" +) + +func TestDoubleSpends(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + + consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + // Mine chain of two blocks to fund our double spend + 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) + if err != nil { + t.Fatalf("Error creating fundingBlock: %+v", err) + } + fundingBlock, err := consensus.GetBlock(fundingBlockHash) + if err != nil { + t.Fatalf("Error getting fundingBlock: %+v", err) + } + + // Get funding transaction + fundingTransaction := fundingBlock.Transactions[transactionhelper.CoinbaseTransactionIndex] + + // Create two transactions that spends the same output, but with different IDs + spendingTransaction1, err := testutils.CreateTransaction(fundingTransaction) + if err != nil { + t.Fatalf("Error creating spendingTransaction1: %+v", err) + } + spendingTransaction2, err := testutils.CreateTransaction(fundingTransaction) + if err != nil { + t.Fatalf("Error creating spendingTransaction2: %+v", err) + } + spendingTransaction2.Outputs[0].Value-- // tweak the value to create a different ID + spendingTransaction1ID := consensusserialization.TransactionID(spendingTransaction1) + spendingTransaction2ID := consensusserialization.TransactionID(spendingTransaction2) + if *spendingTransaction1ID == *spendingTransaction2ID { + t.Fatalf("spendingTransaction1 and spendingTransaction2 ids are equal") + } + + // Mine a block with spendingTransaction1 and make sure that it's valid + goodBlock1Hash, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil, + []*externalapi.DomainTransaction{spendingTransaction1}) + if err != nil { + t.Fatalf("Error adding goodBlock1: %+v", err) + } + goodBlock1Status, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), goodBlock1Hash) + if err != nil { + t.Fatalf("Error getting status of goodBlock1: %+v", err) + } + if goodBlock1Status != externalapi.StatusValid { + t.Fatalf("GoodBlock1 status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock1Status) + } + + // 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, + []*externalapi.DomainTransaction{spendingTransaction1}) + if err != nil { + t.Fatalf("Error adding doubleSpendingBlock1: %+v", err) + } + doubleSpendingBlock1Status, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), doubleSpendingBlock1Hash) + if err != nil { + t.Fatalf("Error getting status of goodBlock: %+v", err) + } + if doubleSpendingBlock1Status != externalapi.StatusDisqualifiedFromChain { + t.Fatalf("GoodBlock status expected to be '%s', but is '%s'", + externalapi.StatusDisqualifiedFromChain, doubleSpendingBlock1Status) + } + + // 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, + []*externalapi.DomainTransaction{spendingTransaction2}) + if err != nil { + t.Fatalf("Error adding doubleSpendingBlock2: %+v", err) + } + doubleSpendingBlock2Status, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), doubleSpendingBlock2Hash) + if err != nil { + t.Fatalf("Error getting status of goodBlock: %+v", err) + } + if doubleSpendingBlock2Status != externalapi.StatusDisqualifiedFromChain { + t.Fatalf("GoodBlock status expected to be '%s', but is '%s'", + externalapi.StatusDisqualifiedFromChain, doubleSpendingBlock2Status) + } + + // 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, + []*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2}) + if err == nil { + t.Fatalf("No error when adding a self-double-spending block") + } + if !errors.Is(err, ruleerrors.ErrDoubleSpendInSameBlock) { + t.Fatalf("Adding self-double-spending block should have "+ + "returned ruleerrors.ErrDoubleSpendInSameBlock, but instead got: %+v", err) + } + + // 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, + []*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2}) + if err == nil { + t.Fatalf("No error when adding a block containing the same transactin twice") + } + if !errors.Is(err, ruleerrors.ErrDuplicateTx) { + t.Fatalf("Adding block that contains the same transaction twice should have "+ + "returned ruleerrors.ErrDuplicateTx, but instead got: %+v", err) + } + + // 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, + []*externalapi.DomainTransaction{spendingTransaction2}) + if err != nil { + t.Fatalf("Error adding goodBlock: %+v", err) + } + //use ResolveBlockStatus, since goodBlock2 might not be the selectedTip + goodBlock2Status, err := consensus.ConsensusStateManager().ResolveBlockStatus(goodBlock2Hash) + if err != nil { + t.Fatalf("Error getting status of goodBlock: %+v", err) + } + if goodBlock2Status != externalapi.StatusValid { + t.Fatalf("GoodBlock status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock2Status) + } + }) +} diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go new file mode 100644 index 000000000..9f1aba398 --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -0,0 +1,24 @@ +package consensusstatemanager + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +type testConsensusStateManager struct { + *consensusStateManager +} + +func NewTestConsensusStateManager(baseConsensusStateManager model.ConsensusStateManager) model.TestConsensusStateManager { + return &testConsensusStateManager{consensusStateManager: baseConsensusStateManager.(*consensusStateManager)} +} + +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) { + return csm.resolveBlockStatus(blockHash) +} diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index d4b885195..f8c711018 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -27,7 +27,10 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain if err != nil { return err } - csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) + err = csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) + if err != nil { + return err + } csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) @@ -46,34 +49,39 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain func (csm *consensusStateManager) updateVirtualDiffParents( newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error { - virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) - if err != nil { - return err - } + var newVirtualDiffParents []*externalapi.DomainHash + if *newBlockHash == *csm.genesisHash { + newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} + } else { + virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err + } - newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) - if err != nil { - return err - } - newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) + newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) + if err != nil { + return err + } + newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) - newVirtualDiffParents := []*externalapi.DomainHash{newBlockHash} - for _, virtualDiffParent := range virtualDiffParents { - if newBlockParents.Contains(virtualDiffParent) { - virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) - if err != nil { - return err + newVirtualDiffParents := []*externalapi.DomainHash{newBlockHash} + for _, virtualDiffParent := range virtualDiffParents { + if newBlockParents.Contains(virtualDiffParent) { + virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) + if err != nil { + return err + } + newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) + if err != nil { + return err + } + err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, newBlockHash) + if err != nil { + return err + } + } else { + newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } - newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) - if err != nil { - return err - } - err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, newBlockHash) - if err != nil { - return err - } - } else { - newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } } diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 746a22855..432e446b9 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -1,12 +1,13 @@ package reachabilitymanager import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "math" "strings" "time" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" ) diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index b5dfd5af5..684604824 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -40,11 +40,6 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do return err } - err = v.checkTransactionPayload(tx) - if err != nil { - return err - } - err = v.checkNativeTransactionPayload(tx) if err != nil { return err @@ -190,11 +185,3 @@ func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.Domain } return nil } - -func (v *transactionValidator) checkTransactionPayload(tx *externalapi.DomainTransaction) error { - if tx.Payload == nil { - return errors.Wrapf(ruleerrors.ErrInvalidPayload, "nil payload is not allowed") - } - - return nil -} diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index bf4c31077..bd5843995 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -4,6 +4,8 @@ import ( "errors" "math" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" @@ -13,7 +15,8 @@ import ( type testConsensus struct { *consensus - testBlockBuilder model.TestBlockBuilder + testBlockBuilder model.TestBlockBuilder + testConsensusStateManager model.TestConsensusStateManager } func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, @@ -33,6 +36,13 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba tc.lock.Lock() defer tc.lock.Unlock() + if coinbaseData == nil { + coinbaseData = &externalapi.DomainCoinbaseData{ + ScriptPublicKey: testutils.OpTrueScript(), + ExtraData: []byte{}, + } + } + block, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) if err != nil { return nil, err @@ -40,7 +50,9 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba solveBlock(block) - err = tc.ValidateAndInsertBlock(block) + // Use blockProcessor.ValidateAndInsertBlock instead of tc.ValidateAndInsertBlock to avoid double-locking + // the conscensus lock. + err = tc.blockProcessor.ValidateAndInsertBlock(block) if err != nil { return nil, err } diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 6a6574f98..7e68ed231 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -1,6 +1,13 @@ package consensus -import "github.com/kaspanet/kaspad/domain/consensus/model" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/processes/blockbuilder" +) + +func (tc *testConsensus) DatabaseContext() model.DBReader { + return tc.databaseContext +} func (tc *testConsensus) AcceptanceDataStore() model.AcceptanceDataStore { return tc.AcceptanceDataStore() @@ -50,8 +57,8 @@ func (tc *testConsensus) UTXODiffStore() model.UTXODiffStore { return tc.utxoDiffStore } -func (tc *testConsensus) BlockBuilder() model.BlockBuilder { - return tc.blockBuilder +func (tc *testConsensus) BlockBuilder() model.TestBlockBuilder { + return blockbuilder.NewTestBlockBuilder(tc.blockBuilder) } func (tc *testConsensus) BlockProcessor() model.BlockProcessor { @@ -66,8 +73,8 @@ func (tc *testConsensus) CoinbaseManager() model.CoinbaseManager { return tc.coinbaseManager } -func (tc *testConsensus) ConsensusStateManager() model.ConsensusStateManager { - return tc.consensusStateManager +func (tc *testConsensus) ConsensusStateManager() model.TestConsensusStateManager { + return tc.testConsensusStateManager } func (tc *testConsensus) DAGTopologyManager() model.DAGTopologyManager { diff --git a/domain/consensus/utils/testutils/create_transaction.go b/domain/consensus/utils/testutils/create_transaction.go new file mode 100644 index 000000000..306926258 --- /dev/null +++ b/domain/consensus/utils/testutils/create_transaction.go @@ -0,0 +1,39 @@ +package testutils + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" +) + +// CreateTransaction create a transaction that spends the first output of provided transaction. +// Assumes that the output being spent has opTrueScript as it's scriptPublicKey +// Creates the value of the spent output minus 1 sompi +func CreateTransaction(txToSpend *externalapi.DomainTransaction) (*externalapi.DomainTransaction, error) { + opTrueScript := OpTrueScript() + + scriptPublicKey := opTrueScript + signatureScript, err := txscript.PayToScriptHashSignatureScript(opTrueScript, nil) + if err != nil { + return nil, err + } + input := &externalapi.DomainTransactionInput{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: *consensusserialization.TransactionID(txToSpend), + Index: 0, + }, + SignatureScript: signatureScript, + Sequence: constants.MaxTxInSequenceNum, + } + output := &externalapi.DomainTransactionOutput{ + ScriptPublicKey: scriptPublicKey, + Value: txToSpend.Outputs[0].Value - 1, + } + return &externalapi.DomainTransaction{ + Version: constants.TransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{input}, + Outputs: []*externalapi.DomainTransactionOutput{output}, + Payload: []byte{}, + }, nil +} diff --git a/domain/consensus/utils/testutils/for_all_nets.go b/domain/consensus/utils/testutils/for_all_nets.go index 0fd718a8d..14371c7d8 100644 --- a/domain/consensus/utils/testutils/for_all_nets.go +++ b/domain/consensus/utils/testutils/for_all_nets.go @@ -22,6 +22,6 @@ func ForAllNets(t *testing.T, setDifficultyToMinimum bool, testFunc func(*testin params.TargetTimePerBlock = dagconfig.SimnetParams.TargetTimePerBlock } - testFunc(t, ¶ms) + t.Run(params.Name, func(t *testing.T) { testFunc(t, ¶ms) }) } } diff --git a/domain/consensus/utils/testutils/op_true_script.go b/domain/consensus/utils/testutils/op_true_script.go new file mode 100644 index 000000000..394bfc018 --- /dev/null +++ b/domain/consensus/utils/testutils/op_true_script.go @@ -0,0 +1,15 @@ +package testutils + +import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/pkg/errors" +) + +// OpTrueScript returns a P2SH script paying to an anyone-can-spend address +func OpTrueScript() []byte { + opTrueScript, err := txscript.PayToScriptHashScript([]byte{txscript.OpTrue}) + if err != nil { + panic(errors.Wrapf(err, "Couldn't parse opTrueScript. This should never happen")) + } + return opTrueScript +} diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index c59d7b5c5..65819fd31 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -28,19 +28,19 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.DomainHash{ - 0x37, 0xf9, 0x09, 0x98, 0x0e, 0x12, 0xf6, 0xa2, - 0xaa, 0x0d, 0x09, 0xfa, 0x41, 0xad, 0x95, 0x1a, - 0x5b, 0x38, 0x14, 0x12, 0xe9, 0x02, 0x14, 0xcd, - 0xba, 0x64, 0xf6, 0x84, 0x72, 0xc4, 0xa4, 0x3a, + 0xbb, 0xc1, 0x88, 0xdd, 0x56, 0x9d, 0x46, 0xbd, + 0x36, 0xb0, 0x31, 0x52, 0x49, 0x93, 0xac, 0x70, + 0x1d, 0x36, 0xf1, 0xb3, 0xd2, 0x2f, 0xe5, 0x51, + 0x7c, 0x8b, 0x1a, 0xaf, 0x3c, 0x82, 0x6f, 0x18, } // genesisMerkleRoot is the hash of the first transaction in the genesis block // for the main network. var genesisMerkleRoot = externalapi.DomainHash{ - 0xca, 0x85, 0x56, 0x27, 0xc7, 0x6a, 0xb5, 0x7a, - 0x26, 0x1d, 0x63, 0x62, 0x1e, 0x57, 0x21, 0xf0, - 0x5e, 0x60, 0x1f, 0xee, 0x1d, 0x4d, 0xaa, 0x53, - 0x72, 0xe1, 0x16, 0xda, 0x4b, 0xb3, 0xd8, 0x0e, + 0x2f, 0x55, 0x37, 0x11, 0x8a, 0x30, 0xcd, 0xcd, + 0xa7, 0xdb, 0xe5, 0xe6, 0x42, 0xf9, 0x1b, 0xf3, + 0xb4, 0x62, 0xd6, 0xb6, 0xed, 0xc0, 0x5c, 0xe1, + 0x6e, 0xee, 0x0f, 0x3c, 0xdc, 0xf6, 0x01, 0x15, } // genesisBlock defines the genesis block of the block DAG which serves as the @@ -52,9 +52,9 @@ var genesisBlock = externalapi.DomainBlock{ HashMerkleRoot: genesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1730a81bdb4, + TimeInMilliseconds: 0x175bc9e305a, Bits: 0x207fffff, - Nonce: 0x1, + Nonce: 0x0, }, Transactions: []*externalapi.DomainTransaction{genesisCoinbaseTx}, } @@ -79,10 +79,10 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.DomainHash{ - 0xd3, 0xad, 0xd6, 0xe4, 0x6b, 0xc2, 0x33, 0xa9, - 0x20, 0x03, 0x1e, 0xf3, 0xe6, 0x8a, 0xf4, 0x08, - 0x91, 0xa1, 0x25, 0xc7, 0xc1, 0xf1, 0x5b, 0x3e, - 0x74, 0x72, 0xb5, 0x8a, 0xa0, 0x10, 0x00, 0x00, + 0x92, 0xb5, 0x28, 0xd3, 0xaa, 0x6d, 0x8b, 0x30, + 0x49, 0x19, 0x53, 0x6f, 0x62, 0xce, 0x9a, 0x82, + 0x2f, 0x91, 0xd4, 0x33, 0x24, 0xbc, 0x39, 0xe6, + 0xad, 0x53, 0xe3, 0x97, 0x5f, 0x03, 0x00, 0x00, } // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -103,9 +103,9 @@ var devnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: devnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x17305b05694, + TimeInMilliseconds: 0x175bca27b7f, Bits: 0x1e7fffff, - Nonce: 282366, + Nonce: 0x1a9ba, }, Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -129,10 +129,10 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0x50, 0x01, 0x7e, 0x84, 0x55, 0xc0, 0xab, 0x9c, - 0xca, 0xf5, 0xc1, 0x5d, 0xbe, 0x57, 0x0a, 0x80, - 0x1f, 0x93, 0x00, 0x34, 0xe6, 0xee, 0xc2, 0xee, - 0xff, 0x57, 0xc1, 0x66, 0x2a, 0x63, 0x4b, 0x23, + 0x84, 0x96, 0x38, 0xb6, 0x5c, 0x44, 0xc0, 0xb9, + 0x3c, 0x48, 0x03, 0x7c, 0x2e, 0xee, 0x0a, 0xbf, + 0xfb, 0x54, 0xc8, 0x5f, 0x99, 0xd6, 0x21, 0x3d, + 0x3f, 0xdd, 0xac, 0xb1, 0xe7, 0x30, 0x7e, 0x05, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -153,7 +153,7 @@ var simnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: simnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x173001df3d5, + TimeInMilliseconds: 0x175bca27c39, Bits: 0x207fffff, Nonce: 1, }, @@ -177,19 +177,19 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.DomainHash{ - 0x29, 0x0c, 0x43, 0x42, 0x66, 0x2d, 0x1b, 0x05, - 0x0b, 0xc7, 0xb2, 0x26, 0x8d, 0x53, 0x16, 0xbf, - 0x5a, 0x2d, 0x7e, 0xff, 0xee, 0x06, 0xb7, 0x2b, - 0x41, 0x9f, 0xe8, 0xf0, 0xfa, 0xc7, 0xd1, 0x1a, + 0xa9, 0xbe, 0xa7, 0xd9, 0x0f, 0xd2, 0xbd, 0xfb, + 0xd8, 0x09, 0x4d, 0x6a, 0x49, 0xa7, 0x59, 0x93, + 0xd1, 0x35, 0xce, 0x61, 0x18, 0x07, 0x0b, 0xe6, + 0xb9, 0xec, 0xad, 0x68, 0xe4, 0x2d, 0x00, 0x00, } // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for testnet. var testnetGenesisMerkleRoot = externalapi.DomainHash{ - 0xA0, 0xA1, 0x3D, 0xFD, 0x86, 0x41, 0x35, 0xC8, - 0xBD, 0xBB, 0xE6, 0x37, 0x35, 0xBB, 0x4C, 0x51, - 0x11, 0x7B, 0x26, 0x90, 0x15, 0x64, 0x0F, 0x42, - 0x6D, 0x2B, 0x6F, 0x37, 0x4D, 0xC1, 0xA9, 0x72, + 0x7c, 0x5a, 0x9a, 0xb4, 0xa6, 0xd5, 0x03, 0xf3, + 0x19, 0x3c, 0x26, 0x82, 0xf5, 0x45, 0xdf, 0xe3, + 0x08, 0x6d, 0x94, 0xfc, 0x7d, 0xb9, 0x42, 0x4b, + 0x2c, 0x38, 0xf2, 0x5c, 0x64, 0xbc, 0xb4, 0x98, } // testnetGenesisBlock defines the genesis block of the block DAG which serves as the @@ -201,9 +201,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: testnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1730a66a9d9, + TimeInMilliseconds: 0x175bcac06ec, Bits: 0x1e7fffff, - Nonce: 0x162ca, + Nonce: 0x568f, }, Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 3e014f77a..bca39d265 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -7,10 +7,11 @@ package mempool import ( "container/list" "fmt" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "sync" "time" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index f2c22425f..42cbb5d52 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -2,11 +2,12 @@ package integration import ( "encoding/hex" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "strings" "testing" "time" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" From fc5e39f6cc99d57cbb3f5c4bbd23198af7d75996 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 15 Nov 2020 03:29:25 -0800 Subject: [PATCH 020/351] [NOD-1535] fix reachability test (#1061) * Revert "[NOD-1500] Delete integration tests" This reverts commit fcb57a206690a884fa6afb69d5d493282954a8bf. * [NOD-1518] hashserialization -> consenusserialization * [NOD-1518] Fix add genesis to virtual * [NOD-1518] Fix a bug in SerializeCoinbasePayload. * [NOD-1518] Fix a loop error and make pastMedianTime behave correctly everywhere on genesis. * [NOD-1518] Fix another bug and an infinite loop. * [NOD-1518] Fix uninitialized slice. * [NOD-1518] Fix bad should-commit checks and another infinite loop. * [NOD-1518] Fix nil serialization. * [NOD-1518] Rename blockHash to currentBlockHash. * [NOD-1518] Move the check whether stagedVirtualUTXOSet != nil to the top of commitVirtualUTXODiff. * [NOD-1518] Simplify utxoDiffStore.Commit. * [NOD-1518] Unextract resolveBlockStatusAndCheckFinality. * [NOD-1518] Move no-transactions logic into CalculateIDMerkleRoot. * [NOD-1518] Remove redundant is-staged check. * [NOD-1518] Fix merge errors. * [NOD-1518] Don't write anything if utxoDiffChild is nil. * [NOD-1518] Stage virtualAcceptanceData and virtualMultiset. * [NOD-1518] Fix bugs in getBlockTemplate and submitBlock. * [NOD-1518] Fix bad validation order in validateHeaderInContext. * [NOD-1518] Fix bug in Next(). * [NOD-1518] Fix nil dereference of subnetworks in AddressCache. * [NOD-1518] Fix multisetStore.Get returning a pointer to a multiset that is changed in place. * [NOD-1518] Break on genesis in countSubtrees. * [NOD-1518] Fix createBlockLocator. * [NOD-1518] Fix MsgTxToDomainTransaction. * [NOD-1518] Set MaxTxVersion to 1. * [NOD-1518] Fix missing error handling, bug in MsgTxToDomainTransaction, and bad subnetwork equality check. * [NOD-1518] Fix bug in hasUTXOByOutpointFromStagedVirtualUTXODiff. * [NOD-1518] Remove irrelevant comments. * [NOD-1518] Generate transactions with sufficient fee in tx_relay_test. * [NOD-1518] Fix broken RPC handlers. * [NOD-1518] Fix merge errors. * [NOD-1518] Fix bad exists check in restorePastUTXO and missing genesis check in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Add a comment. * [NOD-1518] Use a regular mutex instead of a read-write mutex in consensus to avoid dealing with sneaky not-actually-read functions. * [NOD-1518] Fix a deadlock in GetVirtualSelectedParent. * [NOD-1518] Fix missing handler registration for CmdHeader. * [NOD-1518] Fix processHeader calling OnNewBlock and LogBlock. Also fix conversion errors in IBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad Command() in MsgIBDRootUTXOSetAndBlock. * [NOD-1518] Fix bad SyncStateMissingUTXOSet logic in resolveSyncState. * [NOD-1518] Rename mode to syncState. * [NOD-1518] Fix headers-only blocks coming in after the consensus thinks it's synced. * [NOD-1518] Fix selectedChildIterator.Next not ignoring virtual, infinite loop in HashSet.Length(). * [NOD-1518] Fix not-properly wrapped IBD blocks. * [NOD-1518] Fix bad conversion in RequestIBDBlocks. * [NOD-1518] Fix bad string for CmdRequestHeaders. * [NOD-1518] Fix bad string for CmdDoneHeaders. * [NOD-1518] Fix bad Command() for MsgIBDRootNotFound. * [NOD-1518] Fix bad areHeaderTipsSyncedMaxTimeDifference value. * [NOD-1518] Add missing string for CmdRequestIBDBlocks. * [NOD-1518] Fix bad check for SyncStateMissingBlockBodies. * [NOD-1518] Fix bad timeout durations in tests. * [NOD-1518] Fix IBD blocks not calling OnNewBlock. * [NOD-1518] Change when IBD finishes. * [NOD-1518] Properly clone utxoDiffChild. * [NOD-1535] Fix reachability tests * [NOD-1518] Fix merge errors. * [NOD-1518] Move call to LogBlock to into OnNewBlock. * [NOD-1518] Return "not implemented" in unimplemented RPC handlers. * [NOD-1518] Extract cloning of hashes to a method over DomainHash. * [NOD-1518] Use isHeaderOnlyBlock. * [NOD-1518] Use constants.TransactionVersion. * [NOD-1518] Break immediately if we reached the virtual in SelectedChildIterator. * [NOD-1518] Don't stage nil utxoDiffChild. * [NOD-1518] Properly check the genesis hash in CalculatePastUTXOAndAcceptanceData. * [NOD-1518] Explain why we break on current == nil in countSubtrees. * [NOD-1518] Add a comment explaining why we check against StatusValid in resolveSyncState. * [NOD-1535] Add external reachability tests * [NOD-1535] Fix reachability tests and fix related bugs * [NOD-1535] Add setters fox reindex slack and window * [NOD-1535] Remove redundant line * [NOD-1535] Add comment * [NOD-1535] Fix comments * [NOD-1535] Rename DBReader->DatabaseContext * [NOD-1535] Check that reindex root is changed * [NOD-1535] Fix calculateNewTips Co-authored-by: Mike Zak Co-authored-by: stasatdaglabs --- .../blues_anticone_sizes_test.go | 27 + domain/consensus/factory.go | 7 +- .../interface_processes_reachabilitytree.go | 7 + domain/consensus/model/reachabilitydata.go | 9 +- .../consensus/model/testapi/test_consensus.go | 6 +- .../blockbuilder/test_block_builder.go | 3 +- .../pick_virtual_parents.go | 2 +- .../consensusstatemanager/update_virtual.go | 2 + .../dagtopologymanager_external_test.go | 52 + .../dagtraversalmanager/window_test.go | 141 +++ .../processes/reachabilitymanager/interval.go | 6 - .../reachability_external_test.go | 324 ++++++ .../reachabilitymanager/reachability_test.go | 1005 +++++++++++++++++ .../reachabilitymanager.go | 7 +- .../test_reachabilitymanager.go | 23 + .../processes/reachabilitymanager/tree.go | 34 +- domain/consensus/test_consensus.go | 35 +- domain/consensus/test_consensus_getters.go | 4 +- domain/consensus/utils/mining/solve.go | 25 + domain/dagconfig/genesis.go | 2 +- 20 files changed, 1662 insertions(+), 59 deletions(-) create mode 100644 domain/consensus/database/serialization/blues_anticone_sizes_test.go create mode 100644 domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go create mode 100644 domain/consensus/processes/dagtraversalmanager/window_test.go create mode 100644 domain/consensus/processes/reachabilitymanager/reachability_external_test.go create mode 100644 domain/consensus/processes/reachabilitymanager/reachability_test.go create mode 100644 domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go create mode 100644 domain/consensus/utils/mining/solve.go diff --git a/domain/consensus/database/serialization/blues_anticone_sizes_test.go b/domain/consensus/database/serialization/blues_anticone_sizes_test.go new file mode 100644 index 000000000..d6ddb44b0 --- /dev/null +++ b/domain/consensus/database/serialization/blues_anticone_sizes_test.go @@ -0,0 +1,27 @@ +package serialization + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "testing" +) + +// TestBlueAnticoneSizesSize tests that no data can be loss when converting model.KType to the corresponding type in +// DbBluesAnticoneSizes +func TestKType(t *testing.T) { + k := model.KType(0) + k-- + + if k < model.KType(0) { + t.Fatalf("KType must be unsigned") + } + + // Setting maxKType to maximum value of KType. + // As we verify above that KType is unsigned we can be sure that maxKType is indeed the maximum value of KType. + maxKType := ^model.KType(0) + dbBluesAnticoneSizes := DbBluesAnticoneSizes{ + AnticoneSize: uint32(maxKType), + } + if model.KType(dbBluesAnticoneSizes.AnticoneSize) != maxKType { + t.Fatalf("convert from uint32 to KType losses data") + } +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 3ad5c924b..f1fbe1b38 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,7 +1,9 @@ package consensus import ( + "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" "io/ioutil" + "math/rand" "os" "sync" @@ -29,7 +31,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/processes/coinbasemanager" "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager" "github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager" - "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" "github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager" "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" "github.com/kaspanet/kaspad/domain/consensus/processes/headertipsmanager" @@ -78,7 +79,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat reachabilityManager := reachabilitymanager.New( dbManager, ghostdagDataStore, - blockRelationStore, reachabilityDataStore) dagTopologyManager := dagtopologymanager.New( dbManager, @@ -320,9 +320,12 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) testBlockBuilder := blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder) testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager) tc = &testConsensus{ + rd: rand.New(rand.NewSource(0)), consensus: consensusAsImplementation, testBlockBuilder: testBlockBuilder, testConsensusStateManager: testConsensusStateManager, + testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation. + reachabilityManager), } teardown = func() { db.Close() diff --git a/domain/consensus/model/interface_processes_reachabilitytree.go b/domain/consensus/model/interface_processes_reachabilitytree.go index 47284dae6..75c9ee372 100644 --- a/domain/consensus/model/interface_processes_reachabilitytree.go +++ b/domain/consensus/model/interface_processes_reachabilitytree.go @@ -10,3 +10,10 @@ type ReachabilityManager interface { IsDAGAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) UpdateReindexRoot(selectedTip *externalapi.DomainHash) error } + +type TestReachabilityManager interface { + ReachabilityManager + SetReachabilityReindexWindow(reindexWindow uint64) + SetReachabilityReindexSlack(reindexSlack uint64) + ReachabilityReindexSlack() uint64 +} diff --git a/domain/consensus/model/reachabilitydata.go b/domain/consensus/model/reachabilitydata.go index 99e56a4c4..0efb7b62a 100644 --- a/domain/consensus/model/reachabilitydata.go +++ b/domain/consensus/model/reachabilitydata.go @@ -1,6 +1,9 @@ package model -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "fmt" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // ReachabilityData holds the set of data required to answer // reachability queries @@ -41,6 +44,10 @@ type ReachabilityInterval struct { End uint64 } +func (ri *ReachabilityInterval) String() string { + return fmt.Sprintf("[%d,%d]", ri.Start, ri.End) +} + // FutureCoveringTreeNodeSet represents a collection of blocks in the future of // a certain block. Once a block B is added to the DAG, every block A_i in // B's selected parent anticone must register B in its FutureCoveringTreeNodeSet. This allows diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 0adee43b1..be16dfbe0 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -9,6 +9,8 @@ import ( type TestConsensus interface { externalapi.Consensus + DatabaseContext() model.DBReader + BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) @@ -17,7 +19,7 @@ type TestConsensus interface { AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error) - DatabaseContext() model.DBReader + SolveAndAddBlock(block *externalapi.DomainBlock) (*externalapi.DomainHash, error) AcceptanceDataStore() model.AcceptanceDataStore BlockHeaderStore() model.BlockHeaderStore @@ -45,7 +47,7 @@ type TestConsensus interface { MergeDepthManager() model.MergeDepthManager PastMedianTimeManager() model.PastMedianTimeManager PruningManager() model.PruningManager - ReachabilityManager() model.ReachabilityManager + ReachabilityManager() model.TestReachabilityManager SyncManager() model.SyncManager TransactionValidator() model.TransactionValidator } diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 9fc25779a..35cfd30a7 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -36,7 +36,8 @@ func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.Do if err != nil { return nil, err } - timeInMilliseconds, err := bb.newBlockTime() + + timeInMilliseconds, err := bb.pastMedianTimeManager.PastMedianTime(tempBlockHash) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 8fd94ff51..e15981a02 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -1,7 +1,7 @@ package consensusstatemanager import ( - "errors" + "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index f8c711018..39612880d 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -27,10 +27,12 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain if err != nil { return err } + err = csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) if err != nil { return err } + csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go new file mode 100644 index 000000000..7c35188d6 --- /dev/null +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -0,0 +1,52 @@ +package dagtopologymanager + +import ( + "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 TestIsInPast(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestIsInPast") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown() + + // 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) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + 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) + 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) + if err != nil { + t.Fatalf("AddBlock: %s", err) + } + + isAncestorOf, err := tc.DAGTopologyManager().IsAncestorOf(blockC, blockD) + if err != nil { + t.Fatalf("IsAncestorOf: %s", err) + } + if !isAncestorOf { + t.Fatalf("TestIsInPast: node C is unexpectedly not the past of node D") + } + }) +} diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go new file mode 100644 index 000000000..3c3ba65c1 --- /dev/null +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -0,0 +1,141 @@ +package dagtraversalmanager_test + +import ( + "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) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestBlueBlockWindow") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown() + + windowSize := uint64(10) + blockByIDMap := make(map[string]*externalapi.DomainHash) + idByBlockMap := make(map[externalapi.DomainHash]string) + blockByIDMap["A"] = params.GenesisHash + idByBlockMap[*params.GenesisHash] = "A" + + blocksData := []*struct { + parents []string + id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash + expectedWindowWithGenesisPadding []string + }{ + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + }, + } + + for _, blockData := range blocksData { + parents := hashset.New() + for _, parentID := range blockData.parents { + parent := blockByIDMap[parentID] + parents.Add(parent) + } + + block, err := tc.AddBlock(parents.ToSlice(), nil, nil) + if err != nil { + t.Fatalf("AddBlock: %s", err) + } + + blockByIDMap[blockData.id] = block + idByBlockMap[*block] = blockData.id + + window, err := tc.DAGTraversalManager().BlueWindow(block, windowSize) + if err != nil { + t.Fatalf("BlueWindow: %s", err) + } + if err := checkWindowIDs(window, blockData.expectedWindowWithGenesisPadding, idByBlockMap); err != nil { + t.Errorf("Unexpected values for window for block %s: %s", blockData.id, err) + } + } + }) +} + +func checkWindowIDs(window []*externalapi.DomainHash, expectedIDs []string, idByBlockMap map[externalapi.DomainHash]string) error { + ids := make([]string, len(window)) + for i, node := range window { + ids[i] = idByBlockMap[*node] + } + if !reflect.DeepEqual(ids, expectedIDs) { + return errors.Errorf("window expected to have blocks %s but got %s", expectedIDs, ids) + } + return nil +} diff --git a/domain/consensus/processes/reachabilitymanager/interval.go b/domain/consensus/processes/reachabilitymanager/interval.go index 8ce46407a..177b32327 100644 --- a/domain/consensus/processes/reachabilitymanager/interval.go +++ b/domain/consensus/processes/reachabilitymanager/interval.go @@ -1,7 +1,6 @@ package reachabilitymanager import ( - "fmt" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/pkg/errors" "math" @@ -116,8 +115,3 @@ func intervalSplitWithExponentialBias(ri *model.ReachabilityInterval, sizes []ui func intervalContains(ri *model.ReachabilityInterval, other *model.ReachabilityInterval) bool { return ri.Start <= other.Start && other.End <= ri.End } - -// intervalString returns a string representation of the interval. -func intervalString(ri *model.ReachabilityInterval) string { - return fmt.Sprintf("[%d,%d]", ri.Start, ri.End) -} diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go new file mode 100644 index 000000000..c5b5edd35 --- /dev/null +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -0,0 +1,324 @@ +package reachabilitymanager_test + +import ( + "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) { + reachabilityReindexWindow := uint64(2) + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot") + if err != nil { + t.Fatalf("NewTestConsensus: %+v", err) + } + defer tearDown() + + tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow) + + reindexRoot, err := tc.ReachabilityDataStore().ReachabilityReindexRoot(tc.DatabaseContext()) + if err != nil { + t.Fatalf("ReachabilityReindexRoot: %s", err) + } + + if *reindexRoot != *params.GenesisHash { + t.Fatalf("reindex root is expected to initially be genesis") + } + + // Add a block on top of the genesis block + chainRootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + // Add chain of reachabilityReindexWindow blocks above chainRootBlock. + // This should move the reindex root + chainRootBlockTipHash := chainRootBlock + for i := uint64(0); i < reachabilityReindexWindow; i++ { + chainBlock, err := tc.AddBlock([]*externalapi.DomainHash{chainRootBlockTipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + chainRootBlockTipHash = chainBlock + } + + newReindexRoot, err := tc.ReachabilityDataStore().ReachabilityReindexRoot(tc.DatabaseContext()) + if err != nil { + t.Fatalf("ReachabilityReindexRoot: %s", err) + } + + if *newReindexRoot != *reindexRoot { + t.Fatalf("reindex root is expected to change") + } + + // Add another block over genesis + _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + }) +} + +func TestUpdateReindexRoot(t *testing.T) { + reachabilityReindexWindow := uint64(2) + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown() + + tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow) + + intervalSize := func(hash *externalapi.DomainHash) uint64 { + data, err := tc.ReachabilityDataStore().ReachabilityData(tc.DatabaseContext(), hash) + if err != nil { + t.Fatalf("ReachabilityData: %s", err) + } + return data.TreeNode.Interval.End - data.TreeNode.Interval.Start + 1 + } + + // Add two blocks on top of the genesis block + 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) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + // Make two chains of size reachabilityReindexWindow and check that the reindex root is not changed. + for i := uint64(0); i < reachabilityReindexWindow-1; i++ { + _, err := tc.AddBlock([]*externalapi.DomainHash{chain1RootBlock}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + _, err = tc.AddBlock([]*externalapi.DomainHash{chain2RootBlock}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + reindexRoot, err := tc.ReachabilityDataStore().ReachabilityReindexRoot(tc.DatabaseContext()) + if err != nil { + t.Fatalf("ReachabilityReindexRoot: %s", err) + } + + if *reindexRoot != *params.GenesisHash { + t.Fatalf("reindex root unexpectedly moved") + } + } + + // Add another block over chain1. This will move the reindex root to chain1RootBlock + _, err = tc.AddBlock([]*externalapi.DomainHash{chain1RootBlock}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + // Make sure that chain1RootBlock is now the reindex root + reindexRoot, err := tc.ReachabilityDataStore().ReachabilityReindexRoot(tc.DatabaseContext()) + if err != nil { + t.Fatalf("ReachabilityReindexRoot: %s", err) + } + + if *reindexRoot != *chain1RootBlock { + t.Fatalf("chain1RootBlock is not the reindex root after reindex") + } + + // Make sure that tight intervals have been applied to chain2. Since + // we added reachabilityReindexWindow-1 blocks to chain2, the size + // of the interval at its root should be equal to reachabilityReindexWindow + if intervalSize(chain2RootBlock) != reachabilityReindexWindow { + t.Fatalf("got unexpected chain2RootBlock interval. Want: %d, got: %d", + intervalSize(chain2RootBlock), reachabilityReindexWindow) + } + + // Make sure that the rest of the interval has been allocated to + // chain1RootNode, minus slack from both sides + expectedChain1RootIntervalSize := intervalSize(params.GenesisHash) - 1 - + intervalSize(chain2RootBlock) - 2*reachabilityReindexWindow + if intervalSize(chain1RootBlock) != expectedChain1RootIntervalSize { + t.Fatalf("got unexpected chain1RootBlock interval. Want: %d, got: %d", + intervalSize(chain1RootBlock), expectedChain1RootIntervalSize) + } + }) +} + +func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { + reachabilityReindexWindow := uint64(2) + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown() + + tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow) + + intervalSize := func(hash *externalapi.DomainHash) uint64 { + data, err := tc.ReachabilityDataStore().ReachabilityData(tc.DatabaseContext(), hash) + if err != nil { + t.Fatalf("ReachabilityData: %s", err) + } + return data.TreeNode.Interval.End - data.TreeNode.Interval.Start + 1 + } + + // Add three children to the genesis: leftBlock, centerBlock, rightBlock + 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) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + rightBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + // Add a chain of reachabilityReindexWindow blocks above centerBlock. + // This will move the reindex root to centerBlock + centerTipHash := centerBlock + for i := uint64(0); i < reachabilityReindexWindow; i++ { + var err error + centerTipHash, err = tc.AddBlock([]*externalapi.DomainHash{centerTipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + } + + // Make sure that centerBlock is now the reindex root + reindexRoot, err := tc.ReachabilityDataStore().ReachabilityReindexRoot(tc.DatabaseContext()) + if err != nil { + t.Fatalf("ReachabilityReindexRoot: %s", err) + } + + if *reindexRoot != *centerBlock { + t.Fatalf("centerBlock is not the reindex root after reindex") + } + + // Get the current interval for leftBlock. The reindex should have + // resulted in a tight interval there + if intervalSize(leftBlock) != 1 { + t.Fatalf("leftBlock interval not tight after reindex") + } + + // Get the current interval for rightBlock. The reindex should have + // resulted in a tight interval there + if intervalSize(rightBlock) != 1 { + t.Fatalf("rightBlock interval not tight after reindex") + } + + // Get the current interval for centerBlock. Its interval should be: + // genesisInterval - 1 - leftInterval - leftSlack - rightInterval - rightSlack + expectedCenterInterval := intervalSize(params.GenesisHash) - 1 - + intervalSize(leftBlock) - tc.ReachabilityManager().ReachabilityReindexSlack() - + intervalSize(rightBlock) - tc.ReachabilityManager().ReachabilityReindexSlack() + if intervalSize(centerBlock) != expectedCenterInterval { + t.Fatalf("unexpected centerBlock interval. Want: %d, got: %d", + expectedCenterInterval, intervalSize(centerBlock)) + } + + // Add a chain of reachabilityReindexWindow - 1 blocks above leftBlock. + // Each addition will trigger a low-than-reindex-root reindex. We + // expect the centerInterval to shrink by 1 each time, but its child + // to remain unaffected + cetnerData, err := tc.ReachabilityDataStore().ReachabilityData(tc.DatabaseContext(), centerBlock) + if err != nil { + t.Fatalf("ReachabilityData: %s", err) + } + + treeChildOfCenterBlock := cetnerData.TreeNode.Children[0] + treeChildOfCenterBlockOriginalIntervalSize := intervalSize(treeChildOfCenterBlock) + leftTipHash := leftBlock + for i := uint64(0); i < reachabilityReindexWindow-1; i++ { + var err error + leftTipHash, err = tc.AddBlock([]*externalapi.DomainHash{leftTipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + expectedCenterInterval-- + if intervalSize(centerBlock) != expectedCenterInterval { + t.Fatalf("unexpected centerBlock interval. Want: %d, got: %d", + expectedCenterInterval, intervalSize(centerBlock)) + } + + if intervalSize(treeChildOfCenterBlock) != treeChildOfCenterBlockOriginalIntervalSize { + t.Fatalf("the interval of centerBlock's child unexpectedly changed") + } + } + + // Add a chain of reachabilityReindexWindow - 1 blocks above rightBlock. + // Each addition will trigger a low-than-reindex-root reindex. We + // expect the centerInterval to shrink by 1 each time, but its child + // to remain unaffected + rightTipHash := rightBlock + for i := uint64(0); i < reachabilityReindexWindow-1; i++ { + var err error + rightTipHash, err = tc.AddBlock([]*externalapi.DomainHash{rightTipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + expectedCenterInterval-- + if intervalSize(centerBlock) != expectedCenterInterval { + t.Fatalf("unexpected centerBlock interval. Want: %d, got: %d", + expectedCenterInterval, intervalSize(centerBlock)) + } + + if intervalSize(treeChildOfCenterBlock) != treeChildOfCenterBlockOriginalIntervalSize { + t.Fatalf("the interval of centerBlock's child unexpectedly changed") + } + } + }) +} + +func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) { + reachabilityReindexWindow := uint64(2) + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown() + + tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow) + + // Add a chain of reachabilityReindexWindow + 1 blocks above the genesis. + // 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) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + } + + // 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) + 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) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + }) +} diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go new file mode 100644 index 000000000..6b473d101 --- /dev/null +++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go @@ -0,0 +1,1005 @@ +package reachabilitymanager + +import ( + "encoding/binary" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "reflect" + "strings" + "testing" +) + +type reachabilityDataStoreMock struct { + reachabilityDataStaging map[externalapi.DomainHash]*model.ReachabilityData + recorder map[externalapi.DomainHash]struct{} + reachabilityReindexRootStaging *externalapi.DomainHash +} + +func (r *reachabilityDataStoreMock) Discard() { + panic("implement me") +} + +func (r *reachabilityDataStoreMock) Commit(_ model.DBTransaction) error { + panic("implement me") +} + +func (r *reachabilityDataStoreMock) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) error { + r.reachabilityDataStaging[*blockHash] = reachabilityData + r.recorder[*blockHash] = struct{}{} + return nil +} + +func (r *reachabilityDataStoreMock) StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) { + r.reachabilityReindexRootStaging = reachabilityReindexRoot +} + +func (r *reachabilityDataStoreMock) IsAnythingStaged() bool { + panic("implement me") +} + +func (r *reachabilityDataStoreMock) ReachabilityData(_ model.DBReader, blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) { + return r.reachabilityDataStaging[*blockHash], nil +} + +func (r *reachabilityDataStoreMock) HasReachabilityData(_ model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { + _, ok := r.reachabilityDataStaging[*blockHash] + return ok, nil +} + +func (r *reachabilityDataStoreMock) ReachabilityReindexRoot(_ model.DBReader) (*externalapi.DomainHash, error) { + return r.reachabilityReindexRootStaging, nil +} + +func (r *reachabilityDataStoreMock) isRecorderContainsOnly(nodes ...*externalapi.DomainHash) bool { + if len(r.recorder) != len(nodes) { + return false + } + + for _, node := range nodes { + if _, ok := r.recorder[*node]; !ok { + return false + } + } + + return true +} + +func (r *reachabilityDataStoreMock) resetRecorder() { + r.recorder = make(map[externalapi.DomainHash]struct{}) +} + +func newReachabilityDataStoreMock() *reachabilityDataStoreMock { + return &reachabilityDataStoreMock{ + reachabilityDataStaging: make(map[externalapi.DomainHash]*model.ReachabilityData), + recorder: make(map[externalapi.DomainHash]struct{}), + reachabilityReindexRootStaging: nil, + } +} + +type fatalfer interface { + Fatalf(format string, args ...interface{}) +} + +type testHelper struct { + *reachabilityManager + t fatalfer + dataStore *reachabilityDataStoreMock + hashCounter uint64 +} + +func (th *testHelper) generateHash() *externalapi.DomainHash { + var hash externalapi.DomainHash + binary.LittleEndian.PutUint64(hash[:], th.hashCounter) + th.hashCounter++ + return &hash +} + +func (th *testHelper) newNode() *externalapi.DomainHash { + node := th.generateHash() + err := th.stageTreeNode(node, newReachabilityTreeNode()) + if err != nil { + th.t.Fatalf("stageTreeNode: %s", err) + } + + return node +} + +func (th *testHelper) newNodeWithInterval(interval *model.ReachabilityInterval) *externalapi.DomainHash { + node := th.newNode() + err := th.stageInterval(node, interval) + if err != nil { + th.t.Fatalf("stageInteval: %s", err) + } + + return node +} + +func (th *testHelper) getInterval(node *externalapi.DomainHash) *model.ReachabilityInterval { + interval, err := th.interval(node) + if err != nil { + th.t.Fatalf("interval: %s", err) + } + + return interval +} + +func (th *testHelper) getIntervalSize(node *externalapi.DomainHash) uint64 { + return intervalSize(th.getInterval(node)) +} + +func (th *testHelper) remainingIntervalBefore(node *externalapi.DomainHash) *model.ReachabilityInterval { + interval, err := th.reachabilityManager.remainingIntervalBefore(node) + if err != nil { + th.t.Fatalf("remainingIntervalBefore: %s", err) + } + + return interval +} + +func (th *testHelper) remainingIntervalAfter(node *externalapi.DomainHash) *model.ReachabilityInterval { + interval, err := th.reachabilityManager.remainingIntervalAfter(node) + if err != nil { + th.t.Fatalf("remainingIntervalAfter: %s", err) + } + + return interval +} + +func (th *testHelper) addChild(node, child, reindexRoot *externalapi.DomainHash) { + err := th.reachabilityManager.addChild(node, child, reindexRoot) + if err != nil { + th.t.Fatalf("addChild: %s", err) + } +} + +func (th *testHelper) isReachabilityTreeAncestorOf(node, other *externalapi.DomainHash) bool { + isReachabilityTreeAncestorOf, err := th.reachabilityManager.IsReachabilityTreeAncestorOf(node, other) + if err != nil { + th.t.Fatalf("IsReachabilityTreeAncestorOf: %s", err) + } + + return isReachabilityTreeAncestorOf +} + +func (th *testHelper) checkIsRecorderContainsOnly(nodes ...*externalapi.DomainHash) { + if !th.dataStore.isRecorderContainsOnly(nodes...) { + th.t.Fatalf("unexpected nodes on recorder. Want: %v, got: %v", nodes, th.dataStore.recorder) + } +} + +func (th *testHelper) resetRecorder() { + th.dataStore.resetRecorder() +} + +func newTestHelper(manager *reachabilityManager, t fatalfer, dataStore *reachabilityDataStoreMock) *testHelper { + return &testHelper{reachabilityManager: manager, t: t, dataStore: dataStore} +} + +func TestAddChild(t *testing.T) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, t, reachabilityDataStore) + + // Scenario 1: test addChild in a chain + // root -> a -> b -> c... + // Create the root node of a new reachability tree + root := helper.newNode() + err := helper.stageInterval(root, newReachabilityInterval(1, 100)) + if err != nil { + t.Fatalf("stageInterval: %s", err) + } + + // Add a chain of child nodes just before a reindex occurs (2^6=64 < 100) + currentTip := root + for i := 0; i < 6; i++ { + node := helper.newNode() + helper.resetRecorder() + helper.addChild(currentTip, node, root) + + // Expect only the node and its parent to be affected + helper.checkIsRecorderContainsOnly(currentTip, node) + currentTip = node + } + + // Add another node to the tip of the chain to trigger a reindex (100 < 2^7=128) + lastChild := helper.newNode() + helper.resetRecorder() + helper.addChild(currentTip, lastChild, root) + + // Expect more than just the node and its parent to be modified but not + // all the nodes + if len(helper.dataStore.recorder) <= 2 && len(helper.dataStore.recorder) >= 7 { + t.Fatalf("TestAddChild: unexpected amount of staged nodes") + } + + // Expect the tip to have an interval of 1 and remaining interval of 0 both before and after + tipIntervalSize := helper.getIntervalSize(lastChild) + if tipIntervalSize != 1 { + t.Fatalf("TestAddChild: unexpected tip interval size: want: 1, got: %d", tipIntervalSize) + } + + tipRemainingIntervalBefore := helper.remainingIntervalBefore(lastChild) + + if intervalSize(tipRemainingIntervalBefore) != 0 { + t.Fatalf("TestAddChild: unexpected tip interval before size: want: 0, got: %d", intervalSize(tipRemainingIntervalBefore)) + } + + tipRemainingIntervalAfter := helper.remainingIntervalAfter(lastChild) + if intervalSize(tipRemainingIntervalAfter) != 0 { + t.Fatalf("TestAddChild: unexpected tip interval after size: want: 0, got: %d", intervalSize(tipRemainingIntervalAfter)) + } + + // Expect all nodes to be descendant nodes of root + currentNode := currentTip + for currentNode != root { + isReachabilityTreeAncestorOf, err := helper.IsReachabilityTreeAncestorOf(root, currentNode) + if err != nil { + t.Fatalf("IsReachabilityTreeAncestorOf: %s", err) + } + if !isReachabilityTreeAncestorOf { + t.Fatalf("TestAddChild: currentNode is not a descendant of root") + } + + currentNode, err = helper.parent(currentNode) + if err != nil { + t.Fatalf("parent: %s", err) + } + } + + // Scenario 2: test addChild where all nodes are direct descendants of root + // root -> a, b, c... + // Create the root node of a new reachability tree + root = helper.newNode() + err = helper.stageInterval(root, newReachabilityInterval(1, 100)) + if err != nil { + t.Fatalf("stageInterval: %s", err) + } + + // Add child nodes to root just before a reindex occurs (2^6=64 < 100) + childNodes := make([]*externalapi.DomainHash, 6) + for i := 0; i < len(childNodes); i++ { + childNodes[i] = helper.newNode() + helper.resetRecorder() + helper.addChild(root, childNodes[i], root) + + // Expect only the node and the root to be affected + helper.checkIsRecorderContainsOnly(root, childNodes[i]) + } + + // Add another node to the root to trigger a reindex (100 < 2^7=128) + lastChild = helper.newNode() + helper.resetRecorder() + helper.addChild(root, lastChild, root) + + // Expect more than just the node and the root to be modified but not + // all the nodes + if len(helper.dataStore.recorder) <= 2 && len(helper.dataStore.recorder) >= 7 { + t.Fatalf("TestAddChild: unexpected amount of modifiedNodes.") + } + + // Expect the last-added child to have an interval of 1 and remaining interval of 0 both before and after + lastChildInterval, err := helper.interval(lastChild) + if err != nil { + t.Fatalf("interval: %s", err) + } + + if intervalSize(lastChildInterval) != 1 { + t.Fatalf("TestAddChild: unexpected lastChild interval size: want: 1, got: %d", intervalSize(lastChildInterval)) + } + lastChildRemainingIntervalBeforeSize := intervalSize(helper.remainingIntervalBefore(lastChild)) + if lastChildRemainingIntervalBeforeSize != 0 { + t.Fatalf("TestAddChild: unexpected lastChild interval before size: want: 0, got: %d", lastChildRemainingIntervalBeforeSize) + } + lastChildRemainingIntervalAfterSize := intervalSize(helper.remainingIntervalAfter(lastChild)) + if lastChildRemainingIntervalAfterSize != 0 { + t.Fatalf("TestAddChild: unexpected lastChild interval after size: want: 0, got: %d", lastChildRemainingIntervalAfterSize) + } + + // Expect all nodes to be descendant nodes of root + for _, childNode := range childNodes { + isReachabilityTreeAncestorOf, err := helper.IsReachabilityTreeAncestorOf(root, childNode) + if err != nil { + t.Fatalf("IsReachabilityTreeAncestorOf: %s", err) + } + + if !isReachabilityTreeAncestorOf { + t.Fatalf("TestAddChild: childNode is not a descendant of root") + } + } +} + +func TestReachabilityTreeNodeIsAncestorOf(t *testing.T) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, t, reachabilityDataStore) + + root := helper.newNode() + currentTip := root + const numberOfDescendants = 6 + descendants := make([]*externalapi.DomainHash, numberOfDescendants) + for i := 0; i < numberOfDescendants; i++ { + node := helper.newNode() + helper.addChild(currentTip, node, root) + descendants[i] = node + currentTip = node + } + + // Expect all descendants to be in the future of root + for _, node := range descendants { + if !helper.isReachabilityTreeAncestorOf(root, node) { + t.Fatalf("TestReachabilityTreeNodeIsAncestorOf: node is not a descendant of root") + } + } + + if !helper.isReachabilityTreeAncestorOf(root, root) { + t.Fatalf("TestReachabilityTreeNodeIsAncestorOf: root is expected to be an ancestor of root") + } +} + +func TestIntervalContains(t *testing.T) { + tests := []struct { + name string + this, other *model.ReachabilityInterval + thisContainsOther bool + }{ + { + name: "this == other", + this: newReachabilityInterval(10, 100), + other: newReachabilityInterval(10, 100), + thisContainsOther: true, + }, + { + name: "this.start == other.start && this.end < other.end", + this: newReachabilityInterval(10, 90), + other: newReachabilityInterval(10, 100), + thisContainsOther: false, + }, + { + name: "this.start == other.start && this.end > other.end", + this: newReachabilityInterval(10, 100), + other: newReachabilityInterval(10, 90), + thisContainsOther: true, + }, + { + name: "this.start > other.start && this.end == other.end", + this: newReachabilityInterval(20, 100), + other: newReachabilityInterval(10, 100), + thisContainsOther: false, + }, + { + name: "this.start < other.start && this.end == other.end", + this: newReachabilityInterval(10, 100), + other: newReachabilityInterval(20, 100), + thisContainsOther: true, + }, + { + name: "this.start > other.start && this.end < other.end", + this: newReachabilityInterval(20, 90), + other: newReachabilityInterval(10, 100), + thisContainsOther: false, + }, + { + name: "this.start < other.start && this.end > other.end", + this: newReachabilityInterval(10, 100), + other: newReachabilityInterval(20, 90), + thisContainsOther: true, + }, + } + + for _, test := range tests { + if thisContainsOther := intervalContains(test.this, test.other); thisContainsOther != test.thisContainsOther { + t.Errorf("test.this.contains(test.other) is expected to be %t but got %t", + test.thisContainsOther, thisContainsOther) + } + } +} + +func TestSplitFraction(t *testing.T) { + tests := []struct { + interval *model.ReachabilityInterval + fraction float64 + expectedLeft *model.ReachabilityInterval + expectedRight *model.ReachabilityInterval + }{ + { + interval: newReachabilityInterval(1, 100), + fraction: 0.5, + expectedLeft: newReachabilityInterval(1, 50), + expectedRight: newReachabilityInterval(51, 100), + }, + { + interval: newReachabilityInterval(2, 100), + fraction: 0.5, + expectedLeft: newReachabilityInterval(2, 51), + expectedRight: newReachabilityInterval(52, 100), + }, + { + interval: newReachabilityInterval(1, 99), + fraction: 0.5, + expectedLeft: newReachabilityInterval(1, 50), + expectedRight: newReachabilityInterval(51, 99), + }, + { + interval: newReachabilityInterval(1, 100), + fraction: 0.2, + expectedLeft: newReachabilityInterval(1, 20), + expectedRight: newReachabilityInterval(21, 100), + }, + { + interval: newReachabilityInterval(1, 100), + fraction: 0, + expectedLeft: newReachabilityInterval(1, 0), + expectedRight: newReachabilityInterval(1, 100), + }, + { + interval: newReachabilityInterval(1, 100), + fraction: 1, + expectedLeft: newReachabilityInterval(1, 100), + expectedRight: newReachabilityInterval(101, 100), + }, + } + + for i, test := range tests { + left, right, err := intervalSplitFraction(test.interval, test.fraction) + if err != nil { + t.Fatalf("TestSplitFraction: splitFraction unexpectedly failed in test #%d: %s", i, err) + } + if !reflect.DeepEqual(left, test.expectedLeft) { + t.Errorf("TestSplitFraction: unexpected left in test #%d. "+ + "want: %s, got: %s", i, test.expectedLeft, left) + } + if !reflect.DeepEqual(right, test.expectedRight) { + t.Errorf("TestSplitFraction: unexpected right in test #%d. "+ + "want: %s, got: %s", i, test.expectedRight, right) + } + } +} + +func TestSplitExact(t *testing.T) { + tests := []struct { + interval *model.ReachabilityInterval + sizes []uint64 + expectedIntervals []*model.ReachabilityInterval + }{ + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{100}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{50, 50}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 50), + newReachabilityInterval(51, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{10, 20, 30, 40}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 10), + newReachabilityInterval(11, 30), + newReachabilityInterval(31, 60), + newReachabilityInterval(61, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{0, 100}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 0), + newReachabilityInterval(1, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{100, 0}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 100), + newReachabilityInterval(101, 100), + }, + }, + } + + for i, test := range tests { + intervals, err := intervalSplitExact(test.interval, test.sizes) + if err != nil { + t.Fatalf("TestSplitExact: splitExact unexpectedly failed in test #%d: %s", i, err) + } + if !reflect.DeepEqual(intervals, test.expectedIntervals) { + t.Errorf("TestSplitExact: unexpected intervals in test #%d. "+ + "want: %s, got: %s", i, test.expectedIntervals, intervals) + } + } +} + +func TestSplitWithExponentialBias(t *testing.T) { + tests := []struct { + interval *model.ReachabilityInterval + sizes []uint64 + expectedIntervals []*model.ReachabilityInterval + }{ + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{100}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{50, 50}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 50), + newReachabilityInterval(51, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{10, 20, 30, 40}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 10), + newReachabilityInterval(11, 30), + newReachabilityInterval(31, 60), + newReachabilityInterval(61, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{25, 25}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 50), + newReachabilityInterval(51, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{1, 1}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 50), + newReachabilityInterval(51, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{33, 33, 33}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 33), + newReachabilityInterval(34, 66), + newReachabilityInterval(67, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{10, 15, 25}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 10), + newReachabilityInterval(11, 25), + newReachabilityInterval(26, 100), + }, + }, + { + interval: newReachabilityInterval(1, 100), + sizes: []uint64{25, 15, 10}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 75), + newReachabilityInterval(76, 90), + newReachabilityInterval(91, 100), + }, + }, + { + interval: newReachabilityInterval(1, 10_000), + sizes: []uint64{10, 10, 20}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 20), + newReachabilityInterval(21, 40), + newReachabilityInterval(41, 10_000), + }, + }, + { + interval: newReachabilityInterval(1, 100_000), + sizes: []uint64{31_000, 31_000, 30_001}, + expectedIntervals: []*model.ReachabilityInterval{ + newReachabilityInterval(1, 35_000), + newReachabilityInterval(35_001, 69_999), + newReachabilityInterval(70_000, 100_000), + }, + }, + } + + for i, test := range tests { + intervals, err := intervalSplitWithExponentialBias(test.interval, test.sizes) + if err != nil { + t.Fatalf("TestSplitWithExponentialBias: splitWithExponentialBias unexpectedly failed in test #%d: %s", i, err) + } + if !reflect.DeepEqual(intervals, test.expectedIntervals) { + t.Errorf("TestSplitWithExponentialBias: unexpected intervals in test #%d. "+ + "want: %s, got: %s", i, test.expectedIntervals, intervals) + } + } +} + +func TestHasAncestorOf(t *testing.T) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, t, reachabilityDataStore) + + futureCoveringTreeNodeSet := model.FutureCoveringTreeNodeSet{ + helper.newNodeWithInterval(newReachabilityInterval(2, 3)), + helper.newNodeWithInterval(newReachabilityInterval(4, 67)), + helper.newNodeWithInterval(newReachabilityInterval(67, 77)), + helper.newNodeWithInterval(newReachabilityInterval(657, 789)), + helper.newNodeWithInterval(newReachabilityInterval(1000, 1000)), + helper.newNodeWithInterval(newReachabilityInterval(1920, 1921)), + } + + nodeWithFutureCoveringTreeNodeSet := helper.newNode() + err := helper.stageFutureCoveringSet(nodeWithFutureCoveringTreeNodeSet, futureCoveringTreeNodeSet) + if err != nil { + t.Fatalf("stageFutureCoveringSet: %s", err) + } + + tests := []struct { + treeNode *externalapi.DomainHash + expectedResult bool + }{ + { + treeNode: helper.newNodeWithInterval(newReachabilityInterval(1, 1)), + expectedResult: false, + }, + { + treeNode: helper.newNodeWithInterval(newReachabilityInterval(5, 7)), + expectedResult: true, + }, + { + treeNode: helper.newNodeWithInterval(newReachabilityInterval(67, 76)), + expectedResult: true, + }, + { + treeNode: helper.newNodeWithInterval(newReachabilityInterval(78, 100)), + expectedResult: false, + }, + { + treeNode: helper.newNodeWithInterval(newReachabilityInterval(1980, 2000)), + expectedResult: false, + }, + { + treeNode: helper.newNodeWithInterval(newReachabilityInterval(1920, 1920)), + expectedResult: true, + }, + } + + for i, test := range tests { + result, err := helper.futureCoveringSetHasAncestorOf(nodeWithFutureCoveringTreeNodeSet, test.treeNode) + if err != nil { + t.Fatalf("futureCoveringSetHasAncestorOf: %s", err) + } + + if result != test.expectedResult { + t.Errorf("TestHasAncestorOf: unexpected result in test #%d. Want: %t, got: %t", + i, test.expectedResult, result) + } + } +} + +func TestInsertToFutureCoveringSet(t *testing.T) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, t, reachabilityDataStore) + + nodeByIntervalMap := make(map[model.ReachabilityInterval]*externalapi.DomainHash) + nodeByInterval := func(interval *model.ReachabilityInterval) *externalapi.DomainHash { + if node, ok := nodeByIntervalMap[*interval]; ok { + return node + } + + nodeByIntervalMap[*interval] = helper.newNodeWithInterval(interval) + return nodeByIntervalMap[*interval] + } + + futureCoveringTreeNodeSet := model.FutureCoveringTreeNodeSet{ + nodeByInterval(newReachabilityInterval(1, 3)), + nodeByInterval(newReachabilityInterval(4, 67)), + nodeByInterval(newReachabilityInterval(67, 77)), + nodeByInterval(newReachabilityInterval(657, 789)), + nodeByInterval(newReachabilityInterval(1000, 1000)), + nodeByInterval(newReachabilityInterval(1920, 1921)), + } + + tests := []struct { + toInsert []*externalapi.DomainHash + expectedResult model.FutureCoveringTreeNodeSet + }{ + { + toInsert: []*externalapi.DomainHash{ + nodeByInterval(newReachabilityInterval(5, 7)), + }, + expectedResult: model.FutureCoveringTreeNodeSet{ + nodeByInterval(newReachabilityInterval(1, 3)), + nodeByInterval(newReachabilityInterval(4, 67)), + nodeByInterval(newReachabilityInterval(67, 77)), + nodeByInterval(newReachabilityInterval(657, 789)), + nodeByInterval(newReachabilityInterval(1000, 1000)), + nodeByInterval(newReachabilityInterval(1920, 1921)), + }, + }, + { + toInsert: []*externalapi.DomainHash{ + nodeByInterval(newReachabilityInterval(65, 78)), + }, + expectedResult: model.FutureCoveringTreeNodeSet{ + nodeByInterval(newReachabilityInterval(1, 3)), + nodeByInterval(newReachabilityInterval(4, 67)), + nodeByInterval(newReachabilityInterval(65, 78)), + nodeByInterval(newReachabilityInterval(657, 789)), + nodeByInterval(newReachabilityInterval(1000, 1000)), + nodeByInterval(newReachabilityInterval(1920, 1921)), + }, + }, + { + toInsert: []*externalapi.DomainHash{ + nodeByInterval(newReachabilityInterval(88, 97)), + }, + expectedResult: model.FutureCoveringTreeNodeSet{ + nodeByInterval(newReachabilityInterval(1, 3)), + nodeByInterval(newReachabilityInterval(4, 67)), + nodeByInterval(newReachabilityInterval(67, 77)), + nodeByInterval(newReachabilityInterval(88, 97)), + nodeByInterval(newReachabilityInterval(657, 789)), + nodeByInterval(newReachabilityInterval(1000, 1000)), + nodeByInterval(newReachabilityInterval(1920, 1921)), + }, + }, + { + toInsert: []*externalapi.DomainHash{ + nodeByInterval(newReachabilityInterval(88, 97)), + nodeByInterval(newReachabilityInterval(3000, 3010)), + }, + expectedResult: model.FutureCoveringTreeNodeSet{ + nodeByInterval(newReachabilityInterval(1, 3)), + nodeByInterval(newReachabilityInterval(4, 67)), + nodeByInterval(newReachabilityInterval(67, 77)), + nodeByInterval(newReachabilityInterval(88, 97)), + nodeByInterval(newReachabilityInterval(657, 789)), + nodeByInterval(newReachabilityInterval(1000, 1000)), + nodeByInterval(newReachabilityInterval(1920, 1921)), + nodeByInterval(newReachabilityInterval(3000, 3010)), + }, + }, + } + + for i, test := range tests { + // Create a clone of treeNodes so that we have a clean start for every test + futureCoveringTreeNodeSetClone := make(model.FutureCoveringTreeNodeSet, len(futureCoveringTreeNodeSet)) + copy(futureCoveringTreeNodeSetClone, futureCoveringTreeNodeSet) + + node := helper.newNode() + err := helper.stageFutureCoveringSet(node, futureCoveringTreeNodeSetClone) + if err != nil { + t.Fatalf("stageFutureCoveringSet: %s", err) + } + + for _, treeNode := range test.toInsert { + err := helper.insertToFutureCoveringSet(node, treeNode) + if err != nil { + t.Fatalf("insertToFutureCoveringSet: %s", err) + } + } + + resultFutureCoveringTreeNodeSet, err := helper.futureCoveringSet(node) + if err != nil { + t.Fatalf("futureCoveringSet: %s", err) + } + if !reflect.DeepEqual(model.FutureCoveringTreeNodeSet(resultFutureCoveringTreeNodeSet), test.expectedResult) { + t.Errorf("TestInsertToFutureCoveringSet: unexpected result in test #%d. Want: %s, got: %s", + i, test.expectedResult, resultFutureCoveringTreeNodeSet) + } + } +} + +func TestSplitFractionErrors(t *testing.T) { + interval := newReachabilityInterval(100, 200) + + // Negative fraction + _, _, err := intervalSplitFraction(interval, -0.5) + if err == nil { + t.Fatalf("TestSplitFractionErrors: splitFraction unexpectedly " + + "didn't return an error for a negative fraction") + } + expectedErrSubstring := "fraction must be between 0 and 1" + if !strings.Contains(err.Error(), expectedErrSubstring) { + t.Fatalf("TestSplitFractionErrors: splitFraction returned wrong error "+ + "for a negative fraction. "+ + "Want: %s, got: %s", expectedErrSubstring, err) + } + + // Fraction > 1 + _, _, err = intervalSplitFraction(interval, 1.5) + if err == nil { + t.Fatalf("TestSplitFractionErrors: splitFraction unexpectedly " + + "didn't return an error for a fraction greater than 1") + } + expectedErrSubstring = "fraction must be between 0 and 1" + if !strings.Contains(err.Error(), expectedErrSubstring) { + t.Fatalf("TestSplitFractionErrors: splitFraction returned wrong error "+ + "for a fraction greater than 1. "+ + "Want: %s, got: %s", expectedErrSubstring, err) + } + + // Splitting an empty interval + emptyInterval := newReachabilityInterval(1, 0) + _, _, err = intervalSplitFraction(emptyInterval, 0.5) + if err == nil { + t.Fatalf("TestSplitFractionErrors: splitFraction unexpectedly " + + "didn't return an error for an empty interval") + } + expectedErrSubstring = "cannot split an empty interval" + if !strings.Contains(err.Error(), expectedErrSubstring) { + t.Fatalf("TestSplitFractionErrors: splitFraction returned wrong error "+ + "for an empty interval. "+ + "Want: %s, got: %s", expectedErrSubstring, err) + } +} + +func TestSplitExactErrors(t *testing.T) { + interval := newReachabilityInterval(100, 199) + + // Sum of sizes greater than the size of the interval + sizes := []uint64{50, 51} + _, err := intervalSplitExact(interval, sizes) + if err == nil { + t.Fatalf("TestSplitExactErrors: splitExact unexpectedly " + + "didn't return an error for (sum of sizes) > (size of interval)") + } + expectedErrSubstring := "sum of sizes must be equal to the interval's size" + if !strings.Contains(err.Error(), expectedErrSubstring) { + t.Fatalf("TestSplitExactErrors: splitExact returned wrong error "+ + "for (sum of sizes) > (size of interval). "+ + "Want: %s, got: %s", expectedErrSubstring, err) + } + + // Sum of sizes smaller than the size of the interval + sizes = []uint64{50, 49} + _, err = intervalSplitExact(interval, sizes) + if err == nil { + t.Fatalf("TestSplitExactErrors: splitExact unexpectedly " + + "didn't return an error for (sum of sizes) < (size of interval)") + } + expectedErrSubstring = "sum of sizes must be equal to the interval's size" + if !strings.Contains(err.Error(), expectedErrSubstring) { + t.Fatalf("TestSplitExactErrors: splitExact returned wrong error "+ + "for (sum of sizes) < (size of interval). "+ + "Want: %s, got: %s", expectedErrSubstring, err) + } +} + +func TestSplitWithExponentialBiasErrors(t *testing.T) { + interval := newReachabilityInterval(100, 199) + + // Sum of sizes greater than the size of the interval + sizes := []uint64{50, 51} + _, err := intervalSplitWithExponentialBias(interval, sizes) + if err == nil { + t.Fatalf("TestSplitWithExponentialBiasErrors: splitWithExponentialBias " + + "unexpectedly didn't return an error") + } + expectedErrSubstring := "sum of sizes must be less than or equal to the interval's size" + if !strings.Contains(err.Error(), expectedErrSubstring) { + t.Fatalf("TestSplitWithExponentialBiasErrors: splitWithExponentialBias "+ + "returned wrong error. Want: %s, got: %s", expectedErrSubstring, err) + } +} + +func TestReindexIntervalErrors(t *testing.T) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, t, reachabilityDataStore) + + // Create a treeNode and give it size = 100 + treeNode := helper.newNodeWithInterval(newReachabilityInterval(0, 99)) + + // Add a chain of 100 child treeNodes to treeNode + var err error + currentTreeNode := treeNode + for i := 0; i < 100; i++ { + childTreeNode := helper.newNode() + err = helper.reachabilityManager.addChild(currentTreeNode, childTreeNode, treeNode) + if err != nil { + break + } + currentTreeNode = childTreeNode + } + + // At the 100th addChild we expect a reindex. This reindex should + // fail because our initial treeNode only has size = 100, and the + // reindex requires size > 100. + // This simulates the case when (somehow) there's more than 2^64 + // blocks in the DAG, since the genesis block has size = 2^64. + if err == nil { + t.Fatalf("TestReindexIntervalErrors: reindexIntervals " + + "unexpectedly didn't return an error") + } + if !strings.Contains(err.Error(), "missing tree parent during reindexing") { + t.Fatalf("TestReindexIntervalErrors: reindexIntervals "+ + "returned an expected error: %s", err) + } +} + +func BenchmarkReindexInterval(b *testing.B) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, b, reachabilityDataStore) + + for i := 0; i < b.N; i++ { + b.StopTimer() + + const subTreeSize = 70000 + // We set the interval of the root to subTreeSize*2 because + // its first child gets half of the interval, so a reindex + // from the root should happen after adding subTreeSize + // nodes. + root := helper.newNodeWithInterval(newReachabilityInterval(0, subTreeSize*2)) + + currentTreeNode := root + for i := 0; i < subTreeSize; i++ { + childTreeNode := helper.newNode() + helper.addChild(currentTreeNode, childTreeNode, root) + + currentTreeNode = childTreeNode + } + + originalRemainingInterval := *helper.remainingIntervalAfter(root) + // After we added subTreeSize nodes, adding the next + // node should lead to a reindex from root. + fullReindexTriggeringNode := helper.newNode() + b.StartTimer() + err := helper.reachabilityManager.addChild(currentTreeNode, fullReindexTriggeringNode, root) + b.StopTimer() + if err != nil { + b.Fatalf("addChild: %s", err) + } + + if *helper.remainingIntervalAfter(root) == originalRemainingInterval { + b.Fatal("Expected a reindex from root, but it didn't happen") + } + } +} + +func TestReachabilityTreeNodeString(t *testing.T) { + reachabilityDataStore := newReachabilityDataStoreMock() + manager := New(nil, nil, reachabilityDataStore).(*reachabilityManager) + helper := newTestHelper(manager, t, reachabilityDataStore) + + treeNodeA := helper.newNodeWithInterval(newReachabilityInterval(100, 199)) + treeNodeB1 := helper.newNodeWithInterval(newReachabilityInterval(100, 150)) + treeNodeB2 := helper.newNodeWithInterval(newReachabilityInterval(150, 199)) + treeNodeC := helper.newNodeWithInterval(newReachabilityInterval(100, 149)) + + err := helper.addChildAndStage(treeNodeA, treeNodeB1) + if err != nil { + t.Fatalf("addChildAndStage: %s", err) + } + + err = helper.addChildAndStage(treeNodeA, treeNodeB2) + if err != nil { + t.Fatalf("addChildAndStage: %s", err) + } + + err = helper.addChildAndStage(treeNodeB2, treeNodeC) + if err != nil { + t.Fatalf("addChildAndStage: %s", err) + } + + str, err := manager.String(treeNodeA) + if err != nil { + t.Fatalf("String: %s", err) + } + expectedStr := "[100,149]\n[100,150][150,199]\n[100,199]" + if str != expectedStr { + t.Fatalf("TestReachabilityTreeNodeString: unexpected "+ + "string. Want: %s, got: %s", expectedStr, str) + } +} diff --git a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go index 3fb5944b4..9bafb96c4 100644 --- a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go @@ -9,23 +9,24 @@ import ( // reachability queries in sub-linear time type reachabilityManager struct { databaseContext model.DBReader - blockRelationStore model.BlockRelationStore reachabilityDataStore model.ReachabilityDataStore ghostdagDataStore model.GHOSTDAGDataStore + reindexSlack uint64 + reindexWindow uint64 } // New instantiates a new reachabilityManager func New( databaseContext model.DBReader, ghostdagDataStore model.GHOSTDAGDataStore, - blockRelationStore model.BlockRelationStore, reachabilityDataStore model.ReachabilityDataStore, ) model.ReachabilityManager { return &reachabilityManager{ databaseContext: databaseContext, ghostdagDataStore: ghostdagDataStore, - blockRelationStore: blockRelationStore, reachabilityDataStore: reachabilityDataStore, + reindexSlack: defaultReindexSlack, + reindexWindow: defaultReindexWindow, } } diff --git a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go new file mode 100644 index 000000000..2b41d1852 --- /dev/null +++ b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go @@ -0,0 +1,23 @@ +package reachabilitymanager + +import "github.com/kaspanet/kaspad/domain/consensus/model" + +type testReachabilityManager struct { + *reachabilityManager +} + +func (t testReachabilityManager) ReachabilityReindexSlack() uint64 { + return t.reachabilityManager.reindexSlack +} + +func (t testReachabilityManager) SetReachabilityReindexSlack(reindexSlack uint64) { + t.reachabilityManager.reindexSlack = reindexSlack +} + +func (t testReachabilityManager) SetReachabilityReindexWindow(reindexWindow uint64) { + t.reachabilityManager.reindexWindow = reindexWindow +} + +func NewTestReachabilityManager(manager model.ReachabilityManager) model.TestReachabilityManager { + return &testReachabilityManager{reachabilityManager: manager.(*reachabilityManager)} +} diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 432e446b9..b531aae3a 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -12,14 +12,14 @@ import ( ) var ( - // reachabilityReindexWindow is the target window size for reachability + // defaultReindexWindow is the default target window size for reachability // reindexes. Note that this is not a constant for testing purposes. - reachabilityReindexWindow uint64 = 200 + defaultReindexWindow uint64 = 200 - // reachabilityReindexSlack is the slack interval given to reachability + // defaultReindexSlack is default the slack interval given to reachability // tree nodes not in the selected parent chain. Note that this is not // a constant for testing purposes. - reachabilityReindexSlack uint64 = 1 << 12 + defaultReindexSlack uint64 = 1 << 12 // slackReachabilityIntervalForReclaiming is the slack interval to // reclaim during reachability reindexes earlier than the reindex root. @@ -627,7 +627,7 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces // current node with an interval that is smaller by // slackReachabilityIntervalForReclaiming. This is to make room // for the new node. - for current != commonAncestor { + for *current != *commonAncestor { currentInterval, err := rt.interval(current) if err != nil { return err @@ -733,7 +733,7 @@ func (rt *reachabilityManager) String(node *externalapi.DomainHash) (string, err return "", err } - lines := []string{intervalString(nodeInterval)} + lines := []string{nodeInterval.String()} for len(queue) > 0 { var current *externalapi.DomainHash current, queue = queue[0], queue[1:] @@ -753,7 +753,7 @@ func (rt *reachabilityManager) String(node *externalapi.DomainHash) (string, err return "", err } - line += intervalString(childInterval) + line += childInterval.String() queue = append(queue, child) } lines = append([]string{line}, lines...) @@ -814,7 +814,7 @@ func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *ex return nil, false, err } - if newTreeNodeGHOSTDAGData.BlueScore-reindexRootChosenChildGHOSTDAGData.BlueScore < reachabilityReindexWindow { + if newTreeNodeGHOSTDAGData.BlueScore-reindexRootChosenChildGHOSTDAGData.BlueScore < rt.reindexWindow { return nil, false, nil } @@ -883,7 +883,7 @@ func (rt *reachabilityManager) splitChildrenAroundChild(node, child *externalapi } for i, candidateChild := range nodeChildren { - if candidateChild == child { + if *candidateChild == *child { return nodeChildren[:i], nodeChildren[i+1:], nil } } @@ -904,8 +904,8 @@ func (rt *reachabilityManager) tightenIntervalsBeforeReindexRootChosenChild( } intervalBeforeReindexRootStart := newReachabilityInterval( - reindexRootInterval.Start+reachabilityReindexSlack, - reindexRootInterval.Start+reachabilityReindexSlack+reindexRootChildNodesBeforeChosenSizesSum-1, + reindexRootInterval.Start+rt.reindexSlack, + reindexRootInterval.Start+rt.reindexSlack+reindexRootChildNodesBeforeChosenSizesSum-1, ) err = rt.propagateChildIntervals(intervalBeforeReindexRootStart, reindexRootChildNodesBeforeChosen, @@ -931,8 +931,8 @@ func (rt *reachabilityManager) tightenIntervalsAfterReindexRootChosenChild( } intervalAfterReindexRootEnd := newReachabilityInterval( - reindexRootInterval.End-reachabilityReindexSlack-reindexRootChildNodesAfterChosenSizesSum, - reindexRootInterval.End-reachabilityReindexSlack-1, + reindexRootInterval.End-rt.reindexSlack-reindexRootChildNodesAfterChosenSizesSum, + reindexRootInterval.End-rt.reindexSlack-1, ) err = rt.propagateChildIntervals(intervalAfterReindexRootEnd, reindexRootChildNodesAfterChosen, @@ -953,8 +953,8 @@ func (rt *reachabilityManager) expandIntervalInReindexRootChosenChild(reindexRoo } newReindexRootChildInterval := newReachabilityInterval( - reindexRootInterval.Start+reindexRootChildNodesBeforeChosenSizesSum+reachabilityReindexSlack, - reindexRootInterval.End-reindexRootChildNodesAfterChosenSizesSum-reachabilityReindexSlack-1, + reindexRootInterval.Start+reindexRootChildNodesBeforeChosenSizesSum+rt.reindexSlack, + reindexRootInterval.End-reindexRootChildNodesAfterChosenSizesSum-rt.reindexSlack-1, ) reindexRootChosenChildInterval, err := rt.interval(reindexRootChosenChild) @@ -973,8 +973,8 @@ func (rt *reachabilityManager) expandIntervalInReindexRootChosenChild(reindexRoo // reindex root moves), newReindexRootChildInterval is likely to // contain reindexRootChosenChild.Interval. err := rt.stageInterval(reindexRootChosenChild, newReachabilityInterval( - newReindexRootChildInterval.Start+reachabilityReindexSlack, - newReindexRootChildInterval.End-reachabilityReindexSlack, + newReindexRootChildInterval.Start+rt.reindexSlack, + newReindexRootChildInterval.End-rt.reindexSlack, )) if err != nil { return err diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index bd5843995..f6a19765b 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -1,21 +1,22 @@ package consensus import ( - "errors" - "math" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/mining" + "math/rand" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/util" ) type testConsensus struct { *consensus + rd *rand.Rand + testBlockBuilder model.TestBlockBuilder + testReachabilityManager model.TestReachabilityManager testConsensusStateManager model.TestConsensusStateManager } @@ -48,28 +49,16 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba return nil, err } - solveBlock(block) + return tc.SolveAndAddBlock(block) +} - // Use blockProcessor.ValidateAndInsertBlock instead of tc.ValidateAndInsertBlock to avoid double-locking - // the conscensus lock. - err = tc.blockProcessor.ValidateAndInsertBlock(block) +func (tc *testConsensus) SolveAndAddBlock(block *externalapi.DomainBlock) (*externalapi.DomainHash, error) { + mining.SolveBlock(block, tc.rd) + + err := tc.blockProcessor.ValidateAndInsertBlock(block) if err != nil { return nil, err } return consensusserialization.BlockHash(block), nil } - -func solveBlock(block *externalapi.DomainBlock) { - targetDifficulty := util.CompactToBig(block.Header.Bits) - - for i := uint64(0); i < math.MaxUint64; i++ { - block.Header.Nonce = i - hash := consensusserialization.BlockHash(block) - if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { - return - } - } - - panic(errors.New("went over all the nonce space and couldn't find a single one that gives a valid block")) -} diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 7e68ed231..110d79d86 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -109,8 +109,8 @@ func (tc *testConsensus) PruningManager() model.PruningManager { return tc.pruningManager } -func (tc *testConsensus) ReachabilityManager() model.ReachabilityManager { - return tc.reachabilityManager +func (tc *testConsensus) ReachabilityManager() model.TestReachabilityManager { + return tc.testReachabilityManager } func (tc *testConsensus) SyncManager() model.SyncManager { diff --git a/domain/consensus/utils/mining/solve.go b/domain/consensus/utils/mining/solve.go new file mode 100644 index 000000000..3bffe95c3 --- /dev/null +++ b/domain/consensus/utils/mining/solve.go @@ -0,0 +1,25 @@ +package mining + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + utilsMath "github.com/kaspanet/kaspad/domain/consensus/utils/math" + "github.com/pkg/errors" + "math" + "math/rand" +) + +func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) { + targetDifficulty := utilsMath.CompactToBig(block.Header.Bits) + + for i := rd.Uint64(); i < math.MaxUint64; i++ { + block.Header.Nonce = i + hash := consensusserialization.BlockHash(block) + if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { + return + } + } + + panic(errors.New("went over all the nonce space and couldn't find a single one that gives a valid block")) +} diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 65819fd31..577e37b49 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -155,7 +155,7 @@ var simnetGenesisBlock = externalapi.DomainBlock{ UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x175bca27c39, Bits: 0x207fffff, - Nonce: 1, + Nonce: 0x1, }, Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } From f52cddc25c39b1d186ad79850d71ceed10e11228 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 13:12:42 +0200 Subject: [PATCH 021/351] [NOD-1532] Remove consensus rule that requires blocks are sorted by hash --- .../block_header_in_isolation.go | 26 ------------------- domain/consensus/ruleerrors/rule_error.go | 3 --- 2 files changed, 29 deletions(-) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 3c8455e53..6c13cb4ee 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -1,13 +1,10 @@ package blockvalidator import ( - "sort" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/pkg/errors" ) @@ -24,11 +21,6 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain return err } - err = checkBlockParentsOrder(header) - if err != nil { - return err - } - return nil } @@ -44,21 +36,3 @@ func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader } return nil } - -//checkBlockParentsOrder ensures that the block's parents are ordered by hash -func checkBlockParentsOrder(header *externalapi.DomainBlockHeader) error { - sortedHashes := make([]*externalapi.DomainHash, len(header.ParentHashes)) - for i, hash := range header.ParentHashes { - sortedHashes[i] = hash - } - - isSorted := sort.SliceIsSorted(sortedHashes, func(i, j int) bool { - return hashes.Less(sortedHashes[i], sortedHashes[j]) - }) - - if !isSorted { - return errors.Wrapf(ruleerrors.ErrWrongParentsOrder, "block parents are not ordered by hash") - } - - return nil -} diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index d24623dba..8b0367b89 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -34,9 +34,6 @@ var ( // ErrNoParents indicates that the block is missing parents ErrNoParents = newRuleError("ErrNoParents") - // ErrWrongParentsOrder indicates that the block's parents are not ordered by hash, as expected - ErrWrongParentsOrder = newRuleError("ErrWrongParentsOrder") - // ErrDifficultyTooLow indicates the difficulty for the block is lower // than the difficulty required. ErrDifficultyTooLow = newRuleError("ErrDifficultyTooLow") From c52b8100c670d2dc842baba7589ecc6b216de45b Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 13:37:39 +0200 Subject: [PATCH 022/351] [NOD-1532] make dagtopologymanager test external --- .../dagtopologymanager/dagtopologymanager_external_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go index 7c35188d6..c8ef97ab1 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -1,11 +1,12 @@ -package dagtopologymanager +package dagtopologymanager_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 TestIsInPast(t *testing.T) { From 7d14f24b84bc0aec6fb0befbb7c018a3e005fe72 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 14:42:34 +0200 Subject: [PATCH 023/351] [NOD-1532] Fix some error messages --- .../consensusstatemanager/resolve_block_status_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index cafb4e8ce..868f72b55 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -84,7 +84,7 @@ func TestDoubleSpends(t *testing.T) { t.Fatalf("Error getting status of goodBlock: %+v", err) } if doubleSpendingBlock1Status != externalapi.StatusDisqualifiedFromChain { - t.Fatalf("GoodBlock status expected to be '%s', but is '%s'", + t.Fatalf("doubleSpendingBlock1 status expected to be '%s', but is '%s'", externalapi.StatusDisqualifiedFromChain, doubleSpendingBlock1Status) } @@ -101,7 +101,7 @@ func TestDoubleSpends(t *testing.T) { t.Fatalf("Error getting status of goodBlock: %+v", err) } if doubleSpendingBlock2Status != externalapi.StatusDisqualifiedFromChain { - t.Fatalf("GoodBlock status expected to be '%s', but is '%s'", + t.Fatalf("doubleSpendingBlock2 status expected to be '%s', but is '%s'", externalapi.StatusDisqualifiedFromChain, doubleSpendingBlock2Status) } @@ -144,7 +144,7 @@ func TestDoubleSpends(t *testing.T) { t.Fatalf("Error getting status of goodBlock: %+v", err) } if goodBlock2Status != externalapi.StatusValid { - t.Fatalf("GoodBlock status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock2Status) + t.Fatalf("GoodBlock2 status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock2Status) } }) } From aeded07815a5fbc23940bc8aa13b248fa42a8ff3 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 14:55:56 +0200 Subject: [PATCH 024/351] [NOD-1532] Make BuildBlockWithParents resolve the status of the new block's selectedParent --- domain/consensus/factory.go | 14 ++++++----- .../blockbuilder/test_block_builder.go | 24 ++++++++++++++++--- domain/consensus/test_consensus_getters.go | 3 +-- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index f1fbe1b38..ca47109ae 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,12 +1,13 @@ package consensus import ( - "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" "io/ioutil" "math/rand" "os" "sync" + "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database" @@ -282,6 +283,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat headerTipsStore: headerTipsStore, multisetStore: multisetStore, reachabilityDataStore: reachabilityDataStore, + utxoDiffStore: utxoDiffStore, } genesisInfo, err := c.GetBlockInfo(genesisHash) @@ -317,20 +319,20 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) consensusAsImplementation := consensusAsInterface.(*consensus) - testBlockBuilder := blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder) testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager) - tc = &testConsensus{ - rd: rand.New(rand.NewSource(0)), + + tstConsensus := &testConsensus{ + rd: rand.New(rand.NewSource(0)), consensus: consensusAsImplementation, - testBlockBuilder: testBlockBuilder, testConsensusStateManager: testConsensusStateManager, testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation. reachabilityManager), } + tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus) teardown = func() { db.Close() os.RemoveAll(testDatabaseDir) } - return tc, teardown, nil + return tstConsensus, teardown, nil } diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 35cfd30a7..c01b8a195 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -3,20 +3,25 @@ package blockbuilder import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/infrastructure/logger" ) type testBlockBuilder struct { *blockBuilder + testConsensus testapi.TestConsensus } var tempBlockHash = &externalapi.DomainHash{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} // NewTestBlockBuilder creates an instance of a TestBlockBuilder -func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder) model.TestBlockBuilder { - return &testBlockBuilder{blockBuilder: baseBlockBuilder.(*blockBuilder)} +func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus testapi.TestConsensus) model.TestBlockBuilder { + return &testBlockBuilder{ + blockBuilder: baseBlockBuilder.(*blockBuilder), + testConsensus: testConsensus, + } } func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, @@ -79,6 +84,20 @@ func (bb *testBlockBuilder) buildBlockWithParents( } defer bb.ghostdagDataStore.Discard() + ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash) + if err != nil { + return nil, err + } + + _, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + if err != nil { + return nil, err + } + defer bb.testConsensus.BlockStatusStore().Discard() + defer bb.acceptanceDataStore.Discard() + defer bb.multisetStore.Discard() + defer bb.testConsensus.UTXODiffStore().Discard() + _, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) if err != nil { return nil, err @@ -87,7 +106,6 @@ func (bb *testBlockBuilder) buildBlockWithParents( if err != nil { return nil, err } - defer bb.acceptanceDataStore.Discard() coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData) if err != nil { diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 110d79d86..a61e2b069 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -2,7 +2,6 @@ package consensus import ( "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/processes/blockbuilder" ) func (tc *testConsensus) DatabaseContext() model.DBReader { @@ -58,7 +57,7 @@ func (tc *testConsensus) UTXODiffStore() model.UTXODiffStore { } func (tc *testConsensus) BlockBuilder() model.TestBlockBuilder { - return blockbuilder.NewTestBlockBuilder(tc.blockBuilder) + return tc.testBlockBuilder } func (tc *testConsensus) BlockProcessor() model.BlockProcessor { From b50421beee6adec2ee24dacce687387fadd39d98 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 15 Nov 2020 05:27:01 -0800 Subject: [PATCH 025/351] [NOD-1535] Don't reuse pointers on loop (#1069) * [NOD-1535] Don't reuse pointers on loop * [NOD-1535] Don't reuse pointers on loop --- domain/consensus/utils/hashset/hash_set.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/domain/consensus/utils/hashset/hash_set.go b/domain/consensus/utils/hashset/hash_set.go index 0e0b5bbfa..8772b4507 100644 --- a/domain/consensus/utils/hashset/hash_set.go +++ b/domain/consensus/utils/hashset/hash_set.go @@ -55,8 +55,9 @@ func (hs HashSet) Subtract(other HashSet) HashSet { diff := New() for hash := range hs { - if !other.Contains(&hash) { - diff.Add(&hash) + hashCopy := hash + if !other.Contains(&hashCopy) { + diff.Add(&hashCopy) } } @@ -79,7 +80,8 @@ func (hs HashSet) ToSlice() []*externalapi.DomainHash { slice := make([]*externalapi.DomainHash, 0, len(hs)) for hash := range hs { - slice = append(slice, &hash) + hashCopy := hash + slice = append(slice, &hashCopy) } return slice From a1fa17d872f5656d1e0911467b79329d1874f993 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 15:36:10 +0200 Subject: [PATCH 026/351] [NOD-1532] Add DiscardAllStores to TestConsensus --- domain/consensus/consensus.go | 1 + domain/consensus/factory.go | 1 + .../consensus/model/testapi/test_consensus.go | 2 ++ .../blockbuilder/test_block_builder.go | 8 ++------ domain/consensus/test_consensus.go | 18 +++++++++++++++++- domain/consensus/test_consensus_getters.go | 2 +- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 03915010a..3a8903ee3 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -30,6 +30,7 @@ type consensus struct { pruningManager model.PruningManager reachabilityManager model.ReachabilityManager + acceptanceDataStore model.AcceptanceDataStore blockStore model.BlockStore blockHeaderStore model.BlockHeaderStore pruningStore model.PruningStore diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index ca47109ae..44fd76f48 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -273,6 +273,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat pruningManager: pruningManager, reachabilityManager: reachabilityManager, + acceptanceDataStore: acceptanceDataStore, blockStore: blockStore, blockHeaderStore: blockHeaderStore, pruningStore: pruningStore, diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index be16dfbe0..37fbc8e67 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -21,6 +21,8 @@ type TestConsensus interface { SolveAndAddBlock(block *externalapi.DomainBlock) (*externalapi.DomainHash, error) + DiscardAllStores() + AcceptanceDataStore() model.AcceptanceDataStore BlockHeaderStore() model.BlockHeaderStore BlockRelationStore() model.BlockRelationStore diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index c01b8a195..a8597efa2 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -72,17 +72,17 @@ func (bb *testBlockBuilder) buildBlockWithParents( parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + defer bb.testConsensus.DiscardAllStores() + err := bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) if err != nil { return nil, err } - defer bb.blockRelationStore.Discard() err = bb.ghostdagManager.GHOSTDAG(tempBlockHash) if err != nil { return nil, err } - defer bb.ghostdagDataStore.Discard() ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash) if err != nil { @@ -93,10 +93,6 @@ func (bb *testBlockBuilder) buildBlockWithParents( if err != nil { return nil, err } - defer bb.testConsensus.BlockStatusStore().Discard() - defer bb.acceptanceDataStore.Discard() - defer bb.multisetStore.Discard() - defer bb.testConsensus.UTXODiffStore().Discard() _, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) if err != nil { diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index f6a19765b..d36cfce53 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -1,9 +1,10 @@ package consensus import ( + "math/rand" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/mining" - "math/rand" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" @@ -62,3 +63,18 @@ func (tc *testConsensus) SolveAndAddBlock(block *externalapi.DomainBlock) (*exte return consensusserialization.BlockHash(block), nil } + +func (tc *testConsensus) DiscardAllStores() { + tc.AcceptanceDataStore().Discard() + tc.BlockHeaderStore().Discard() + tc.BlockRelationStore().Discard() + tc.BlockStatusStore().Discard() + tc.BlockStore().Discard() + tc.ConsensusStateStore().Discard() + tc.GHOSTDAGDataStore().Discard() + tc.HeaderTipsStore().Discard() + tc.MultisetStore().Discard() + tc.PruningStore().Discard() + tc.ReachabilityDataStore().Discard() + tc.UTXODiffStore().Discard() +} diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index a61e2b069..0ab7f6ccd 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -9,7 +9,7 @@ func (tc *testConsensus) DatabaseContext() model.DBReader { } func (tc *testConsensus) AcceptanceDataStore() model.AcceptanceDataStore { - return tc.AcceptanceDataStore() + return tc.acceptanceDataStore } func (tc *testConsensus) BlockHeaderStore() model.BlockHeaderStore { From afbad73c0b5592d810b0eec9c556d0fedf790cba Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 15 Nov 2020 06:12:58 -0800 Subject: [PATCH 027/351] [NOD-1535] Don't compare pointers (#1072) --- .../reachabilitymanager/reachability_external_test.go | 4 ++-- domain/consensus/processes/reachabilitymanager/tree.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index c5b5edd35..cdd97593c 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -234,12 +234,12 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { // Each addition will trigger a low-than-reindex-root reindex. We // expect the centerInterval to shrink by 1 each time, but its child // to remain unaffected - cetnerData, err := tc.ReachabilityDataStore().ReachabilityData(tc.DatabaseContext(), centerBlock) + centerData, err := tc.ReachabilityDataStore().ReachabilityData(tc.DatabaseContext(), centerBlock) if err != nil { t.Fatalf("ReachabilityData: %s", err) } - treeChildOfCenterBlock := cetnerData.TreeNode.Children[0] + treeChildOfCenterBlock := centerData.TreeNode.Children[0] treeChildOfCenterBlockOriginalIntervalSize := intervalSize(treeChildOfCenterBlock) leftTipHash := leftBlock for i := uint64(0); i < reachabilityReindexWindow-1; i++ { diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index b531aae3a..8ea711939 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -317,7 +317,7 @@ func (rt *reachabilityManager) countSubtrees(node *externalapi.DomainHash, subTr // We reached a leaf or a pre-calculated subtree. // Push information up - for current != node { + for *current != *node { current, err = rt.parent(current) if err != nil { return err @@ -471,7 +471,7 @@ func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAnces } } - if current == reindexRoot { + if *current == *reindexRoot { // "Deallocate" an interval of slackReachabilityIntervalForReclaiming // from this node. This is the interval that we'll use for the new // node. @@ -505,7 +505,7 @@ func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAnces // current node with an interval that is smaller by // slackReachabilityIntervalForReclaiming. This is to make room // for the new node. - for current != commonAncestor { + for *current != *commonAncestor { currentInterval, err := rt.interval(current) if err != nil { return err @@ -593,7 +593,7 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces } } - if current == reindexRoot { + if *current == *reindexRoot { // "Deallocate" an interval of slackReachabilityIntervalForReclaiming // from this node. This is the interval that we'll use for the new // node. From 3ab507b66feb2d43b8c0cf515ddd75e8a960f401 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 16:42:06 +0200 Subject: [PATCH 028/351] [NOD-1532] Use correct coinbase transaction in buildBlockWith Parents --- domain/consensus/processes/blockbuilder/test_block_builder.go | 2 +- .../processes/consensusstatemanager/verify_and_build_utxo.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index a8597efa2..6dc944f34 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -103,7 +103,7 @@ func (bb *testBlockBuilder) buildBlockWithParents( return nil, err } - coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData) + coinbase, err := bb.coinbaseManager.ExpectedCoinbaseTransaction(tempBlockHash, coinbaseData) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index f5a718c0d..a85259d01 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -31,6 +31,9 @@ func (csm *consensusStateManager) verifyAndBuildUTXO(block *externalapi.DomainBl coinbaseTransaction := block.Transactions[0] err = csm.validateCoinbaseTransaction(blockHash, coinbaseTransaction) + if err != nil { + return err + } err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff, err) if err != nil { From efe1986a56e70d235c202cc60fb7d406bb1a5bca Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 16:42:45 +0200 Subject: [PATCH 029/351] [NOD-1532] Don't validate coinbase transaction in normal flow --- .../consensusstatemanager/verify_and_build_utxo.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index a85259d01..e9d9c6156 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -3,6 +3,8 @@ package consensusstatemanager import ( "sort" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + "github.com/kaspanet/kaspad/domain/consensus/utils/coinbase" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" @@ -51,7 +53,10 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block return err } - for _, transaction := range block.Transactions { + for i, transaction := range block.Transactions { + if i == transactionhelper.CoinbaseTransactionIndex { + continue + } err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, pastUTXODiff) if err != nil { return err From a34091991ad6f7ae5e2da6696a638ca9cea40a7f Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 15 Nov 2020 17:28:28 +0200 Subject: [PATCH 030/351] [NOD-1538] Fix MinimalNetAdapter and don't insert BlockRelations before making sure the block's parents exist (#1074) * [NOD-1538] Fix minimal net adapter. * [NOD-1538] Don't insert block relation until we've validated that the block's parents exist. * [NOD-1538] Don't hold addressManager in MinimalNetAdapter. * [NOD-1538] Fix a comment in messages.proto. --- app/appmessage/p2p_msgaddresses.go | 54 +- app/appmessage/p2p_msgaddresses_test.go | 58 - .../flows/addressexchange/receiveaddresses.go | 14 +- .../flows/addressexchange/sendaddresses.go | 13 +- app/protocol/peer/peer.go | 8 +- .../blockprocessor/validateandinsertblock.go | 5 - .../processes/blockvalidator/proof_of_work.go | 5 + .../grpcserver/protowire/messages.pb.go | 1634 ++++++++--------- .../grpcserver/protowire/messages.proto | 18 +- .../grpcserver/protowire/p2p_addresses.go | 22 +- .../standalone/minimal_net_adapter.go | 45 +- .../network/netadapter/standalone/routes.go | 1 + 12 files changed, 884 insertions(+), 993 deletions(-) delete mode 100644 app/appmessage/p2p_msgaddresses_test.go diff --git a/app/appmessage/p2p_msgaddresses.go b/app/appmessage/p2p_msgaddresses.go index 402452e15..f9093466e 100644 --- a/app/appmessage/p2p_msgaddresses.go +++ b/app/appmessage/p2p_msgaddresses.go @@ -4,59 +4,15 @@ package appmessage -import ( - "fmt" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - // MaxAddressesPerMsg is the maximum number of addresses that can be in a single // kaspa Addresses message (MsgAddresses). const MaxAddressesPerMsg = 1000 // MsgAddresses implements the Message interface and represents a kaspa -// Addresses message. It is used to provide a list of known active peers on the -// network. An active peer is considered one that has transmitted a message -// within the last 3 hours. Nodes which have not transmitted in that time -// frame should be forgotten. Each message is limited to a maximum number of -// addresses, which is currently 1000. As a result, multiple messages must -// be used to relay the full list. -// -// Use the AddAddress function to build up the list of known addresses when -// sending an Addresses message to another peer. +// Addresses message. type MsgAddresses struct { baseMessage - IncludeAllSubnetworks bool - SubnetworkID *externalapi.DomainSubnetworkID - AddrList []*NetAddress -} - -// AddAddress adds a known active peer to the message. -func (msg *MsgAddresses) AddAddress(na *NetAddress) error { - if len(msg.AddrList)+1 > MaxAddressesPerMsg { - str := fmt.Sprintf("too many addresses in message [max %d]", - MaxAddressesPerMsg) - return messageError("MsgAddresses.AddAddress", str) - } - - msg.AddrList = append(msg.AddrList, na) - return nil -} - -// AddAddresses adds multiple known active peers to the message. -func (msg *MsgAddresses) AddAddresses(netAddrs ...*NetAddress) error { - for _, na := range netAddrs { - err := msg.AddAddress(na) - if err != nil { - return err - } - } - return nil -} - -// ClearAddresses removes all addresses from the message. -func (msg *MsgAddresses) ClearAddresses() { - msg.AddrList = []*NetAddress{} + AddressList []*NetAddress } // Command returns the protocol command string for the message. This is part @@ -67,10 +23,8 @@ func (msg *MsgAddresses) Command() MessageCommand { // NewMsgAddresses returns a new kaspa Addresses message that conforms to the // Message interface. See MsgAddresses for details. -func NewMsgAddresses(includeAllSubnetworks bool, subnetworkID *externalapi.DomainSubnetworkID) *MsgAddresses { +func NewMsgAddresses(addressList []*NetAddress) *MsgAddresses { return &MsgAddresses{ - IncludeAllSubnetworks: includeAllSubnetworks, - SubnetworkID: subnetworkID, - AddrList: make([]*NetAddress, 0, MaxAddressesPerMsg), + AddressList: addressList, } } diff --git a/app/appmessage/p2p_msgaddresses_test.go b/app/appmessage/p2p_msgaddresses_test.go deleted file mode 100644 index 38d50c550..000000000 --- a/app/appmessage/p2p_msgaddresses_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package appmessage - -import ( - "net" - "testing" - - "github.com/davecgh/go-spew/spew" -) - -// TestAddresses tests the MsgAddresses API. -func TestAddresses(t *testing.T) { - // Ensure the command is expected value. - wantCmd := MessageCommand(3) - msg := NewMsgAddresses(false, nil) - if cmd := msg.Command(); cmd != wantCmd { - t.Errorf("NewMsgAddresses: wrong command - got %v want %v", - cmd, wantCmd) - } - - // Ensure NetAddresses are added properly. - tcpAddr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 16111} - na := NewNetAddress(tcpAddr, SFNodeNetwork) - err := msg.AddAddress(na) - if err != nil { - t.Errorf("AddAddress: %v", err) - } - if msg.AddrList[0] != na { - t.Errorf("AddAddress: wrong address added - got %v, want %v", - spew.Sprint(msg.AddrList[0]), spew.Sprint(na)) - } - - // Ensure the address list is cleared properly. - msg.ClearAddresses() - if len(msg.AddrList) != 0 { - t.Errorf("ClearAddresses: address list is not empty - "+ - "got %v [%v], want %v", len(msg.AddrList), - spew.Sprint(msg.AddrList[0]), 0) - } - - // Ensure adding more than the max allowed addresses per message returns - // error. - for i := 0; i < MaxAddressesPerMsg+1; i++ { - err = msg.AddAddress(na) - } - if err == nil { - t.Errorf("AddAddress: expected error on too many addresses " + - "not received") - } - err = msg.AddAddresses(na) - if err == nil { - t.Errorf("AddAddresses: expected error on too many addresses " + - "not received") - } -} diff --git a/app/protocol/flows/addressexchange/receiveaddresses.go b/app/protocol/flows/addressexchange/receiveaddresses.go index 5e6d7e4fc..779ab7714 100644 --- a/app/protocol/flows/addressexchange/receiveaddresses.go +++ b/app/protocol/flows/addressexchange/receiveaddresses.go @@ -33,20 +33,10 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou } msgAddresses := message.(*appmessage.MsgAddresses) - if len(msgAddresses.AddrList) > addressmanager.GetAddressesMax { + if len(msgAddresses.AddressList) > addressmanager.GetAddressesMax { return protocolerrors.Errorf(true, "address count exceeded %d", addressmanager.GetAddressesMax) } - if msgAddresses.IncludeAllSubnetworks { - return protocolerrors.Errorf(true, "got unexpected "+ - "IncludeAllSubnetworks=true in [%s] command", msgAddresses.Command()) - } - if msgAddresses.SubnetworkID != nil && *msgAddresses.SubnetworkID != *context.Config().SubnetworkID { - return protocolerrors.Errorf(false, "only full nodes and %s subnetwork IDs "+ - "are allowed in [%s] command, but got subnetwork ID %s", - context.Config().SubnetworkID, msgAddresses.Command(), msgAddresses.SubnetworkID) - } - - context.AddressManager().AddAddresses(msgAddresses.AddrList...) + context.AddressManager().AddAddresses(msgAddresses.AddressList...) return nil } diff --git a/app/protocol/flows/addressexchange/sendaddresses.go b/app/protocol/flows/addressexchange/sendaddresses.go index af6cd4128..340640459 100644 --- a/app/protocol/flows/addressexchange/sendaddresses.go +++ b/app/protocol/flows/addressexchange/sendaddresses.go @@ -1,6 +1,7 @@ package addressexchange import ( + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "math/rand" "github.com/kaspanet/kaspad/app/appmessage" @@ -20,13 +21,13 @@ func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, ou return err } - msgGetAddresses := message.(*appmessage.MsgRequestAddresses) - addresses := context.AddressManager().Addresses() - msgAddresses := appmessage.NewMsgAddresses(msgGetAddresses.IncludeAllSubnetworks, msgGetAddresses.SubnetworkID) - err = msgAddresses.AddAddresses(shuffleAddresses(addresses)...) - if err != nil { - return err + _, ok := message.(*appmessage.MsgRequestAddresses) + if !ok { + return protocolerrors.Errorf(true, "unexpected message. "+ + "Expected: %s, got: %s", appmessage.CmdRequestAddresses, message.Command()) } + addresses := context.AddressManager().Addresses() + msgAddresses := appmessage.NewMsgAddresses(shuffleAddresses(addresses)) return outgoingRoute.Enqueue(msgAddresses) } diff --git a/app/protocol/peer/peer.go b/app/protocol/peer/peer.go index 5783708eb..9438beac9 100644 --- a/app/protocol/peer/peer.go +++ b/app/protocol/peer/peer.go @@ -14,6 +14,10 @@ import ( "github.com/kaspanet/kaspad/util/mstime" ) +// maxProtocolVersion version is the maximum supported protocol +// version this kaspad node supports +const maxProtocolVersion = 1 + // Peer holds data about a peer. type Peer struct { connection *netadapter.NetConnection @@ -112,9 +116,9 @@ func (p *Peer) IsOutbound() bool { func (p *Peer) UpdateFieldsFromMsgVersion(msg *appmessage.MsgVersion) { // Negotiate the protocol version. p.advertisedProtocolVerion = msg.ProtocolVersion - p.protocolVersion = mathUtil.MinUint32(p.protocolVersion, p.advertisedProtocolVerion) + p.protocolVersion = mathUtil.MinUint32(maxProtocolVersion, p.advertisedProtocolVerion) log.Debugf("Negotiated protocol version %d for peer %s", - p.protocolVersion, p.ID()) + p.protocolVersion, p) // Set the supported services for the peer to what the remote peer // advertised. diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 1c1fd7537..946fdb6bf 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -205,11 +205,6 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex if err != nil { return err } - - err = bp.dagTopologyManager.SetParents(blockHash, block.Header.ParentHashes) - if err != nil { - return err - } } // If any validation until (included) proof-of-work fails, simply diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index d2624efe9..49175ffb5 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -25,6 +25,11 @@ func (v *blockValidator) ValidateProofOfWorkAndDifficulty(blockHash *externalapi return err } + err = v.dagTopologyManager.SetParents(blockHash, header.ParentHashes) + if err != nil { + return err + } + err = v.validateDifficulty(blockHash) if err != nil { return err diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 6b98ea962..d2a6dcb04 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -1127,21 +1127,75 @@ func (*KaspadMessage_GetHeadersRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetHeadersResponse) isKaspadMessage_Payload() {} -// AddressesMessage start -type AddressesMessage struct { +// RequestAddressesMessage start +type RequestAddressesMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields IncludeAllSubnetworks bool `protobuf:"varint,1,opt,name=includeAllSubnetworks,proto3" json:"includeAllSubnetworks,omitempty"` SubnetworkID *SubnetworkID `protobuf:"bytes,2,opt,name=subnetworkID,proto3" json:"subnetworkID,omitempty"` - AddressList []*NetAddress `protobuf:"bytes,3,rep,name=addressList,proto3" json:"addressList,omitempty"` +} + +func (x *RequestAddressesMessage) Reset() { + *x = RequestAddressesMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestAddressesMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestAddressesMessage) ProtoMessage() {} + +func (x *RequestAddressesMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestAddressesMessage.ProtoReflect.Descriptor instead. +func (*RequestAddressesMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{1} +} + +func (x *RequestAddressesMessage) GetIncludeAllSubnetworks() bool { + if x != nil { + return x.IncludeAllSubnetworks + } + return false +} + +func (x *RequestAddressesMessage) GetSubnetworkID() *SubnetworkID { + if x != nil { + return x.SubnetworkID + } + return nil +} + +// AddressesMessage start +type AddressesMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressList []*NetAddress `protobuf:"bytes,1,rep,name=addressList,proto3" json:"addressList,omitempty"` } func (x *AddressesMessage) Reset() { *x = AddressesMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[1] + mi := &file_messages_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1154,7 +1208,7 @@ func (x *AddressesMessage) String() string { func (*AddressesMessage) ProtoMessage() {} func (x *AddressesMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[1] + mi := &file_messages_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1167,21 +1221,7 @@ func (x *AddressesMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddressesMessage.ProtoReflect.Descriptor instead. func (*AddressesMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{1} -} - -func (x *AddressesMessage) GetIncludeAllSubnetworks() bool { - if x != nil { - return x.IncludeAllSubnetworks - } - return false -} - -func (x *AddressesMessage) GetSubnetworkID() *SubnetworkID { - if x != nil { - return x.SubnetworkID - } - return nil + return file_messages_proto_rawDescGZIP(), []int{2} } func (x *AddressesMessage) GetAddressList() []*NetAddress { @@ -1205,7 +1245,7 @@ type NetAddress struct { func (x *NetAddress) Reset() { *x = NetAddress{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[2] + mi := &file_messages_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1218,7 +1258,7 @@ func (x *NetAddress) String() string { func (*NetAddress) ProtoMessage() {} func (x *NetAddress) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[2] + mi := &file_messages_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1231,7 +1271,7 @@ func (x *NetAddress) ProtoReflect() protoreflect.Message { // Deprecated: Use NetAddress.ProtoReflect.Descriptor instead. func (*NetAddress) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{2} + return file_messages_proto_rawDescGZIP(), []int{3} } func (x *NetAddress) GetTimestamp() int64 { @@ -1273,7 +1313,7 @@ type SubnetworkID struct { func (x *SubnetworkID) Reset() { *x = SubnetworkID{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[3] + mi := &file_messages_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1286,7 +1326,7 @@ func (x *SubnetworkID) String() string { func (*SubnetworkID) ProtoMessage() {} func (x *SubnetworkID) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[3] + mi := &file_messages_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1299,7 +1339,7 @@ func (x *SubnetworkID) ProtoReflect() protoreflect.Message { // Deprecated: Use SubnetworkID.ProtoReflect.Descriptor instead. func (*SubnetworkID) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{3} + return file_messages_proto_rawDescGZIP(), []int{4} } func (x *SubnetworkID) GetBytes() []byte { @@ -1309,62 +1349,6 @@ func (x *SubnetworkID) GetBytes() []byte { return nil } -// GetAddressesMessage start -type RequestAddressesMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IncludeAllSubnetworks bool `protobuf:"varint,1,opt,name=includeAllSubnetworks,proto3" json:"includeAllSubnetworks,omitempty"` - SubnetworkID *SubnetworkID `protobuf:"bytes,2,opt,name=subnetworkID,proto3" json:"subnetworkID,omitempty"` -} - -func (x *RequestAddressesMessage) Reset() { - *x = RequestAddressesMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestAddressesMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestAddressesMessage) ProtoMessage() {} - -func (x *RequestAddressesMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestAddressesMessage.ProtoReflect.Descriptor instead. -func (*RequestAddressesMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{4} -} - -func (x *RequestAddressesMessage) GetIncludeAllSubnetworks() bool { - if x != nil { - return x.IncludeAllSubnetworks - } - return false -} - -func (x *RequestAddressesMessage) GetSubnetworkID() *SubnetworkID { - if x != nil { - return x.SubnetworkID - } - return nil -} - // TransactionMessage start type TransactionMessage struct { state protoimpl.MessageState @@ -6780,391 +6764,539 @@ var file_messages_proto_rawDesc = []byte{ 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xbe, 0x01, 0x0a, 0x10, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x44, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, - 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8c, 0x01, - 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, - 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x22, 0xd3, 0x02, 0x0a, - 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, - 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, + 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, + 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, + 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, + 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, + 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, + 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, + 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, + 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, + 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x52, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, - 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, - 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x0d, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, - 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, - 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, + 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 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, 0x22, + 0x0a, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, + 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, + 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, + 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, + 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, + 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, + 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, + 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, + 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, + 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x22, 0x74, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, + 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, - 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, - 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, - 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, - 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, - 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, - 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, - 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, - 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, + 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, + 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, + 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, + 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, - 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, - 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, - 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, - 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x22, 0x4f, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x8d, 0x03, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, - 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, - 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, - 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, - 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, + 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, + 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, + 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x48, 0x0a, + 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, + 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x03, 0x69, + 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x4f, 0x0a, 0x12, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0f, 0x73, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0f, 0x0a, + 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8d, + 0x03, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0f, + 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, + 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, + 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, - 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, - 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 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, 0x40, 0x0a, - 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, - 0x8a, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, + 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, + 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, + 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, + 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, + 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, + 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, + 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1f, + 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, - 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, - 0x65, 0x64, 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, 0x4e, 0x0a, - 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, - 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, - 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, + 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, + 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, + 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, - 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, - 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, - 0x66, 0x65, 0x65, 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, 0x02, 0x20, - 0x01, 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, 0x22, 0x33, - 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, - 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, - 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, - 0x66, 0x6f, 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, - 0xff, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, - 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, - 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, - 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, - 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, - 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, + 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, + 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 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, 0x7b, 0x0a, + 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, + 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x1f, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x4d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x12, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, - 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x72, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x21, 0x0a, 0x1f, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, + 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xff, 0x02, 0x0a, 0x1b, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, + 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x69, + 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, + 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, + 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, + 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, + 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, + 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, + 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, + 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, + 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x1f, 0x53, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, + 0x49, 0x64, 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, 0x22, + 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, @@ -7172,289 +7304,134 @@ var file_messages_proto_rawDesc = []byte{ 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, - 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, + 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, 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, 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, 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, + 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, 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, 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, + 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, 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, + 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, + 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 ( @@ -7472,10 +7449,10 @@ func file_messages_proto_rawDescGZIP() []byte { var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 94) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage - (*AddressesMessage)(nil), // 1: protowire.AddressesMessage - (*NetAddress)(nil), // 2: protowire.NetAddress - (*SubnetworkID)(nil), // 3: protowire.SubnetworkID - (*RequestAddressesMessage)(nil), // 4: protowire.RequestAddressesMessage + (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage + (*AddressesMessage)(nil), // 2: protowire.AddressesMessage + (*NetAddress)(nil), // 3: protowire.NetAddress + (*SubnetworkID)(nil), // 4: protowire.SubnetworkID (*TransactionMessage)(nil), // 5: protowire.TransactionMessage (*TransactionInput)(nil), // 6: protowire.TransactionInput (*Outpoint)(nil), // 7: protowire.Outpoint @@ -7567,12 +7544,12 @@ var file_messages_proto_goTypes = []interface{}{ (*GetHeadersResponseMessage)(nil), // 93: protowire.GetHeadersResponseMessage } var file_messages_proto_depIdxs = []int32{ - 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage + 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage 10, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage 5, // 2: protowire.KaspadMessage.transaction:type_name -> protowire.TransactionMessage 13, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage 14, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage - 4, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage + 1, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage 15, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage 16, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage 17, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage @@ -7642,90 +7619,89 @@ var file_messages_proto_depIdxs = []int32{ 91, // 72: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage 92, // 73: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage 93, // 74: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 3, // 75: protowire.AddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID - 2, // 76: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 3, // 77: protowire.RequestAddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID - 6, // 78: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 79: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 3, // 80: protowire.TransactionMessage.subnetworkID:type_name -> protowire.SubnetworkID - 12, // 81: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 82: protowire.TransactionInput.PreviousOutpoint:type_name -> protowire.Outpoint - 8, // 83: protowire.Outpoint.transactionID:type_name -> protowire.TransactionID - 11, // 84: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 85: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 86: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 12, // 87: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 88: protowire.BlockHeaderMessage.acceptedIDMerkleRoot:type_name -> protowire.Hash - 12, // 89: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 12, // 90: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 91: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 92: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 93: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 12, // 94: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 12, // 95: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 96: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionID - 8, // 97: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionID - 12, // 98: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 99: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionID - 12, // 100: protowire.SelectedTipMessage.selectedTipHash:type_name -> protowire.Hash - 2, // 101: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 12, // 102: protowire.VersionMessage.selectedTipHash:type_name -> protowire.Hash - 3, // 103: protowire.VersionMessage.subnetworkID:type_name -> protowire.SubnetworkID - 12, // 104: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 105: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 106: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 34, // 107: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 108: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 34, // 109: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 110: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 34, // 111: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 34, // 112: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 113: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 46, // 114: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 46, // 115: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 34, // 116: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 34, // 117: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 69, // 118: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 49, // 119: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 34, // 120: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 49, // 121: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 34, // 122: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 56, // 123: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 34, // 124: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 125: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 5, // 126: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage - 34, // 127: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 34, // 128: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError - 64, // 129: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 65, // 130: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 68, // 131: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 132: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 69, // 133: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 70, // 134: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 72, // 135: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 71, // 136: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 73, // 137: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 34, // 138: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 64, // 139: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 68, // 140: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 141: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 68, // 142: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 143: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 34, // 144: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 34, // 145: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 146: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 34, // 147: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 34, // 148: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 34, // 149: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 0, // 150: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 151: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 152: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 153: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 152, // [152:154] is the sub-list for method output_type - 150, // [150:152] is the sub-list for method input_type - 150, // [150:150] is the sub-list for extension type_name - 150, // [150:150] is the sub-list for extension extendee - 0, // [0:150] is the sub-list for field type_name + 4, // 75: protowire.RequestAddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID + 3, // 76: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 6, // 77: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 78: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 4, // 79: protowire.TransactionMessage.subnetworkID:type_name -> protowire.SubnetworkID + 12, // 80: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 7, // 81: protowire.TransactionInput.PreviousOutpoint:type_name -> protowire.Outpoint + 8, // 82: protowire.Outpoint.transactionID:type_name -> protowire.TransactionID + 11, // 83: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 84: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 85: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 86: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 87: protowire.BlockHeaderMessage.acceptedIDMerkleRoot:type_name -> protowire.Hash + 12, // 88: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 89: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 90: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 91: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 92: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 93: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 94: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 95: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionID + 8, // 96: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionID + 12, // 97: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 98: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionID + 12, // 99: protowire.SelectedTipMessage.selectedTipHash:type_name -> protowire.Hash + 3, // 100: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 12, // 101: protowire.VersionMessage.selectedTipHash:type_name -> protowire.Hash + 4, // 102: protowire.VersionMessage.subnetworkID:type_name -> protowire.SubnetworkID + 12, // 103: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 104: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 105: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 34, // 106: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 107: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 34, // 108: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 109: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 34, // 110: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 34, // 111: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 112: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 46, // 113: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 46, // 114: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 34, // 115: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 34, // 116: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 69, // 117: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 49, // 118: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 34, // 119: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 49, // 120: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 34, // 121: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 56, // 122: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 34, // 123: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 124: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 5, // 125: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage + 34, // 126: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 34, // 127: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError + 64, // 128: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 65, // 129: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 68, // 130: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 131: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 69, // 132: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 70, // 133: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 72, // 134: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 71, // 135: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 73, // 136: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 34, // 137: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 64, // 138: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 68, // 139: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 140: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 68, // 141: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 142: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 34, // 143: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 34, // 144: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 145: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 34, // 146: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 34, // 147: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 34, // 148: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 0, // 149: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 150: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 151: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 152: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 151, // [151:153] is the sub-list for method output_type + 149, // [149:151] is the sub-list for method input_type + 149, // [149:149] is the sub-list for extension type_name + 149, // [149:149] is the sub-list for extension extendee + 0, // [0:149] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -7747,7 +7723,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddressesMessage); i { + switch v := v.(*RequestAddressesMessage); i { case 0: return &v.state case 1: @@ -7759,7 +7735,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NetAddress); i { + switch v := v.(*AddressesMessage); i { case 0: return &v.state case 1: @@ -7771,7 +7747,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubnetworkID); i { + switch v := v.(*NetAddress); i { case 0: return &v.state case 1: @@ -7783,7 +7759,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestAddressesMessage); i { + switch v := v.(*SubnetworkID); i { case 0: return &v.state case 1: diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 2076b6a7f..4419871ea 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -88,11 +88,16 @@ message KaspadMessage { // P2P // ///////////////////////////////////////////////////////////////////////////// -// AddressesMessage start -message AddressesMessage{ +// RequestAddressesMessage start +message RequestAddressesMessage{ bool includeAllSubnetworks = 1; SubnetworkID subnetworkID = 2; - repeated NetAddress addressList = 3; +} +// RequestAddressesMessage end + +// AddressesMessage start +message AddressesMessage{ + repeated NetAddress addressList = 1; } message NetAddress{ @@ -107,13 +112,6 @@ message SubnetworkID{ } // AddressesMessage end -// GetAddressesMessage start -message RequestAddressesMessage{ - bool includeAllSubnetworks = 1; - SubnetworkID subnetworkID = 2; -} -// GetAddressesMessage end - // TransactionMessage start message TransactionMessage{ int32 version = 1; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_addresses.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_addresses.go index 70b29347c..d2233a3c6 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_addresses.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_addresses.go @@ -12,40 +12,32 @@ func (x *KaspadMessage_Addresses) toAppMessage() (appmessage.Message, error) { "[count %d, max %d]", len(x.Addresses.AddressList), appmessage.MaxAddressesPerMsg) } - subnetworkID, err := protoAddresses.SubnetworkID.toDomain() - if err != nil { - return nil, err - } - addressList := make([]*appmessage.NetAddress, len(protoAddresses.AddressList)) for i, address := range protoAddresses.AddressList { + var err error addressList[i], err = address.toAppMessage() if err != nil { return nil, err } } return &appmessage.MsgAddresses{ - IncludeAllSubnetworks: protoAddresses.IncludeAllSubnetworks, - SubnetworkID: subnetworkID, - AddrList: addressList, + AddressList: addressList, }, nil } func (x *KaspadMessage_Addresses) fromAppMessage(msgAddresses *appmessage.MsgAddresses) error { - if len(msgAddresses.AddrList) > appmessage.MaxAddressesPerMsg { + if len(msgAddresses.AddressList) > appmessage.MaxAddressesPerMsg { return errors.Errorf("too many addresses for message "+ - "[count %d, max %d]", len(msgAddresses.AddrList), appmessage.MaxAddressesPerMsg) + "[count %d, max %d]", len(msgAddresses.AddressList), appmessage.MaxAddressesPerMsg) } - addressList := make([]*NetAddress, len(msgAddresses.AddrList)) - for i, address := range msgAddresses.AddrList { + addressList := make([]*NetAddress, len(msgAddresses.AddressList)) + for i, address := range msgAddresses.AddressList { addressList[i] = appMessageNetAddressToProto(address) } x.Addresses = &AddressesMessage{ - IncludeAllSubnetworks: msgAddresses.IncludeAllSubnetworks, - SubnetworkID: domainSubnetworkIDToProto(msgAddresses.SubnetworkID), - AddressList: addressList, + AddressList: addressList, } return nil } diff --git a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go index 9a5e4ba60..d0036b8bb 100644 --- a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go +++ b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go @@ -108,12 +108,10 @@ func (mna *MinimalNetAdapter) handleHandshake(routes *Routes, ourID *id.ID) erro if err != nil { return err } - versionMessage, ok := msg.(*appmessage.MsgVersion) if !ok { return errors.Errorf("expected first message to be of type %s, but got %s", appmessage.CmdVersion, msg.Command()) } - err = routes.OutgoingRoute.Enqueue(&appmessage.MsgVersion{ ProtocolVersion: versionMessage.ProtocolVersion, Network: mna.cfg.ActiveNetParams.Name, @@ -134,22 +132,53 @@ func (mna *MinimalNetAdapter) handleHandshake(routes *Routes, ourID *id.ID) erro if err != nil { return err } - _, ok = msg.(*appmessage.MsgVerAck) if !ok { return errors.Errorf("expected second message to be of type %s, but got %s", appmessage.CmdVerAck, msg.Command()) } - err = routes.OutgoingRoute.Enqueue(&appmessage.MsgVerAck{}) if err != nil { return err } + msg, err = routes.addressesRoute.DequeueWithTimeout(common.DefaultTimeout) + if err != nil { + return err + } + _, ok = msg.(*appmessage.MsgRequestAddresses) + if !ok { + return errors.Errorf("expected third message to be of type %s, but got %s", appmessage.CmdRequestAddresses, msg.Command()) + } + err = routes.OutgoingRoute.Enqueue(&appmessage.MsgAddresses{ + AddressList: []*appmessage.NetAddress{}, + }) + + err = routes.OutgoingRoute.Enqueue(&appmessage.MsgRequestAddresses{ + IncludeAllSubnetworks: true, + SubnetworkID: nil, + }) + if err != nil { + return err + } + msg, err = routes.addressesRoute.DequeueWithTimeout(common.DefaultTimeout) + if err != nil { + return err + } + _, ok = msg.(*appmessage.MsgAddresses) + if !ok { + return errors.Errorf("expected fourth message to be of type %s, but got %s", appmessage.CmdAddresses, msg.Command()) + } + return nil } func generateRouteInitializer() (netadapter.RouterInitializer, <-chan *Routes) { - cmdsWithBuiltInRoutes := []appmessage.MessageCommand{appmessage.CmdVerAck, appmessage.CmdVersion, appmessage.CmdPing} + cmdsWithBuiltInRoutes := []appmessage.MessageCommand{ + appmessage.CmdVersion, + appmessage.CmdVerAck, + appmessage.CmdRequestAddresses, + appmessage.CmdAddresses, + appmessage.CmdPing} everythingElse := make([]appmessage.MessageCommand, 0, len(appmessage.ProtocolMessageCommandToString)-len(cmdsWithBuiltInRoutes)) outerLoop: @@ -170,11 +199,14 @@ outerLoop: if err != nil { panic(errors.Wrap(err, "error registering handshake route")) } + addressesRoute, err := router.AddIncomingRoute([]appmessage.MessageCommand{appmessage.CmdRequestAddresses, appmessage.CmdAddresses}) + if err != nil { + panic(errors.Wrap(err, "error registering addresses route")) + } pingRoute, err := router.AddIncomingRoute([]appmessage.MessageCommand{appmessage.CmdPing}) if err != nil { panic(errors.Wrap(err, "error registering ping route")) } - everythingElseRoute, err := router.AddIncomingRoute(everythingElse) if err != nil { panic(errors.Wrap(err, "error registering everythingElseRoute")) @@ -186,6 +218,7 @@ outerLoop: OutgoingRoute: router.OutgoingRoute(), IncomingRoute: everythingElseRoute, handshakeRoute: handshakeRoute, + addressesRoute: addressesRoute, pingRoute: pingRoute, } }) diff --git a/infrastructure/network/netadapter/standalone/routes.go b/infrastructure/network/netadapter/standalone/routes.go index 28d48aa5b..d2f7d0083 100644 --- a/infrastructure/network/netadapter/standalone/routes.go +++ b/infrastructure/network/netadapter/standalone/routes.go @@ -16,6 +16,7 @@ type Routes struct { netConnection *netadapter.NetConnection IncomingRoute, OutgoingRoute *router.Route handshakeRoute *router.Route + addressesRoute *router.Route pingRoute *router.Route } From 347f3de15cfec4cb221f71e0b1ada19476068b0d Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 15 Nov 2020 07:50:30 -0800 Subject: [PATCH 031/351] [NOD-1535] fix reachability test (#1075) * [NOD-1535] Don't compare pointers * [NOD-1535] Fix condition on updateVirtualDiffParents --- .../processes/consensusstatemanager/update_virtual.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 39612880d..8b7c7b675 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -68,7 +68,7 @@ func (csm *consensusStateManager) updateVirtualDiffParents( newVirtualDiffParents := []*externalapi.DomainHash{newBlockHash} for _, virtualDiffParent := range virtualDiffParents { - if newBlockParents.Contains(virtualDiffParent) { + if !newBlockParents.Contains(virtualDiffParent) { virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { return err @@ -81,7 +81,7 @@ func (csm *consensusStateManager) updateVirtualDiffParents( if err != nil { return err } - } else { + newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } } From ae682d59f7af784d04c2aa88bc52ee2d4ee978e2 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 18:24:45 +0200 Subject: [PATCH 032/351] [NOD-1532] Fixes in updateVirtualDiffParent --- .../consensusstatemanager/update_virtual.go | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 8b7c7b675..c714a89b4 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -69,22 +69,25 @@ func (csm *consensusStateManager) updateVirtualDiffParents( newVirtualDiffParents := []*externalapi.DomainHash{newBlockHash} for _, virtualDiffParent := range virtualDiffParents { if !newBlockParents.Contains(virtualDiffParent) { - virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) - if err != nil { - return err - } - newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) - if err != nil { - return err - } - err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, newBlockHash) - if err != nil { - return err - } newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } } + + for _, virtualDiffParent := range newVirtualDiffParents { + virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) + if err != nil { + return err + } + newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) + if err != nil { + return err + } + err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil) + if err != nil { + return err + } + } } return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) From fddce00d085392a713089f1aa5a1b85ead3f7dfe Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Sun, 15 Nov 2020 18:26:15 +0200 Subject: [PATCH 033/351] [NOD-1532] Fixes in updateVirtualDiffParent --- .../consensus/processes/consensusstatemanager/update_virtual.go | 1 - 1 file changed, 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index c714a89b4..d5e1d0760 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -69,7 +69,6 @@ func (csm *consensusStateManager) updateVirtualDiffParents( newVirtualDiffParents := []*externalapi.DomainHash{newBlockHash} for _, virtualDiffParent := range virtualDiffParents { if !newBlockParents.Contains(virtualDiffParent) { - newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } } From a0c6076cccba6b62affe8cd1fbbbd21ea1d8e423 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 15 Nov 2020 08:51:31 -0800 Subject: [PATCH 034/351] [NOD-1535] Add new block to virtual diff parents only if it's valid (#1077) --- .../processes/consensusstatemanager/update_virtual.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index d5e1d0760..37b65ee96 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -66,7 +66,16 @@ func (csm *consensusStateManager) updateVirtualDiffParents( } newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) - newVirtualDiffParents := []*externalapi.DomainHash{newBlockHash} + newVirtualDiffParents := []*externalapi.DomainHash{} + status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) + if err != nil { + return err + } + + if status == externalapi.StatusValid { + newVirtualDiffParents = append(newVirtualDiffParents, newBlockHash) + } + for _, virtualDiffParent := range virtualDiffParents { if !newBlockParents.Contains(virtualDiffParent) { newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) From f4a2fbf64f1bee9b3112072296706d1aed9d8d28 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 09:18:45 +0200 Subject: [PATCH 035/351] [NOD-1532] Fixes in updateVirtualDiffParents --- .../consensusstatemanager/update_virtual.go | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 37b65ee96..10c113ab2 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -51,6 +51,15 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain func (csm *consensusStateManager) updateVirtualDiffParents( newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error { + // If the status of the new block is not `Valid` - virtualDiffParents didn't change + status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) + if err != nil { + return err + } + if status != externalapi.StatusValid { + return nil + } + var newVirtualDiffParents []*externalapi.DomainHash if *newBlockHash == *csm.genesisHash { newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} @@ -66,35 +75,26 @@ func (csm *consensusStateManager) updateVirtualDiffParents( } newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) - newVirtualDiffParents := []*externalapi.DomainHash{} - status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) - if err != nil { - return err - } - - if status == externalapi.StatusValid { - newVirtualDiffParents = append(newVirtualDiffParents, newBlockHash) - } - + newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} for _, virtualDiffParent := range virtualDiffParents { if !newBlockParents.Contains(virtualDiffParent) { newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) } } + } - for _, virtualDiffParent := range newVirtualDiffParents { - virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) - if err != nil { - return err - } - newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) - if err != nil { - return err - } - err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil) - if err != nil { - return err - } + for _, virtualDiffParent := range newVirtualDiffParents { + virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) + if err != nil { + return err + } + newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) + if err != nil { + return err + } + err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil) + if err != nil { + return err } } From 34be8984912e92f096e01a069f4c3e1d3498328e Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 10:43:30 +0200 Subject: [PATCH 036/351] [NOD-1532] utxoSetIterator should be a pointer receiver --- .../processes/consensusstatemanager/calculate_past_utxo.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index b6e14ed44..0e4058946 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -238,12 +238,12 @@ func newUTXOSetIterator(collection model.UTXOCollection) *utxoSetIterator { return &utxoSetIterator{index: 0, pairs: pairs} } -func (u utxoSetIterator) Next() bool { +func (u *utxoSetIterator) Next() bool { u.index++ return u.index < len(u.pairs) } -func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { +func (u *utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { pair := u.pairs[u.index] return &pair.outpoint, pair.entry, nil } From dc80a39c54d97acd7ac284e8a0ab7b9e62e198c8 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 10:44:04 +0200 Subject: [PATCH 037/351] [NOD-1532] OpTrueScript should also return the redeem script --- domain/consensus/test_consensus.go | 4 +++- .../consensus/utils/testutils/create_transaction.go | 5 ++--- domain/consensus/utils/testutils/op_true_script.go | 11 +++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index d36cfce53..3df3b44fc 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -38,9 +38,11 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba tc.lock.Lock() defer tc.lock.Unlock() + scriptPublicKey, _ := testutils.OpTrueScript() + if coinbaseData == nil { coinbaseData = &externalapi.DomainCoinbaseData{ - ScriptPublicKey: testutils.OpTrueScript(), + ScriptPublicKey: scriptPublicKey, ExtraData: []byte{}, } } diff --git a/domain/consensus/utils/testutils/create_transaction.go b/domain/consensus/utils/testutils/create_transaction.go index 306926258..7fa6367d3 100644 --- a/domain/consensus/utils/testutils/create_transaction.go +++ b/domain/consensus/utils/testutils/create_transaction.go @@ -11,10 +11,9 @@ import ( // Assumes that the output being spent has opTrueScript as it's scriptPublicKey // Creates the value of the spent output minus 1 sompi func CreateTransaction(txToSpend *externalapi.DomainTransaction) (*externalapi.DomainTransaction, error) { - opTrueScript := OpTrueScript() + scriptPublicKey, redeemScript := OpTrueScript() - scriptPublicKey := opTrueScript - signatureScript, err := txscript.PayToScriptHashSignatureScript(opTrueScript, nil) + signatureScript, err := txscript.PayToScriptHashSignatureScript(redeemScript, nil) if err != nil { return nil, err } diff --git a/domain/consensus/utils/testutils/op_true_script.go b/domain/consensus/utils/testutils/op_true_script.go index 394bfc018..fb111dc1d 100644 --- a/domain/consensus/utils/testutils/op_true_script.go +++ b/domain/consensus/utils/testutils/op_true_script.go @@ -5,11 +5,14 @@ import ( "github.com/pkg/errors" ) -// OpTrueScript returns a P2SH script paying to an anyone-can-spend address -func OpTrueScript() []byte { - opTrueScript, err := txscript.PayToScriptHashScript([]byte{txscript.OpTrue}) +// OpTrueScript returns a P2SH script paying to an anyone-can-spend address, +// The second return value is a redeemScript to be used with txscript.PayToScriptHashSignatureScript +func OpTrueScript() (scriptPublicKey, redeemScript []byte) { + var err error + redeemScript = []byte{txscript.OpTrue} + scriptPublicKey, err = txscript.PayToScriptHashScript(redeemScript) if err != nil { panic(errors.Wrapf(err, "Couldn't parse opTrueScript. This should never happen")) } - return opTrueScript + return scriptPublicKey, redeemScript } From 2dcfe908503d656a00017cefd622661575d93861 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 11:27:49 +0200 Subject: [PATCH 038/351] [NOD-1532] Shouldn't update parent diff if the parent is not UTXO-verified --- .../consensusstatemanager/resolve_block_status.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 398747989..373984bb2 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -119,6 +119,14 @@ func (csm *consensusStateManager) updateParentDiffs( continue } + parentStatus, err := csm.blockStatusStore.Get(csm.databaseContext, parentHash) + if err != nil { + return err + } + if parentStatus != externalapi.StatusValid { + continue + } + // parents that till now didn't have a utxo-diff child - were actually virtual's diffParents. // Update them to have the new block as their utxo-diff child parentCurrentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, parentHash) From f07f2edad274c9ff0830985449856fbf85b27fd9 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 12:00:48 +0200 Subject: [PATCH 039/351] [NOD-1532] Properly deal with selectedParentStatuses in buildBlockWithParents --- .../processes/blockbuilder/test_block_builder.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 6dc944f34..2877008a7 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" ) type testBlockBuilder struct { @@ -89,11 +90,22 @@ func (bb *testBlockBuilder) buildBlockWithParents( return nil, err } - _, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + selectedParentStatus, err := bb.testConsensus.BlockStatusStore().Get(bb.databaseContext, ghostdagData.SelectedParent) if err != nil { return nil, err } + if selectedParentStatus == externalapi.StatusUTXOPendingVerification { + selectedParentStatus, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + if err != nil { + return nil, err + } + } + if selectedParentStatus == externalapi.StatusDisqualifiedFromChain { + return nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain", + ghostdagData.SelectedParent) + } + _, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) if err != nil { return nil, err From 56679818bea9d196dd6e5c253ae1b7b400cc70f0 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 16 Nov 2020 05:17:44 -0800 Subject: [PATCH 040/351] [NOD-1535] Add non coinbase transactions to diff (#1084) --- .../calculate_past_utxo.go | 46 ++++++++++--------- .../resolve_block_status.go | 2 +- .../utxoalgebra/diff_helpers.go | 3 +- .../verify_and_build_utxo.go | 2 +- .../dagtopologymanager_external_test.go | 2 +- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 0e4058946..68badf6b5 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -135,26 +135,6 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap isAccepted bool, accumulatedMassAfter uint64, err error) { err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, accumulatedUTXODiff) - if err != nil { - return false, 0, err - } - - // Coinbase transaction outputs are added to the UTXO-set only if they are in the selected parent chain. - if transactionhelper.IsCoinBase(transaction) { - if !isSelectedParent { - return false, accumulatedMassBefore, nil - } - - err := utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore) - if err != nil { - return false, 0, err - } - - return true, accumulatedMassBefore, nil - } - - err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( - transaction, blockHash, selectedParentPastMedianTime) if err != nil { if !errors.As(err, &(ruleerrors.RuleError{})) { return false, 0, err @@ -163,9 +143,31 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap return false, accumulatedMassBefore, nil } - isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore) + // Coinbase transaction outputs are added to the UTXO-set only if they are in the selected parent chain. + if transactionhelper.IsCoinBase(transaction) { + if !isSelectedParent { + return false, accumulatedMassBefore, nil + } + } else { + err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + transaction, blockHash, selectedParentPastMedianTime) + if err != nil { + if !errors.As(err, &(ruleerrors.RuleError{})) { + return false, 0, err + } - return isAccepted, accumulatedMassAfter, nil + return false, accumulatedMassBefore, nil + } + + isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore) + } + + err = utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore) + if err != nil { + return false, 0, err + } + + return true, accumulatedMassAfter, nil } func (csm *consensusStateManager) checkTransactionMass( diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 373984bb2..25ba37ad9 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -82,7 +82,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap return 0, err } - err = csm.verifyAndBuildUTXO(block, blockHash, pastUTXODiff, acceptanceData, multiset) + err = csm.verifyUTXO(block, blockHash, pastUTXODiff, acceptanceData, multiset) if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { return externalapi.StatusDisqualifiedFromChain, nil diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go index bc3bd9272..fc7b5bd05 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go +++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go @@ -31,9 +31,10 @@ func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.Domai } isCoinbase := transactionhelper.IsCoinBase(transaction) + transactionID := *consensusserialization.TransactionID(transaction) for i, output := range transaction.Outputs { outpoint := &externalapi.DomainOutpoint{ - TransactionID: *consensusserialization.TransactionID(transaction), + TransactionID: transactionID, Index: uint32(i), } entry := &externalapi.UTXOEntry{ diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index e9d9c6156..2b7b72b20 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -18,7 +18,7 @@ import ( "github.com/pkg/errors" ) -func (csm *consensusStateManager) verifyAndBuildUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, +func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error { err := csm.validateUTXOCommitment(block, blockHash, multiset) diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go index c8ef97ab1..b060930e6 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -9,7 +9,7 @@ import ( "github.com/kaspanet/kaspad/domain/dagconfig" ) -func TestIsInPast(t *testing.T) { +func TestIsAncestorOf(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() tc, tearDown, err := factory.NewTestConsensus(params, "TestIsInPast") From fca8ed57bd8cfd69e0edab0e6a30a392ad4cbf40 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 12:29:00 +0200 Subject: [PATCH 041/351] [NOD-1532] Add another block in TestUTXOCommitment --- .../calculate_past_utxo_test.go | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index 6de504f8f..fb13ae776 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -3,6 +3,8 @@ package consensusstatemanager_test import ( "testing" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" @@ -22,8 +24,9 @@ func TestUTXOCommitment(t *testing.T) { defer teardown() // Build the following DAG: - // G <- A <- B <- D - // <- C <- + // G <- A <- B <- C <- E + // <- D <- + // Where block D has a non-coinbase transaction genesisHash := params.GenesisHash // Block A: @@ -31,43 +34,49 @@ func TestUTXOCommitment(t *testing.T) { if err != nil { t.Fatalf("Error creating block A: %+v", err) } - blockA, err := consensus.GetBlock(blockAHash) - if err != nil { - t.Fatalf("Error getting block A: %+v", err) - } // Block B: blockBHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil) if err != nil { t.Fatalf("Error creating block B: %+v", err) } - // Block C: - blockCTransaction, err := testutils.CreateTransaction(blockA.Transactions[0]) + blockB, err := consensus.GetBlock(blockBHash) if err != nil { - t.Fatalf("Error creating transaction: %+v", err) + t.Fatalf("Error getting block B: %+v", err) } - blockCHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, - []*externalapi.DomainTransaction{blockCTransaction}) + // Block C: + blockCHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, nil) if err != nil { t.Fatalf("Error creating block C: %+v", err) } // Block D: - blockDHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash, blockCHash}, nil, nil) + blockDTransaction, err := testutils.CreateTransaction( + blockB.Transactions[transactionhelper.CoinbaseTransactionIndex]) + if err != nil { + t.Fatalf("Error creating transaction: %+v", err) + } + blockDHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, + []*externalapi.DomainTransaction{blockDTransaction}) if err != nil { t.Fatalf("Error creating block D: %+v", err) } - blockD, err := consensus.GetBlock(blockDHash) + // Block E: + blockEHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockCHash, blockDHash}, nil, nil) if err != nil { - t.Fatalf("Error getting block D: %+v", err) + t.Fatalf("Error creating block E: %+v", err) + } + blockE, err := consensus.GetBlock(blockEHash) + if err != nil { + t.Fatalf("Error getting block E: %+v", err) } - // Get the past UTXO set of block D + // Get the past UTXO set of block E csm := consensus.ConsensusStateManager() - utxoSetIterator, err := csm.RestorePastUTXOSetIterator(blockDHash) + utxoSetIterator, err := csm.RestorePastUTXOSetIterator(blockEHash) if err != nil { - t.Fatalf("Error restoring past UTXO of block D: %+v", err) + t.Fatalf("Error restoring past UTXO of block E: %+v", err) } - // Build a Multiset for block D + // Build a Multiset for block E ms := multiset.New() for utxoSetIterator.Next() { outpoint, entry, err := utxoSetIterator.Get() @@ -84,10 +93,10 @@ func TestUTXOCommitment(t *testing.T) { utxoCommitment := ms.Hash() // Make sure that the two commitments are equal - if *utxoCommitment != blockD.Header.UTXOCommitment { + if *utxoCommitment != blockE.Header.UTXOCommitment { t.Fatalf("TestUTXOCommitment: calculated UTXO commitment and "+ "actual UTXO commitment don't match. Want: %s, got: %s", - utxoCommitment, blockD.Header.UTXOCommitment) + utxoCommitment, blockE.Header.UTXOCommitment) } }) } From 151910c27a35d88e02f54c930938faf870dc90dc Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 12:42:26 +0200 Subject: [PATCH 042/351] [NOD-1532] Check UTXOCommitment for all blocks --- .../calculate_past_utxo_test.go | 78 +++++++++++-------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index fb13ae776..b17697017 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -3,6 +3,8 @@ package consensusstatemanager_test import ( "testing" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" "github.com/kaspanet/kaspad/domain/consensus" @@ -34,6 +36,7 @@ func TestUTXOCommitment(t *testing.T) { 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) if err != nil { @@ -43,11 +46,13 @@ func TestUTXOCommitment(t *testing.T) { if err != nil { t.Fatalf("Error getting block B: %+v", err) } + checkBlockUTXOCommitment(t, consensus, blockBHash, "B") // Block C: blockCHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, nil) if err != nil { t.Fatalf("Error creating block C: %+v", err) } + checkBlockUTXOCommitment(t, consensus, blockCHash, "C") // Block D: blockDTransaction, err := testutils.CreateTransaction( blockB.Transactions[transactionhelper.CoinbaseTransactionIndex]) @@ -59,48 +64,53 @@ func TestUTXOCommitment(t *testing.T) { 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) if err != nil { t.Fatalf("Error creating block E: %+v", err) } - blockE, err := consensus.GetBlock(blockEHash) - if err != nil { - t.Fatalf("Error getting block E: %+v", err) - } - - // Get the past UTXO set of block E - csm := consensus.ConsensusStateManager() - utxoSetIterator, err := csm.RestorePastUTXOSetIterator(blockEHash) - if err != nil { - t.Fatalf("Error restoring past UTXO of block E: %+v", err) - } - - // Build a Multiset for block E - ms := multiset.New() - for utxoSetIterator.Next() { - outpoint, entry, err := utxoSetIterator.Get() - if err != nil { - t.Fatalf("Error getting from UTXOSet iterator: %+v", err) - } - err = consensus.ConsensusStateManager().AddUTXOToMultiset(ms, entry, outpoint) - if err != nil { - t.Fatalf("Error adding utxo to multiset: %+v", err) - } - } - - // Turn the multiset into a UTXO commitment - utxoCommitment := ms.Hash() - - // Make sure that the two commitments are equal - if *utxoCommitment != blockE.Header.UTXOCommitment { - t.Fatalf("TestUTXOCommitment: calculated UTXO commitment and "+ - "actual UTXO commitment don't match. Want: %s, got: %s", - utxoCommitment, blockE.Header.UTXOCommitment) - } + checkBlockUTXOCommitment(t, consensus, blockEHash, "E") }) } +func checkBlockUTXOCommitment(t *testing.T, consensus testapi.TestConsensus, blockHash *externalapi.DomainHash, blockName string) { + block, err := consensus.GetBlock(blockHash) + if err != nil { + t.Fatalf("Error getting block %s: %+v", blockName, err) + } + + // Get the past UTXO set of block + csm := consensus.ConsensusStateManager() + utxoSetIterator, err := csm.RestorePastUTXOSetIterator(blockHash) + if err != nil { + t.Fatalf("Error restoring past UTXO of block %s: %+v", blockName, err) + } + + // Build a Multiset + ms := multiset.New() + for utxoSetIterator.Next() { + outpoint, entry, err := utxoSetIterator.Get() + if err != nil { + t.Fatalf("Error getting from UTXOSet iterator: %+v", err) + } + err = consensus.ConsensusStateManager().AddUTXOToMultiset(ms, entry, outpoint) + if err != nil { + t.Fatalf("Error adding utxo to multiset: %+v", err) + } + } + + // Turn the multiset into a UTXO commitment + utxoCommitment := ms.Hash() + + // Make sure that the two commitments are equal + if *utxoCommitment != block.Header.UTXOCommitment { + t.Fatalf("TestUTXOCommitment: calculated UTXO commitment for block %s and "+ + "actual UTXO commitment don't match. Want: %s, got: %s", blockName, + utxoCommitment, block.Header.UTXOCommitment) + } +} + func TestPastUTXOMultiset(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() From 83a88d9989cd8fd2442520af90aedae8869a89f1 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 12:51:33 +0200 Subject: [PATCH 043/351] [NOD-1532] newUTXOSetIterator should start with -1 index --- .../processes/consensusstatemanager/calculate_past_utxo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 68badf6b5..f2b8d48ea 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -237,7 +237,7 @@ func newUTXOSetIterator(collection model.UTXOCollection) *utxoSetIterator { } i++ } - return &utxoSetIterator{index: 0, pairs: pairs} + return &utxoSetIterator{index: -1, pairs: pairs} } func (u *utxoSetIterator) Next() bool { From 08749deaeb2cf10214dd26bdc460424afe086348 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 16 Nov 2020 15:29:27 +0200 Subject: [PATCH 044/351] [NOD-1538] Fix mempool not wrapping consensus errors and bad invalid message handling (#1082) * [NOD-1538] Correct messages.proto. * [NOD-1538] Fix invalid message handling. * [NOD-1538] Fix mempool not wrapping consensus errors. * [NOD-1538] Extract wrapping logic to a separate function. * [NOD-1538] Extract wrapping logic to an even better separate function. --- app/protocol/protocol.go | 12 +- domain/miningmanager/mempool/error.go | 11 + domain/miningmanager/mempool/mempool.go | 3 + .../network/netadapter/netconnection.go | 19 +- .../server/grpcserver/connection_loops.go | 8 +- .../server/grpcserver/grpc_connection.go | 4 - .../server/grpcserver/protowire/common.go | 18 +- .../grpcserver/protowire/messages.pb.go | 779 +++++++++--------- .../grpcserver/protowire/messages.proto | 34 +- .../server/grpcserver/protowire/p2p_header.go | 4 +- .../protowire/p2p_request_addresses.go | 4 +- .../grpcserver/protowire/p2p_transaction.go | 10 +- .../grpcserver/protowire/p2p_version.go | 4 +- .../protowire/rpc_submit_transaction.go | 6 +- 14 files changed, 457 insertions(+), 459 deletions(-) diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 2f0cdc665..523018796 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -50,15 +50,9 @@ func (m *Manager) routerInitializer(router *routerpkg.Router, netConnection *net return } - spawn("Manager.routerInitializer-netConnection.DequeueInvalidMessage", func() { - for { - isOpen, err := netConnection.DequeueInvalidMessage() - if !isOpen { - return - } - if atomic.AddUint32(&isStopping, 1) == 1 { - errChan <- protocolerrors.Wrap(true, err, "received bad message") - } + netConnection.SetOnInvalidMessageHandler(func(err error) { + if atomic.AddUint32(&isStopping, 1) == 1 { + errChan <- protocolerrors.Wrap(true, err, "received bad message") } }) diff --git a/domain/miningmanager/mempool/error.go b/domain/miningmanager/mempool/error.go index c4116929a..0e7b5dc93 100644 --- a/domain/miningmanager/mempool/error.go +++ b/domain/miningmanager/mempool/error.go @@ -30,6 +30,11 @@ func (e RuleError) Error() string { return e.Err.Error() } +// Unwrap unwraps the wrapped error +func (e RuleError) Unwrap() error { + return e.Err +} + // RejectCode represents a numeric value by which a remote peer indicates // why a message was rejected. type RejectCode uint8 @@ -94,6 +99,12 @@ func txRuleError(c RejectCode, desc string) RuleError { } } +func newRuleError(err error) RuleError { + return RuleError{ + Err: err, + } +} + // extractRejectCode attempts to return a relevant reject code for a given error // by examining the error for known types. It will return true if a code // was successfully extracted. diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index bca39d265..99ebf0e1d 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -620,6 +620,9 @@ func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransac if errors.As(err, &missingOutpoints) { return missingOutpoints.MissingOutpoints, nil, nil } + if errors.As(err, &ruleerrors.RuleError{}) { + return nil, nil, newRuleError(err) + } return nil, nil, err } diff --git a/infrastructure/network/netadapter/netconnection.go b/infrastructure/network/netadapter/netconnection.go index 6b553aa43..c3809d71b 100644 --- a/infrastructure/network/netadapter/netconnection.go +++ b/infrastructure/network/netadapter/netconnection.go @@ -16,7 +16,6 @@ type NetConnection struct { connection server.Connection id *id.ID router *routerpkg.Router - invalidMessageChan chan error onDisconnectedHandler server.OnDisconnectedHandler isRouterClosed uint32 } @@ -25,9 +24,8 @@ func newNetConnection(connection server.Connection, routerInitializer RouterInit router := routerpkg.NewRouter() netConnection := &NetConnection{ - connection: connection, - router: router, - invalidMessageChan: make(chan error), + connection: connection, + router: router, } netConnection.connection.SetOnDisconnectedHandler(func() { @@ -36,15 +34,9 @@ func newNetConnection(connection server.Connection, routerInitializer RouterInit if atomic.AddUint32(&netConnection.isRouterClosed, 1) == 1 { netConnection.router.Close() } - - close(netConnection.invalidMessageChan) netConnection.onDisconnectedHandler() }) - netConnection.connection.SetOnInvalidMessageHandler(func(err error) { - netConnection.invalidMessageChan <- err - }) - routerInitializer(router, netConnection) return netConnection @@ -98,8 +90,7 @@ func (c *NetConnection) Disconnect() { } } -// DequeueInvalidMessage dequeues the next invalid message -func (c *NetConnection) DequeueInvalidMessage() (isOpen bool, err error) { - err, isOpen = <-c.invalidMessageChan - return isOpen, err +// SetOnInvalidMessageHandler sets the invalid message handler for this connection +func (c *NetConnection) SetOnInvalidMessageHandler(onInvalidMessageHandler server.OnInvalidMessageHandler) { + c.connection.SetOnInvalidMessageHandler(onInvalidMessageHandler) } diff --git a/infrastructure/network/netadapter/server/grpcserver/connection_loops.go b/infrastructure/network/netadapter/server/grpcserver/connection_loops.go index e10111eb8..d55a8da65 100644 --- a/infrastructure/network/netadapter/server/grpcserver/connection_loops.go +++ b/infrastructure/network/netadapter/server/grpcserver/connection_loops.go @@ -67,7 +67,9 @@ func (c *gRPCConnection) receiveLoop() error { } message, err := protoMessage.ToAppMessage() if err != nil { - c.onInvalidMessageHandler(err) + if c.onInvalidMessageHandler != nil { + c.onInvalidMessageHandler(err) + } return err } @@ -88,7 +90,9 @@ func (c *gRPCConnection) receiveLoop() error { if errors.Is(err, routerpkg.ErrRouteClosed) { return nil } - c.onInvalidMessageHandler(err) + if c.onInvalidMessageHandler != nil { + c.onInvalidMessageHandler(err) + } return err } } diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go b/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go index 006dec285..19bee44a8 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go @@ -58,10 +58,6 @@ func (c *gRPCConnection) Start(router *router.Router) { panic(errors.New("onDisconnectedHandler is nil")) } - if c.onInvalidMessageHandler == nil { - panic(errors.New("onInvalidMessageHandler is nil")) - } - c.router = router spawn("gRPCConnection.Start-connectionLoops", func() { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/common.go b/infrastructure/network/netadapter/server/grpcserver/protowire/common.go index b8572a43a..d48dee029 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/common.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/common.go @@ -42,11 +42,11 @@ func domainHashesToProto(hashes []*externalapi.DomainHash) []*Hash { return protoHashes } -func (x *TransactionID) toDomain() (*externalapi.DomainTransactionID, error) { +func (x *TransactionId) toDomain() (*externalapi.DomainTransactionID, error) { return transactionid.FromBytes(x.Bytes) } -func protoTransactionIDsToDomain(protoIDs []*TransactionID) ([]*externalapi.DomainTransactionID, error) { +func protoTransactionIDsToDomain(protoIDs []*TransactionId) ([]*externalapi.DomainTransactionID, error) { txIDs := make([]*externalapi.DomainTransactionID, len(protoIDs)) for i, protoID := range protoIDs { var err error @@ -58,32 +58,32 @@ func protoTransactionIDsToDomain(protoIDs []*TransactionID) ([]*externalapi.Doma return txIDs, nil } -func domainTransactionIDToProto(id *externalapi.DomainTransactionID) *TransactionID { - return &TransactionID{ +func domainTransactionIDToProto(id *externalapi.DomainTransactionID) *TransactionId { + return &TransactionId{ Bytes: id[:], } } -func wireTransactionIDsToProto(ids []*externalapi.DomainTransactionID) []*TransactionID { - protoIDs := make([]*TransactionID, len(ids)) +func wireTransactionIDsToProto(ids []*externalapi.DomainTransactionID) []*TransactionId { + protoIDs := make([]*TransactionId, len(ids)) for i, hash := range ids { protoIDs[i] = domainTransactionIDToProto(hash) } return protoIDs } -func (x *SubnetworkID) toDomain() (*externalapi.DomainSubnetworkID, error) { +func (x *SubnetworkId) toDomain() (*externalapi.DomainSubnetworkID, error) { if x == nil { return nil, nil } return subnetworks.FromBytes(x.Bytes) } -func domainSubnetworkIDToProto(id *externalapi.DomainSubnetworkID) *SubnetworkID { +func domainSubnetworkIDToProto(id *externalapi.DomainSubnetworkID) *SubnetworkId { if id == nil { return nil } - return &SubnetworkID{ + return &SubnetworkId{ Bytes: id[:], } } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index d2a6dcb04..119e90c62 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -1134,7 +1134,7 @@ type RequestAddressesMessage struct { unknownFields protoimpl.UnknownFields IncludeAllSubnetworks bool `protobuf:"varint,1,opt,name=includeAllSubnetworks,proto3" json:"includeAllSubnetworks,omitempty"` - SubnetworkID *SubnetworkID `protobuf:"bytes,2,opt,name=subnetworkID,proto3" json:"subnetworkID,omitempty"` + SubnetworkId *SubnetworkId `protobuf:"bytes,2,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` } func (x *RequestAddressesMessage) Reset() { @@ -1176,9 +1176,9 @@ func (x *RequestAddressesMessage) GetIncludeAllSubnetworks() bool { return false } -func (x *RequestAddressesMessage) GetSubnetworkID() *SubnetworkID { +func (x *RequestAddressesMessage) GetSubnetworkId() *SubnetworkId { if x != nil { - return x.SubnetworkID + return x.SubnetworkId } return nil } @@ -1302,7 +1302,7 @@ func (x *NetAddress) GetPort() uint32 { return 0 } -type SubnetworkID struct { +type SubnetworkId struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1310,8 +1310,8 @@ type SubnetworkID struct { Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` } -func (x *SubnetworkID) Reset() { - *x = SubnetworkID{} +func (x *SubnetworkId) Reset() { + *x = SubnetworkId{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1319,13 +1319,13 @@ func (x *SubnetworkID) Reset() { } } -func (x *SubnetworkID) String() string { +func (x *SubnetworkId) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SubnetworkID) ProtoMessage() {} +func (*SubnetworkId) ProtoMessage() {} -func (x *SubnetworkID) ProtoReflect() protoreflect.Message { +func (x *SubnetworkId) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1337,12 +1337,12 @@ func (x *SubnetworkID) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SubnetworkID.ProtoReflect.Descriptor instead. -func (*SubnetworkID) Descriptor() ([]byte, []int) { +// Deprecated: Use SubnetworkId.ProtoReflect.Descriptor instead. +func (*SubnetworkId) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{4} } -func (x *SubnetworkID) GetBytes() []byte { +func (x *SubnetworkId) GetBytes() []byte { if x != nil { return x.Bytes } @@ -1359,10 +1359,10 @@ type TransactionMessage struct { Inputs []*TransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` Outputs []*TransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` - SubnetworkID *SubnetworkID `protobuf:"bytes,5,opt,name=subnetworkID,proto3" json:"subnetworkID,omitempty"` + SubnetworkId *SubnetworkId `protobuf:"bytes,5,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"` PayloadHash *Hash `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` - Payload []byte `protobuf:"bytes,8,opt,name=Payload,proto3" json:"Payload,omitempty"` + Payload []byte `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` } func (x *TransactionMessage) Reset() { @@ -1425,9 +1425,9 @@ func (x *TransactionMessage) GetLockTime() uint64 { return 0 } -func (x *TransactionMessage) GetSubnetworkID() *SubnetworkID { +func (x *TransactionMessage) GetSubnetworkId() *SubnetworkId { if x != nil { - return x.SubnetworkID + return x.SubnetworkId } return nil } @@ -1458,9 +1458,9 @@ type TransactionInput struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PreviousOutpoint *Outpoint `protobuf:"bytes,1,opt,name=PreviousOutpoint,proto3" json:"PreviousOutpoint,omitempty"` - SignatureScript []byte `protobuf:"bytes,2,opt,name=SignatureScript,proto3" json:"SignatureScript,omitempty"` - Sequence uint64 `protobuf:"varint,3,opt,name=Sequence,proto3" json:"Sequence,omitempty"` + PreviousOutpoint *Outpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` + SignatureScript []byte `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` + Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` } func (x *TransactionInput) Reset() { @@ -1521,7 +1521,7 @@ type Outpoint struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TransactionID *TransactionID `protobuf:"bytes,1,opt,name=transactionID,proto3" json:"transactionID,omitempty"` + TransactionId *TransactionId `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` } @@ -1557,9 +1557,9 @@ func (*Outpoint) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{7} } -func (x *Outpoint) GetTransactionID() *TransactionID { +func (x *Outpoint) GetTransactionId() *TransactionId { if x != nil { - return x.TransactionID + return x.TransactionId } return nil } @@ -1571,7 +1571,7 @@ func (x *Outpoint) GetIndex() uint32 { return 0 } -type TransactionID struct { +type TransactionId struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1579,8 +1579,8 @@ type TransactionID struct { Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` } -func (x *TransactionID) Reset() { - *x = TransactionID{} +func (x *TransactionId) Reset() { + *x = TransactionId{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1588,13 +1588,13 @@ func (x *TransactionID) Reset() { } } -func (x *TransactionID) String() string { +func (x *TransactionId) String() string { return protoimpl.X.MessageStringOf(x) } -func (*TransactionID) ProtoMessage() {} +func (*TransactionId) ProtoMessage() {} -func (x *TransactionID) ProtoReflect() protoreflect.Message { +func (x *TransactionId) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1606,12 +1606,12 @@ func (x *TransactionID) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use TransactionID.ProtoReflect.Descriptor instead. -func (*TransactionID) Descriptor() ([]byte, []int) { +// Deprecated: Use TransactionId.ProtoReflect.Descriptor instead. +func (*TransactionId) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{8} } -func (x *TransactionID) GetBytes() []byte { +func (x *TransactionId) GetBytes() []byte { if x != nil { return x.Bytes } @@ -1624,7 +1624,7 @@ type TransactionOutput struct { unknownFields protoimpl.UnknownFields Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - ScriptPubKey []byte `protobuf:"bytes,2,opt,name=ScriptPubKey,proto3" json:"ScriptPubKey,omitempty"` + ScriptPubKey []byte `protobuf:"bytes,2,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` } func (x *TransactionOutput) Reset() { @@ -1737,7 +1737,7 @@ type BlockHeaderMessage struct { Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` ParentHashes []*Hash `protobuf:"bytes,2,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` HashMerkleRoot *Hash `protobuf:"bytes,3,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` - AcceptedIDMerkleRoot *Hash `protobuf:"bytes,4,opt,name=acceptedIDMerkleRoot,proto3" json:"acceptedIDMerkleRoot,omitempty"` + AcceptedIdMerkleRoot *Hash `protobuf:"bytes,4,opt,name=acceptedIdMerkleRoot,proto3" json:"acceptedIdMerkleRoot,omitempty"` UtxoCommitment *Hash `protobuf:"bytes,5,opt,name=utxoCommitment,proto3" json:"utxoCommitment,omitempty"` Timestamp int64 `protobuf:"varint,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Bits uint32 `protobuf:"varint,7,opt,name=bits,proto3" json:"bits,omitempty"` @@ -1797,9 +1797,9 @@ func (x *BlockHeaderMessage) GetHashMerkleRoot() *Hash { return nil } -func (x *BlockHeaderMessage) GetAcceptedIDMerkleRoot() *Hash { +func (x *BlockHeaderMessage) GetAcceptedIdMerkleRoot() *Hash { if x != nil { - return x.AcceptedIDMerkleRoot + return x.AcceptedIdMerkleRoot } return nil } @@ -2210,7 +2210,7 @@ type RequestTransactionsMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Ids []*TransactionID `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` + Ids []*TransactionId `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` } func (x *RequestTransactionsMessage) Reset() { @@ -2245,7 +2245,7 @@ func (*RequestTransactionsMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{20} } -func (x *RequestTransactionsMessage) GetIds() []*TransactionID { +func (x *RequestTransactionsMessage) GetIds() []*TransactionId { if x != nil { return x.Ids } @@ -2258,7 +2258,7 @@ type TransactionNotFoundMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id *TransactionID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Id *TransactionId `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` } func (x *TransactionNotFoundMessage) Reset() { @@ -2293,7 +2293,7 @@ func (*TransactionNotFoundMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{21} } -func (x *TransactionNotFoundMessage) GetId() *TransactionID { +func (x *TransactionNotFoundMessage) GetId() *TransactionId { if x != nil { return x.Id } @@ -2354,7 +2354,7 @@ type InvTransactionsMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Ids []*TransactionID `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` + Ids []*TransactionId `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` } func (x *InvTransactionsMessage) Reset() { @@ -2389,7 +2389,7 @@ func (*InvTransactionsMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{23} } -func (x *InvTransactionsMessage) GetIds() []*TransactionID { +func (x *InvTransactionsMessage) GetIds() []*TransactionId { if x != nil { return x.Ids } @@ -2593,7 +2593,7 @@ type VersionMessage struct { UserAgent string `protobuf:"bytes,6,opt,name=userAgent,proto3" json:"userAgent,omitempty"` SelectedTipHash *Hash `protobuf:"bytes,7,opt,name=selectedTipHash,proto3" json:"selectedTipHash,omitempty"` DisableRelayTx bool `protobuf:"varint,8,opt,name=disableRelayTx,proto3" json:"disableRelayTx,omitempty"` - SubnetworkID *SubnetworkID `protobuf:"bytes,9,opt,name=subnetworkID,proto3" json:"subnetworkID,omitempty"` + SubnetworkId *SubnetworkId `protobuf:"bytes,9,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` Network string `protobuf:"bytes,10,opt,name=network,proto3" json:"network,omitempty"` } @@ -2685,9 +2685,9 @@ func (x *VersionMessage) GetDisableRelayTx() bool { return false } -func (x *VersionMessage) GetSubnetworkID() *SubnetworkID { +func (x *VersionMessage) GetSubnetworkId() *SubnetworkId { if x != nil { - return x.SubnetworkID + return x.SubnetworkId } return nil } @@ -4217,7 +4217,7 @@ type SubmitTransactionRequestMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TransactionMessage *TransactionMessage `protobuf:"bytes,1,opt,name=transactionMessage,proto3" json:"transactionMessage,omitempty"` + Transaction *TransactionMessage `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` } func (x *SubmitTransactionRequestMessage) Reset() { @@ -4252,9 +4252,9 @@ func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{59} } -func (x *SubmitTransactionRequestMessage) GetTransactionMessage() *TransactionMessage { +func (x *SubmitTransactionRequestMessage) GetTransaction() *TransactionMessage { if x != nil { - return x.TransactionMessage + return x.Transaction } return nil } @@ -6770,10 +6770,10 @@ var file_messages_proto_rawDesc = []byte{ 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, @@ -6786,7 +6786,7 @@ var file_messages_proto_rawDesc = []byte{ 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, @@ -6800,38 +6800,38 @@ var file_messages_proto_rawDesc = []byte{ 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, - 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x12, + 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, + 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x52, 0x10, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x53, + 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, + 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, - 0x0a, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, + 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, @@ -6851,10 +6851,10 @@ var file_messages_proto_rawDesc = []byte{ 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, @@ -6897,11 +6897,11 @@ var file_messages_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x44, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, @@ -6909,7 +6909,7 @@ var file_messages_proto_rawDesc = []byte{ 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x03, 0x69, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, @@ -6941,10 +6941,10 @@ var file_messages_proto_rawDesc = []byte{ 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x44, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, @@ -7118,320 +7118,319 @@ var file_messages_proto_rawDesc = []byte{ 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, 0x1f, 0x53, 0x75, 0x62, 0x6d, + 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x62, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, - 0x49, 0x64, 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, 0x22, - 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x20, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x78, 0x49, 0x64, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, + 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, 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, + 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, 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, + 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, 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, 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, 0x43, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73, + 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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 ( @@ -7452,11 +7451,11 @@ var file_messages_proto_goTypes = []interface{}{ (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage (*AddressesMessage)(nil), // 2: protowire.AddressesMessage (*NetAddress)(nil), // 3: protowire.NetAddress - (*SubnetworkID)(nil), // 4: protowire.SubnetworkID + (*SubnetworkId)(nil), // 4: protowire.SubnetworkId (*TransactionMessage)(nil), // 5: protowire.TransactionMessage (*TransactionInput)(nil), // 6: protowire.TransactionInput (*Outpoint)(nil), // 7: protowire.Outpoint - (*TransactionID)(nil), // 8: protowire.TransactionID + (*TransactionId)(nil), // 8: protowire.TransactionId (*TransactionOutput)(nil), // 9: protowire.TransactionOutput (*BlockMessage)(nil), // 10: protowire.BlockMessage (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage @@ -7619,19 +7618,19 @@ var file_messages_proto_depIdxs = []int32{ 91, // 72: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage 92, // 73: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage 93, // 74: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 4, // 75: protowire.RequestAddressesMessage.subnetworkID:type_name -> protowire.SubnetworkID + 4, // 75: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId 3, // 76: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress 6, // 77: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput 9, // 78: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 4, // 79: protowire.TransactionMessage.subnetworkID:type_name -> protowire.SubnetworkID + 4, // 79: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId 12, // 80: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 81: protowire.TransactionInput.PreviousOutpoint:type_name -> protowire.Outpoint - 8, // 82: protowire.Outpoint.transactionID:type_name -> protowire.TransactionID + 7, // 81: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint + 8, // 82: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId 11, // 83: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage 5, // 84: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage 12, // 85: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash 12, // 86: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 87: protowire.BlockHeaderMessage.acceptedIDMerkleRoot:type_name -> protowire.Hash + 12, // 87: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash 12, // 88: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash 12, // 89: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash 12, // 90: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash @@ -7639,14 +7638,14 @@ var file_messages_proto_depIdxs = []int32{ 12, // 92: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash 12, // 93: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash 12, // 94: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 95: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionID - 8, // 96: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionID + 8, // 95: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 8, // 96: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId 12, // 97: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 98: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionID + 8, // 98: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId 12, // 99: protowire.SelectedTipMessage.selectedTipHash:type_name -> protowire.Hash 3, // 100: protowire.VersionMessage.address:type_name -> protowire.NetAddress 12, // 101: protowire.VersionMessage.selectedTipHash:type_name -> protowire.Hash - 4, // 102: protowire.VersionMessage.subnetworkID:type_name -> protowire.SubnetworkID + 4, // 102: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId 12, // 103: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash 10, // 104: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage 12, // 105: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash @@ -7669,7 +7668,7 @@ var file_messages_proto_depIdxs = []int32{ 56, // 122: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage 34, // 123: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError 34, // 124: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 5, // 125: protowire.SubmitTransactionRequestMessage.transactionMessage:type_name -> protowire.TransactionMessage + 5, // 125: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.TransactionMessage 34, // 126: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError 34, // 127: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError 64, // 128: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock @@ -7759,7 +7758,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubnetworkID); i { + switch v := v.(*SubnetworkId); i { case 0: return &v.state case 1: @@ -7807,7 +7806,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionID); i { + switch v := v.(*TransactionId); i { case 0: return &v.state case 1: diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 4419871ea..ed296bfa0 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -91,7 +91,7 @@ message KaspadMessage { // RequestAddressesMessage start message RequestAddressesMessage{ bool includeAllSubnetworks = 1; - SubnetworkID subnetworkID = 2; + SubnetworkId subnetworkId = 2; } // RequestAddressesMessage end @@ -101,13 +101,13 @@ message AddressesMessage{ } message NetAddress{ - int64 timestamp = 1; + int64 timestamp = 1; uint64 services = 2; bytes ip = 3; uint32 port = 4; } -message SubnetworkID{ +message SubnetworkId{ bytes bytes = 1; } // AddressesMessage end @@ -118,30 +118,30 @@ message TransactionMessage{ repeated TransactionInput inputs = 2; repeated TransactionOutput outputs = 3; uint64 lockTime = 4; - SubnetworkID subnetworkID = 5; + SubnetworkId subnetworkId = 5; uint64 gas = 6; Hash payloadHash = 7; - bytes Payload = 8; + bytes payload = 8; } message TransactionInput{ - Outpoint PreviousOutpoint = 1; - bytes SignatureScript = 2; - uint64 Sequence = 3; + Outpoint previousOutpoint = 1; + bytes signatureScript = 2; + uint64 sequence = 3; } message Outpoint{ - TransactionID transactionID = 1; + TransactionId transactionId = 1; uint32 index = 2; } -message TransactionID{ +message TransactionId{ bytes bytes = 1; } message TransactionOutput{ uint64 value = 1; - bytes ScriptPubKey = 2; + bytes scriptPubKey = 2; } // TransactionMessage end @@ -155,7 +155,7 @@ message BlockHeaderMessage{ int32 version = 1; repeated Hash parentHashes = 2; Hash hashMerkleRoot = 3; - Hash acceptedIDMerkleRoot = 4; + Hash acceptedIdMerkleRoot = 4; Hash utxoCommitment = 5; int64 timestamp = 6; uint32 bits = 7; @@ -210,13 +210,13 @@ message RequestSelectedTipMessage{ // RequestTransactionsMessage start message RequestTransactionsMessage { - repeated TransactionID ids = 1; + repeated TransactionId ids = 1; } // GetTransactionsMessage end // TransactionNotFoundMessage start message TransactionNotFoundMessage{ - TransactionID id = 1; + TransactionId id = 1; } // TransactionsNotFoundMessage end @@ -228,7 +228,7 @@ message InvRelayBlockMessage{ // InvTransactionMessage start message InvTransactionsMessage{ - repeated TransactionID ids = 1; + repeated TransactionId ids = 1; } // InvTransactionMessage end @@ -265,7 +265,7 @@ message VersionMessage{ string userAgent = 6; Hash selectedTipHash = 7; bool disableRelayTx = 8; - SubnetworkID subnetworkID = 9; + SubnetworkId subnetworkId = 9; string network = 10; } // VersionMessage end @@ -427,7 +427,7 @@ message AddPeerResponseMessage{ } message SubmitTransactionRequestMessage{ - TransactionMessage transactionMessage = 1; + TransactionMessage transaction = 1; } message SubmitTransactionResponseMessage{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go index b95d5644d..6de033e1d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go @@ -31,7 +31,7 @@ func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) return nil, err } - acceptedIDMerkleRoot, err := x.AcceptedIDMerkleRoot.toDomain() + acceptedIDMerkleRoot, err := x.AcceptedIdMerkleRoot.toDomain() if err != nil { return nil, err } @@ -63,7 +63,7 @@ func (x *BlockHeaderMessage) fromAppMessage(msgBlockHeader *appmessage.MsgBlockH Version: msgBlockHeader.Version, ParentHashes: domainHashesToProto(msgBlockHeader.ParentHashes), HashMerkleRoot: domainHashToProto(msgBlockHeader.HashMerkleRoot), - AcceptedIDMerkleRoot: domainHashToProto(msgBlockHeader.AcceptedIDMerkleRoot), + AcceptedIdMerkleRoot: domainHashToProto(msgBlockHeader.AcceptedIDMerkleRoot), UtxoCommitment: domainHashToProto(msgBlockHeader.UTXOCommitment), Timestamp: msgBlockHeader.Timestamp.UnixMilliseconds(), Bits: msgBlockHeader.Bits, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_addresses.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_addresses.go index 294308341..0350ee0b2 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_addresses.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_addresses.go @@ -6,7 +6,7 @@ import ( func (x *KaspadMessage_RequestAddresses) toAppMessage() (appmessage.Message, error) { protoGetAddresses := x.RequestAddresses - subnetworkID, err := protoGetAddresses.SubnetworkID.toDomain() + subnetworkID, err := protoGetAddresses.SubnetworkId.toDomain() if err != nil { return nil, err } @@ -20,7 +20,7 @@ func (x *KaspadMessage_RequestAddresses) toAppMessage() (appmessage.Message, err func (x *KaspadMessage_RequestAddresses) fromAppMessage(msgGetAddresses *appmessage.MsgRequestAddresses) error { x.RequestAddresses = &RequestAddressesMessage{ IncludeAllSubnetworks: msgGetAddresses.IncludeAllSubnetworks, - SubnetworkID: domainSubnetworkIDToProto(msgGetAddresses.SubnetworkID), + SubnetworkId: domainSubnetworkIDToProto(msgGetAddresses.SubnetworkID), } return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go index 09353f68c..c2fb5a4c7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go @@ -19,7 +19,7 @@ func (x *KaspadMessage_Transaction) fromAppMessage(msgTx *appmessage.MsgTx) erro func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { inputs := make([]*appmessage.TxIn, len(x.Inputs)) for i, protoInput := range x.Inputs { - prevTxID, err := protoInput.PreviousOutpoint.TransactionID.toDomain() + prevTxID, err := protoInput.PreviousOutpoint.TransactionId.toDomain() if err != nil { return nil, err } @@ -36,11 +36,11 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { } } - if x.SubnetworkID == nil { + if x.SubnetworkId == nil { return nil, errors.New("transaction subnetwork field cannot be nil") } - subnetworkID, err := x.SubnetworkID.toDomain() + subnetworkID, err := x.SubnetworkId.toDomain() if err != nil { return nil, err } @@ -70,7 +70,7 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { for i, input := range msgTx.TxIn { protoInputs[i] = &TransactionInput{ PreviousOutpoint: &Outpoint{ - TransactionID: domainTransactionIDToProto(&input.PreviousOutpoint.TxID), + TransactionId: domainTransactionIDToProto(&input.PreviousOutpoint.TxID), Index: input.PreviousOutpoint.Index, }, SignatureScript: input.SignatureScript, @@ -91,7 +91,7 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { Inputs: protoInputs, Outputs: protoOutputs, LockTime: msgTx.LockTime, - SubnetworkID: domainSubnetworkIDToProto(&msgTx.SubnetworkID), + SubnetworkId: domainSubnetworkIDToProto(&msgTx.SubnetworkID), Gas: msgTx.Gas, PayloadHash: domainHashToProto(&msgTx.PayloadHash), Payload: msgTx.Payload, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go index b49942806..2cffe5465 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go @@ -22,7 +22,7 @@ func (x *KaspadMessage_Version) toAppMessage() (appmessage.Message, error) { return nil, err } - subnetworkID, err := x.Version.SubnetworkID.toDomain() + subnetworkID, err := x.Version.SubnetworkId.toDomain() if err != nil { return nil, err } @@ -73,7 +73,7 @@ func (x *KaspadMessage_Version) fromAppMessage(msgVersion *appmessage.MsgVersion UserAgent: msgVersion.UserAgent, SelectedTipHash: domainHashToProto(msgVersion.SelectedTipHash), DisableRelayTx: msgVersion.DisableRelayTx, - SubnetworkID: domainSubnetworkIDToProto(msgVersion.SubnetworkID), + SubnetworkId: domainSubnetworkIDToProto(msgVersion.SubnetworkID), } return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go index 31de19129..89a9bc440 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go @@ -3,7 +3,7 @@ package protowire import "github.com/kaspanet/kaspad/app/appmessage" func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) { - msgTx, err := x.SubmitTransactionRequest.TransactionMessage.toAppMessage() + msgTx, err := x.SubmitTransactionRequest.Transaction.toAppMessage() if err != nil { return nil, err } @@ -14,9 +14,9 @@ func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Mess func (x *KaspadMessage_SubmitTransactionRequest) fromAppMessage(message *appmessage.SubmitTransactionRequestMessage) error { x.SubmitTransactionRequest = &SubmitTransactionRequestMessage{ - TransactionMessage: &TransactionMessage{}, + Transaction: &TransactionMessage{}, } - x.SubmitTransactionRequest.TransactionMessage.fromAppMessage(message.Transaction) + x.SubmitTransactionRequest.Transaction.fromAppMessage(message.Transaction) return nil } From d8f72e2b27bab86e8e6a7face03dced556cbbd1f Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 15:58:05 +0200 Subject: [PATCH 045/351] [NOD-1532] Update VirtualUTXODiffParents diffs even if list didn't change --- .../calculate_past_utxo.go | 17 +++++----- .../consensusstatemanager/update_virtual.go | 32 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index f2b8d48ea..7cbef09cb 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -1,10 +1,9 @@ package consensusstatemanager import ( - "errors" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" + "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -186,7 +185,7 @@ func (csm *consensusStateManager) checkTransactionMass( } func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (model.ReadOnlyUTXOSetIterator, error) { - diff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) + blockDiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) if err != nil { return nil, err } @@ -196,25 +195,25 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external return nil, err } - pastUTXO := model.NewUTXODiff() + virtualUTXO := model.NewUTXODiff() for virtualUTXOSetIterator.Next() { outpoint, utxoEntry, err := virtualUTXOSetIterator.Get() if err != nil { return nil, err } - pastUTXO.ToAdd[*outpoint] = utxoEntry + virtualUTXO.ToAdd[*outpoint] = utxoEntry } - diff, err = utxoalgebra.WithDiff(pastUTXO, diff) + blockUTXO, err := utxoalgebra.WithDiff(virtualUTXO, blockDiff) if err != nil { return nil, err } - if len(diff.ToRemove) > 0 { - return nil, errors.New("diff.ToRemove is expected to be empty") + if len(blockUTXO.ToRemove) > 0 { + return nil, errors.New("blockUTXO.ToRemove is expected to be empty") } - return newUTXOSetIterator(diff.ToAdd), nil + return newUTXOSetIterator(blockUTXO.ToAdd), nil } type utxoOutpointEntryPair struct { diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 10c113ab2..fb0df7df4 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -51,34 +51,34 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain func (csm *consensusStateManager) updateVirtualDiffParents( newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error { - // If the status of the new block is not `Valid` - virtualDiffParents didn't change - status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) - if err != nil { - return err - } - if status != externalapi.StatusValid { - return nil - } - var newVirtualDiffParents []*externalapi.DomainHash if *newBlockHash == *csm.genesisHash { newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} } else { - virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { return err } - newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) + // If the status of the new block is not `Valid` - virtualDiffParents didn't change + status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) if err != nil { return err } - newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) + if status != externalapi.StatusValid { + newVirtualDiffParents = oldVirtualDiffParents + } else { + newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) + if err != nil { + return err + } + newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) - newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} - for _, virtualDiffParent := range virtualDiffParents { - if !newBlockParents.Contains(virtualDiffParent) { - newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) + newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} + for _, virtualDiffParent := range oldVirtualDiffParents { + if !newBlockParents.Contains(virtualDiffParent) { + newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) + } } } } From e6a2b7366f1a00a60fcad77ed545f3b89dd52aae Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 16 Nov 2020 07:02:03 -0800 Subject: [PATCH 046/351] [NOD-1535] Don't use pointer to outpoint when serializing (#1086) --- domain/consensus/database/serialization/utxo_collection.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain/consensus/database/serialization/utxo_collection.go b/domain/consensus/database/serialization/utxo_collection.go index c8030ea15..81e51496c 100644 --- a/domain/consensus/database/serialization/utxo_collection.go +++ b/domain/consensus/database/serialization/utxo_collection.go @@ -8,8 +8,9 @@ func utxoCollectionToDBUTXOCollection(utxoCollection model.UTXOCollection) []*Db items := make([]*DbUtxoCollectionItem, len(utxoCollection)) i := 0 for outpoint, entry := range utxoCollection { + outpointCopy := outpoint items[i] = &DbUtxoCollectionItem{ - Outpoint: DomainOutpointToDbOutpoint(&outpoint), + Outpoint: DomainOutpointToDbOutpoint(&outpointCopy), UtxoEntry: UTXOEntryToDBUTXOEntry(entry), } i++ From b6c47fdd2159ab35ee474a330d1f952cabc2d0db Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 16 Nov 2020 07:22:12 -0800 Subject: [PATCH 047/351] [NOD-1535] fix reachability tests (#1087) * [NOD-1535] Don't use pointer to outpoint when serializing * [NOD-1535] Fix reachability tests --- .../reachability_external_test.go | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index cdd97593c..de8123ba9 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -9,7 +9,7 @@ import ( ) func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *testing.T) { - reachabilityReindexWindow := uint64(2) + reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() tc, tearDown, err := factory.NewTestConsensus(params, "TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot") @@ -51,7 +51,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t t.Fatalf("ReachabilityReindexRoot: %s", err) } - if *newReindexRoot != *reindexRoot { + if *newReindexRoot == *reindexRoot { t.Fatalf("reindex root is expected to change") } @@ -64,7 +64,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t } func TestUpdateReindexRoot(t *testing.T) { - reachabilityReindexWindow := uint64(2) + reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") @@ -95,13 +95,15 @@ func TestUpdateReindexRoot(t *testing.T) { } // Make two chains of size reachabilityReindexWindow and check that the reindex root is not changed. + chain1Tip, chain2Tip := chain1RootBlock, chain2RootBlock for i := uint64(0); i < reachabilityReindexWindow-1; i++ { - _, err := tc.AddBlock([]*externalapi.DomainHash{chain1RootBlock}, nil, nil) + var err error + chain1Tip, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil) if err != nil { t.Fatalf("AddBlock: %+v", err) } - _, err = tc.AddBlock([]*externalapi.DomainHash{chain2RootBlock}, nil, nil) + chain2Tip, err = tc.AddBlock([]*externalapi.DomainHash{chain2Tip}, nil, nil) if err != nil { t.Fatalf("AddBlock: %+v", err) } @@ -117,7 +119,7 @@ func TestUpdateReindexRoot(t *testing.T) { } // Add another block over chain1. This will move the reindex root to chain1RootBlock - _, err = tc.AddBlock([]*externalapi.DomainHash{chain1RootBlock}, nil, nil) + _, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil) if err != nil { t.Fatalf("AddBlock: %+v", err) } @@ -143,7 +145,7 @@ func TestUpdateReindexRoot(t *testing.T) { // Make sure that the rest of the interval has been allocated to // chain1RootNode, minus slack from both sides expectedChain1RootIntervalSize := intervalSize(params.GenesisHash) - 1 - - intervalSize(chain2RootBlock) - 2*reachabilityReindexWindow + intervalSize(chain2RootBlock) - 2*tc.ReachabilityManager().ReachabilityReindexSlack() if intervalSize(chain1RootBlock) != expectedChain1RootIntervalSize { t.Fatalf("got unexpected chain1RootBlock interval. Want: %d, got: %d", intervalSize(chain1RootBlock), expectedChain1RootIntervalSize) @@ -152,7 +154,7 @@ func TestUpdateReindexRoot(t *testing.T) { } func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { - reachabilityReindexWindow := uint64(2) + reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") @@ -286,7 +288,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { } func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) { - reachabilityReindexWindow := uint64(2) + reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") From 310cf0bb9b2958091977f196f35cf106a8b00c87 Mon Sep 17 00:00:00 2001 From: stasatdaglabs Date: Mon, 16 Nov 2020 16:53:11 +0200 Subject: [PATCH 048/351] [NOD-1538] Remove bad check in selectPeerForIBD. --- app/protocol/flowcontext/ibd.go | 32 ++++++++----------- .../blockprocessor/validateandinsertblock.go | 12 +++++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/protocol/flowcontext/ibd.go b/app/protocol/flowcontext/ibd.go index e81f14109..fd2a038ba 100644 --- a/app/protocol/flowcontext/ibd.go +++ b/app/protocol/flowcontext/ibd.go @@ -56,28 +56,24 @@ func (f *FlowContext) selectPeerForIBD(syncInfo *externalapi.SyncInfo) (*peerpkg f.peersMutex.RLock() defer f.peersMutex.RUnlock() - if syncInfo.State == externalapi.SyncStateHeadersFirst { - for _, peer := range f.peers { - peerSelectedTipHash := peer.SelectedTipHash() - blockInfo, err := f.domain.Consensus().GetBlockInfo(peerSelectedTipHash) - if err != nil { - return nil, err - } + for _, peer := range f.peers { + peerSelectedTipHash := peer.SelectedTipHash() + blockInfo, err := f.domain.Consensus().GetBlockInfo(peerSelectedTipHash) + if err != nil { + return nil, err + } - if syncInfo.State == externalapi.SyncStateHeadersFirst { - if !blockInfo.Exists { - return peer, nil - } - } else { - if blockInfo.Exists && blockInfo.BlockStatus == externalapi.StatusHeaderOnly && - blockInfo.IsBlockInHeaderPruningPointFuture { - return peer, nil - } + if syncInfo.State == externalapi.SyncStateHeadersFirst { + if !blockInfo.Exists { + return peer, nil + } + } else { + if blockInfo.Exists && blockInfo.BlockStatus == externalapi.StatusHeaderOnly && + blockInfo.IsBlockInHeaderPruningPointFuture { + return peer, nil } } - return nil, nil } - return nil, nil } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 946fdb6bf..01971331e 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -8,6 +8,9 @@ import ( ) func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error { + hash := consensusserialization.HeaderHash(block.Header) + log.Debugf("Validating block %s", hash) + syncInfo, err := bp.syncManager.GetSyncInfo() if err != nil { return err @@ -17,7 +20,6 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) syncInfo.State = externalapi.SyncStateHeadersFirst } - hash := consensusserialization.HeaderHash(block.Header) if syncInfo.State == externalapi.SyncStateMissingUTXOSet { if isHeaderOnlyBlock(block) { // Allow processing headers while in state SyncStateMissingUTXOSet @@ -147,7 +149,13 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } } - return bp.commitAllChanges() + err = bp.commitAllChanges() + if err != nil { + return err + } + + log.Debugf("Block %s validated and inserted", hash) + return nil } func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error { From 48d8137604e16bb2b6c710915cbcbbbcd519a841 Mon Sep 17 00:00:00 2001 From: stasatdaglabs Date: Mon, 16 Nov 2020 17:18:23 +0200 Subject: [PATCH 049/351] [NOD-1538] Implement GetBlockCount. --- app/rpc/rpchandlers/get_block_count.go | 7 +++++-- .../blockheaderstore/blockheaderstore.go | 12 ++++++++++++ .../datastructures/blockstore/blockstore.go | 12 ++++++++++++ domain/consensus/factory.go | 3 ++- domain/consensus/model/externalapi/sync.go | 2 ++ ...terface_datastructures_blockheaderstore.go | 1 + .../interface_datastructures_blockstore.go | 1 + .../processes/syncmanager/syncinfo.go | 19 +++++++++++++++++++ .../processes/syncmanager/syncmanager.go | 5 ++++- 9 files changed, 58 insertions(+), 4 deletions(-) diff --git a/app/rpc/rpchandlers/get_block_count.go b/app/rpc/rpchandlers/get_block_count.go index 5988c5342..24b6d353b 100644 --- a/app/rpc/rpchandlers/get_block_count.go +++ b/app/rpc/rpchandlers/get_block_count.go @@ -8,7 +8,10 @@ import ( // HandleGetBlockCount handles the respectively named RPC command func HandleGetBlockCount(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { - response := &appmessage.GetBlockCountResponseMessage{} - response.Error = appmessage.RPCErrorf("not implemented") + syncInfo, err := context.Domain.Consensus().GetSyncInfo() + if err != nil { + return nil, err + } + response := appmessage.NewGetBlockCountResponseMessage(syncInfo.BlockCount) return response, nil } diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index 4fb6ffa47..3869ed443 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -143,3 +143,15 @@ func (bms *blockHeaderStore) cloneHeader(header *externalapi.DomainBlockHeader) return bms.deserializeHeader(serialized) } + +func (bms *blockHeaderStore) Count(dbContext model.DBReader) (uint64, error) { + cursor, err := dbContext.Cursor(bucket) + if err != nil { + return 0, err + } + count := uint64(0) + for cursor.Next() { + count++ + } + return count, nil +} diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index 84fedbb54..e7619c6cd 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -143,3 +143,15 @@ func (bms *blockStore) clone(block *externalapi.DomainBlock) (*externalapi.Domai return bms.deserializeBlock(serialized) } + +func (bms *blockStore) Count(dbContext model.DBReader) (uint64, error) { + cursor, err := dbContext.Cursor(bucket) + if err != nil { + return 0, err + } + count := uint64(0) + for cursor.Next() { + count++ + } + return count, nil +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 44fd76f48..3bd7883c2 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -209,7 +209,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore, blockStatusStore, blockHeaderStore, - headerTipsStore) + headerTipsStore, + blockStore) blockBuilder := blockbuilder.New( dbManager, diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index e57905c05..4bf942fa2 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -36,4 +36,6 @@ func (s SyncState) String() string { type SyncInfo struct { State SyncState IBDRootUTXOBlockHash *DomainHash + HeaderCount uint64 + BlockCount uint64 } diff --git a/domain/consensus/model/interface_datastructures_blockheaderstore.go b/domain/consensus/model/interface_datastructures_blockheaderstore.go index 6b98f815c..adbe97b5d 100644 --- a/domain/consensus/model/interface_datastructures_blockheaderstore.go +++ b/domain/consensus/model/interface_datastructures_blockheaderstore.go @@ -11,4 +11,5 @@ type BlockHeaderStore interface { HasBlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) BlockHeaders(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) Delete(blockHash *externalapi.DomainHash) + Count(dbContext DBReader) (uint64, error) } diff --git a/domain/consensus/model/interface_datastructures_blockstore.go b/domain/consensus/model/interface_datastructures_blockstore.go index 0eaead6a0..4c36ed3be 100644 --- a/domain/consensus/model/interface_datastructures_blockstore.go +++ b/domain/consensus/model/interface_datastructures_blockstore.go @@ -11,4 +11,5 @@ type BlockStore interface { HasBlock(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) Blocks(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlock, error) Delete(blockHash *externalapi.DomainHash) + Count(dbContext DBReader) (uint64, error) } diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 42c732d01..02990d9af 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -25,9 +25,20 @@ func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { } } + headerCount, err := sm.getHeaderCount() + if err != nil { + return nil, err + } + blockCount, err := sm.getBlockCount() + if err != nil { + return nil, err + } + return &externalapi.SyncInfo{ State: syncState, IBDRootUTXOBlockHash: ibdRootUTXOBlockHash, + HeaderCount: headerCount, + BlockCount: blockCount, }, nil } @@ -111,3 +122,11 @@ func (sm *syncManager) areHeaderTipsSynced(headerVirtualSelectedParentHash *exte return timeDifference <= maxTimeDifference, nil } + +func (sm *syncManager) getHeaderCount() (uint64, error) { + return sm.blockHeaderStore.Count(sm.databaseContext) +} + +func (sm *syncManager) getBlockCount() (uint64, error) { + return sm.blockStore.Count(sm.databaseContext) +} diff --git a/domain/consensus/processes/syncmanager/syncmanager.go b/domain/consensus/processes/syncmanager/syncmanager.go index bed6329ef..5c206c408 100644 --- a/domain/consensus/processes/syncmanager/syncmanager.go +++ b/domain/consensus/processes/syncmanager/syncmanager.go @@ -20,6 +20,7 @@ type syncManager struct { blockStatusStore model.BlockStatusStore blockHeaderStore model.BlockHeaderStore headerTipsStore model.HeaderTipsStore + blockStore model.BlockStore } // New instantiates a new SyncManager @@ -35,7 +36,8 @@ func New( ghostdagDataStore model.GHOSTDAGDataStore, blockStatusStore model.BlockStatusStore, blockHeaderStore model.BlockHeaderStore, - headerTipsStore model.HeaderTipsStore) model.SyncManager { + headerTipsStore model.HeaderTipsStore, + blockStore model.BlockStore) model.SyncManager { return &syncManager{ databaseContext: databaseContext, @@ -51,6 +53,7 @@ func New( blockStatusStore: blockStatusStore, blockHeaderStore: blockHeaderStore, headerTipsStore: headerTipsStore, + blockStore: blockStore, } } From f2df48139fb2f3ddde2e325597801e4c2b466d35 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 16 Nov 2020 18:05:35 +0200 Subject: [PATCH 050/351] [NOD-1532] Remove virtual from ParentChildren when checking for virtualSelectedParent candidates (#1089) * [NOD-1532] Remove virtual from ParentChildren when checking for virtualSelectedParent candidates * [NOD-1532] Fix minor issues --- .../consensusstatemanager/pick_virtual_parents.go | 8 ++++++++ .../consensusstatemanager/resolve_block_status_test.go | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index e15981a02..8707618f3 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -83,6 +83,14 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod return nil, err } + // remove virtual from parentChildren if it's there + for i, parentChild := range parentChildren { + if *parentChild == *model.VirtualBlockHash { + parentChildren = append(parentChildren[:i], parentChildren[i+1:]...) + break + } + } + if disqualifiedCandidates.ContainsAllInSlice(parentChildren) { err := candidatesHeap.Push(parent) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 868f72b55..b7b8d9e64 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -122,7 +122,7 @@ func TestDoubleSpends(t *testing.T) { // Add a block on top of goodBlock, containing spendingTransaction1 twice, and make // sure AddBlock returns a RuleError _, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil, - []*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2}) + []*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction1}) if err == nil { t.Fatalf("No error when adding a block containing the same transactin twice") } From 7050ebeac9cc6171dc1bb013f9f2f927612b401b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 16 Nov 2020 23:39:11 -0800 Subject: [PATCH 051/351] [NOD-1541] Add TestPastMedianTime (#1091) --- .../blockbuilder/test_block_builder.go | 9 +++ .../pastmediantimemanager_test.go | 79 +++++++++++++++++++ domain/consensus/test_consensus.go | 11 --- 3 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 2877008a7..1f9cb5c78 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" ) @@ -75,6 +76,14 @@ func (bb *testBlockBuilder) buildBlockWithParents( defer bb.testConsensus.DiscardAllStores() + if coinbaseData == nil { + scriptPublicKey, _ := testutils.OpTrueScript() + coinbaseData = &externalapi.DomainCoinbaseData{ + ScriptPublicKey: scriptPublicKey, + ExtraData: []byte{}, + } + } + err := bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) if err != nil { return nil, err diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go new file mode 100644 index 000000000..c335a0d07 --- /dev/null +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -0,0 +1,79 @@ +package pastmediantimemanager_test + +import ( + "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 TestPastMedianTime(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown() + + numBlocks := uint32(300) + blockHashes := make([]*externalapi.DomainHash, numBlocks) + blockHashes[0] = params.GenesisHash + blockTime := params.GenesisBlock.Header.TimeInMilliseconds + for i := uint32(1); i < numBlocks; i++ { + blockTime += 1000 + block, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{blockHashes[i-1]}, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %s", err) + } + + block.Header.TimeInMilliseconds = blockTime + blockHash, err := tc.SolveAndAddBlock(block) + if err != nil { + t.Fatalf("SolveAndAddBlock: %s", err) + } + + blockHashes[i] = blockHash + } + + tests := []struct { + blockNumber uint32 + expectedMillisecondsSinceGenesis int64 + }{ + { + blockNumber: 263, + expectedMillisecondsSinceGenesis: 130000, + }, + { + blockNumber: 271, + expectedMillisecondsSinceGenesis: 138000, + }, + { + blockNumber: 241, + expectedMillisecondsSinceGenesis: 108000, + }, + { + blockNumber: 5, + expectedMillisecondsSinceGenesis: 0, + }, + } + + for _, test := range tests { + pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(blockHashes[test.blockNumber]) + if err != nil { + t.Fatalf("PastMedianTime: %s", err) + } + + millisecondsSinceGenesis := pastMedianTime - + params.GenesisBlock.Header.TimeInMilliseconds + + if millisecondsSinceGenesis != test.expectedMillisecondsSinceGenesis { + t.Errorf("TestCalcPastMedianTime: expected past median time of block %v to be %v milliseconds "+ + "from genesis but got %v", + test.blockNumber, test.expectedMillisecondsSinceGenesis, millisecondsSinceGenesis) + } + } + }) + +} diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 3df3b44fc..67d4be494 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -6,8 +6,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/mining" - "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) @@ -38,15 +36,6 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba tc.lock.Lock() defer tc.lock.Unlock() - scriptPublicKey, _ := testutils.OpTrueScript() - - if coinbaseData == nil { - coinbaseData = &externalapi.DomainCoinbaseData{ - ScriptPublicKey: scriptPublicKey, - ExtraData: []byte{}, - } - } - block, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) if err != nil { return nil, err From c994200878089bc3c8657eeaecda90434b6e892e Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 18:11:34 +0200 Subject: [PATCH 052/351] [NOD-1532] ResolveBlockStatus should return the blockStatus --- .../consensusstatemanager/resolve_block_status.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 25ba37ad9..32332a336 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -15,11 +15,17 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma return 0, err } + // If there's no unverified blocks in the given block's chain - this means the given block already has a + // UTXO-verified status, and therefore it should be retrieved from the store and returned + if len(unverifiedBlocks) == 0 { + return csm.blockStatusStore.Get(csm.databaseContext, blockHash) + } + + var blockStatus externalapi.BlockStatus // resolve the unverified blocks' statuses in opposite order for i := len(unverifiedBlocks) - 1; i >= 0; i-- { unverifiedBlockHash := unverifiedBlocks[i] - var blockStatus externalapi.BlockStatus if selectedParentStatus == externalapi.StatusDisqualifiedFromChain { blockStatus = externalapi.StatusDisqualifiedFromChain } else { @@ -33,7 +39,7 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma selectedParentStatus = blockStatus } - return 0, nil + return blockStatus, nil } func (csm *consensusStateManager) getUnverifiedChainBlocksAndSelectedParentStatus(blockHash *externalapi.DomainHash) ( From 66f5a5bd7dac793318933b26d0086584fcbe0c52 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 16 Nov 2020 18:14:17 +0200 Subject: [PATCH 053/351] [NOD-1532] Genesis is not violating finality by definition --- domain/consensus/processes/consensusstatemanager/finality.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go index e6a94f430..bc9729414 100644 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ b/domain/consensus/processes/consensusstatemanager/finality.go @@ -8,6 +8,10 @@ import ( func (csm *consensusStateManager) checkFinalityViolation( blockHash *externalapi.DomainHash) error { + if *blockHash == *csm.genesisHash { + return nil + } + isViolatingFinality, err := csm.isViolatingFinality(blockHash) if err != nil { return err From dbd15aecf5214687e04b2a8743ccc25029488cb8 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Tue, 17 Nov 2020 11:23:31 +0200 Subject: [PATCH 054/351] [NOD-1532] Invert condition in isViolatingFinality --- .../consensusstatemanager/finality.go | 22 +++++++++++------- .../pick_virtual_parents.go | 12 +++++----- .../dagtraversalmanager.go | 23 ++++++++----------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go index bc9729414..c63bd449a 100644 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ b/domain/consensus/processes/consensusstatemanager/finality.go @@ -25,30 +25,36 @@ func (csm *consensusStateManager) checkFinalityViolation( return nil } -func (csm *consensusStateManager) virtualFinalityPoint(virtualGHOSTDAGData *model.BlockGHOSTDAGData) ( +func (csm *consensusStateManager) virtualFinalityPoint() ( *externalapi.DomainHash, error) { - blueScore := virtualGHOSTDAGData.BlueScore - csm.finalityDepth + virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + + finalityPointBlueScore := virtualGHOSTDAGData.BlueScore - csm.finalityDepth if virtualGHOSTDAGData.BlueScore < csm.finalityDepth { - blueScore = 0 + // if there's no `csm.finalityDepth` blocks in the DAG + // practically - returns the genesis + finalityPointBlueScore = 0 } return csm.dagTraversalManager.HighestChainBlockBelowBlueScore( - model.VirtualBlockHash, blueScore) + model.VirtualBlockHash, finalityPointBlueScore) } func (csm *consensusStateManager) isViolatingFinality( blockHash *externalapi.DomainHash) (bool, error) { - virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) + virtualFinalityPoint, err := csm.virtualFinalityPoint() if err != nil { return false, err } - virtualFinalityPoint, err := csm.virtualFinalityPoint(virtualGHOSTDAGData) + isInSelectedParentChain, err := csm.dagTopologyManager.IsInSelectedParentChainOf(virtualFinalityPoint, blockHash) if err != nil { return false, err } - - return csm.dagTopologyManager.IsInSelectedParentChainOf(virtualFinalityPoint, blockHash) + return !isInSelectedParentChain, nil } diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 8707618f3..3e123ef26 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -160,17 +160,17 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa return nil, err } - virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - - virtualFinalityPoint, err := csm.virtualFinalityPoint(virtualGHOSTDAGData) + virtualFinalityPoint, err := csm.virtualFinalityPoint() if err != nil { return nil, err } badReds := []*externalapi.DomainHash{} + + virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } for _, redBlock := range virtualGHOSTDAGData.MergeSetReds { isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock) if err != nil { diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index a83c955eb..1379c8263 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -2,6 +2,7 @@ package dagtraversalmanager import ( "fmt" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) @@ -65,27 +66,23 @@ func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.Dom // HighestChainBlockBelowBlueScore returns the hash of the // highest block with a blue score lower than the given -// blueScore in the block with the given highHash's selected -// parent chain -func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) { +// blueScore in the selected-parent-chain of the block +// with the given highHash's selected parent chain +func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, requiredBlueScore uint64) (*externalapi.DomainHash, error) { currentBlockHash := highHash - chainBlock, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash) + highBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash) if err != nil { return nil, err } - if chainBlock.BlueScore < blueScore { // will practically return genesis. - blueScore = chainBlock.BlueScore - } - - requiredBlueScore := chainBlock.BlueScore - blueScore + currentBlockGHOSTDAGData := highBlockGHOSTDAGData // If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore - for chainBlock.BlueScore >= requiredBlueScore { - if chainBlock.SelectedParent == nil { // genesis + for currentBlockGHOSTDAGData.BlueScore >= requiredBlueScore { + if currentBlockGHOSTDAGData.SelectedParent == nil { // genesis return currentBlockHash, nil } - currentBlockHash = chainBlock.SelectedParent - chainBlock, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash) + currentBlockHash = currentBlockGHOSTDAGData.SelectedParent + currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash) if err != nil { return nil, err } From b2188f5993305fb54883475b1bcc580a6d15699c Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Tue, 17 Nov 2020 11:47:12 +0200 Subject: [PATCH 055/351] [NOD-1532] AlwaysCallResolveBlockStatus in BuildBlock + Fixes to make it work if there's nothing to resolve --- .../blockbuilder/test_block_builder.go | 8 ++- .../resolve_block_status.go | 50 +++++++++++++------ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 1f9cb5c78..57204c2d7 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -104,11 +104,9 @@ func (bb *testBlockBuilder) buildBlockWithParents( return nil, err } - if selectedParentStatus == externalapi.StatusUTXOPendingVerification { - selectedParentStatus, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) - if err != nil { - return nil, err - } + selectedParentStatus, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + if err != nil { + return nil, err } if selectedParentStatus == externalapi.StatusDisqualifiedFromChain { return nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain", diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 32332a336..ea2a8152d 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -10,7 +10,7 @@ import ( func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { // get list of all blocks in the selected parent chain that have not yet resolved their status - unverifiedBlocks, selectedParentStatus, err := csm.getUnverifiedChainBlocksAndSelectedParentStatus(blockHash) + unverifiedBlocks, err := csm.getUnverifiedChainBlocks(blockHash) if err != nil { return 0, err } @@ -21,6 +21,11 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma return csm.blockStatusStore.Get(csm.databaseContext, blockHash) } + selectedParentStatus, err := csm.findSelectedParentStatus(unverifiedBlocks) + if err != nil { + return 0, err + } + var blockStatus externalapi.BlockStatus // resolve the unverified blocks' statuses in opposite order for i := len(unverifiedBlocks) - 1; i >= 0; i-- { @@ -42,33 +47,46 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma return blockStatus, nil } -func (csm *consensusStateManager) getUnverifiedChainBlocksAndSelectedParentStatus(blockHash *externalapi.DomainHash) ( - []*externalapi.DomainHash, externalapi.BlockStatus, error) { +// findSelectedParentStatus returns the status of the selectedParent of the last block in the unverifiedBlocks chain +func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*externalapi.DomainHash) ( + externalapi.BlockStatus, error) { + lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1] + if *lastUnverifiedBlock == *csm.genesisHash { + return externalapi.StatusValid, nil + } + lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, lastUnverifiedBlock) + if err != nil { + return 0, err + } + return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent) +} - unverifiedBlocks := []*externalapi.DomainHash{blockHash} +func (csm *consensusStateManager) getUnverifiedChainBlocks( + blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + + unverifiedBlocks := []*externalapi.DomainHash{} currentHash := blockHash for { - ghostdagData, err := csm.ghostdagDataStore.Get(csm.databaseContext, currentHash) + currentBlockStatus, err := csm.blockStatusStore.Get(csm.databaseContext, currentHash) if err != nil { - return nil, 0, err + return nil, err + } + if currentBlockStatus != externalapi.StatusUTXOPendingVerification { + return unverifiedBlocks, nil } - if ghostdagData.SelectedParent == nil { - return unverifiedBlocks, externalapi.StatusValid, nil - } + unverifiedBlocks = append(unverifiedBlocks, currentHash) - selectedParentStatus, err := csm.blockStatusStore.Get(csm.databaseContext, ghostdagData.SelectedParent) + currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, currentHash) if err != nil { - return nil, 0, err + return nil, err } - if selectedParentStatus != externalapi.StatusUTXOPendingVerification { - return unverifiedBlocks, selectedParentStatus, nil + if currentBlockGHOSTDAGData.SelectedParent == nil { + return unverifiedBlocks, nil // this means we reached genesis } - unverifiedBlocks = append(unverifiedBlocks, ghostdagData.SelectedParent) - - currentHash = ghostdagData.SelectedParent + currentHash = currentBlockGHOSTDAGData.SelectedParent } } From 7224d5894043c1db8f8d1aa9c8fdc7537f5c9752 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Tue, 17 Nov 2020 11:59:11 +0200 Subject: [PATCH 056/351] [NOD-1532] Add comments --- .../consensus/model/interface_processes_reachabilitytree.go | 1 + .../consensusstatemanager/test_consensus_state_manager.go | 1 + .../reachabilitymanager/test_reachabilitymanager.go | 1 + domain/consensus/utils/mining/solve.go | 6 ++++-- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/domain/consensus/model/interface_processes_reachabilitytree.go b/domain/consensus/model/interface_processes_reachabilitytree.go index 75c9ee372..f151d08c1 100644 --- a/domain/consensus/model/interface_processes_reachabilitytree.go +++ b/domain/consensus/model/interface_processes_reachabilitytree.go @@ -11,6 +11,7 @@ type ReachabilityManager interface { UpdateReindexRoot(selectedTip *externalapi.DomainHash) error } +// TestReachabilityManager adds to the main ReachabilityManager methods required by tests type TestReachabilityManager interface { ReachabilityManager SetReachabilityReindexWindow(reindexWindow uint64) diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go index 9f1aba398..93750f161 100644 --- a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -9,6 +9,7 @@ type testConsensusStateManager struct { *consensusStateManager } +// NewTestConsensusStateManager creates an instance of a TestConsensusStateManager func NewTestConsensusStateManager(baseConsensusStateManager model.ConsensusStateManager) model.TestConsensusStateManager { return &testConsensusStateManager{consensusStateManager: baseConsensusStateManager.(*consensusStateManager)} } diff --git a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go index 2b41d1852..057794fb9 100644 --- a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go @@ -18,6 +18,7 @@ func (t testReachabilityManager) SetReachabilityReindexWindow(reindexWindow uint t.reachabilityManager.reindexWindow = reindexWindow } +// NewTestReachabilityManager creates an instance of a TestReachabilityManager func NewTestReachabilityManager(manager model.ReachabilityManager) model.TestReachabilityManager { return &testReachabilityManager{reachabilityManager: manager.(*reachabilityManager)} } diff --git a/domain/consensus/utils/mining/solve.go b/domain/consensus/utils/mining/solve.go index 3bffe95c3..844e3475b 100644 --- a/domain/consensus/utils/mining/solve.go +++ b/domain/consensus/utils/mining/solve.go @@ -1,15 +1,17 @@ package mining import ( + "math" + "math/rand" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" utilsMath "github.com/kaspanet/kaspad/domain/consensus/utils/math" "github.com/pkg/errors" - "math" - "math/rand" ) +// SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) { targetDifficulty := utilsMath.CompactToBig(block.Header.Bits) From 14d7ab5fc60a9b596f9299df82ce5609369dd595 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 17 Nov 2020 02:52:27 -0800 Subject: [PATCH 057/351] Add TestBigToCompact and TestCompactToBig (#1092) * Add TestBigToCompact and TestCompactToBig * Add tests --- domain/consensus/utils/math/math_test.go | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/domain/consensus/utils/math/math_test.go b/domain/consensus/utils/math/math_test.go index b5a3e2a6a..ddefea4f0 100644 --- a/domain/consensus/utils/math/math_test.go +++ b/domain/consensus/utils/math/math_test.go @@ -1,6 +1,8 @@ package math import ( + "math" + "math/big" "testing" ) @@ -33,3 +35,60 @@ func TestFastLog2Floor(t *testing.T) { } } } + +// TestBigToCompact ensures BigToCompact converts big integers to the expected +// compact representation. +func TestBigToCompact(t *testing.T) { + tests := []struct { + in string + out uint32 + }{ + {"0", 0}, + {"-1", 25231360}, + {"9223372036854775807", 142606335}, + {"922337203685477580712312312123487", 237861256}, + } + + for x, test := range tests { + n := new(big.Int) + n.SetString(test.in, 10) + r := BigToCompact(n) + if r != test.out { + t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n", + x, r, test.out) + return + } + } +} + +// TestCompactToBig ensures CompactToBig converts numbers using the compact +// representation to the expected big integers. +func TestCompactToBig(t *testing.T) { + tests := []struct { + in uint32 + out string + }{ + {0, "0"}, + {10000000, "0"}, + {math.MaxUint32, "-6311914495863998658485429352026283268468573753812676234178171506285465200675957" + + "87397376951158770808349115367298981082112562162319027637583517246275967980671962038665775867893645140" + + "22856089959012026469381002722748489975264028415685723882208353467651862351803217528553851158828320170" + + "89832330727351553686808317476632783024236208492771822246700842318520468733521003756809213629548010354" + + "33865968377930773213939300289069292503211567790599147939718451689002543278625341832829837474611074167" + + "86700705915281593002614032021233542099318559748885883681365573294332856023451874423425211080847063825" + + "199113186681992371681311588352", + }, + {142606335, "9223370937343148032"}, + {25231360, "-1"}, + {237861256, "922337129789886856855791696084992"}, + } + + for i, test := range tests { + n := CompactToBig(test.in) + if n.String() != test.out { + t.Errorf("TestCompactToBig test #%d failed: got %s want %s", + i, n, test.out) + return + } + } +} From 213be67c47c24bd9cb9c85dd0f20f36a232c2e58 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 17 Nov 2020 13:21:37 +0200 Subject: [PATCH 058/351] [NOD-1538] Fix isBlockInHeaderPruningPointFuture. (#1094) --- .../processes/consensusstatemanager/set_pruning_utxo_set.go | 6 +++++- domain/consensus/processes/syncmanager/antipast.go | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 6b633d854..74926f69d 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -161,5 +161,9 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH return nil, err } - return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(virtualHeaderHash, virtualHeaderGHOSTDAGData.BlueScore-csm.pruningDepth) + blueScore := virtualHeaderGHOSTDAGData.BlueScore - csm.pruningDepth + if csm.pruningDepth > virtualHeaderGHOSTDAGData.BlueScore { + blueScore = 0 + } + return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(virtualHeaderHash, blueScore) } diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 1f4da7a7a..973b9efbf 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -188,6 +188,10 @@ func (sm *syncManager) isHeaderOnlyBlock(blockHash *externalapi.DomainHash) (boo } 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 From 9d5d1b02dc2c01bb590e49c0fa54e78ab532d6b6 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 17 Nov 2020 14:44:34 +0200 Subject: [PATCH 059/351] [NOD-1538] Implement a simple orphan pool (#1093) * [NOD-1538] Implement a simple orphan pool. * [NOD-1538] Connect the orphan pool to the appropriate flows. * [NOD-1538] Make UnorphanBlocks actually unorphan blocks. * [NOD-1538] Fix logs. * [NOD-1538] Make unorphaned blocks call LogBlock. * [NOD-1538] Fix a log and some bad names. * [NOD-1538] Don't return an error from LogBlock. * [NOD-1538] Pass a pointer to hash in findChildOrphansOfBlock. * [NOD-1538] Extract addChildOrphansToProcessQueue to a separate function. --- app/protocol/blocklogger/blocklogger.go | 5 +- app/protocol/flowcontext/blocks.go | 17 ++- app/protocol/flowcontext/flow_context.go | 4 + app/protocol/flowcontext/orphans.go | 111 ++++++++++++++++++ .../flows/blockrelay/handle_relay_invs.go | 4 + 5 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 app/protocol/flowcontext/orphans.go diff --git a/app/protocol/blocklogger/blocklogger.go b/app/protocol/blocklogger/blocklogger.go index bcc467293..81713aba5 100644 --- a/app/protocol/blocklogger/blocklogger.go +++ b/app/protocol/blocklogger/blocklogger.go @@ -22,7 +22,7 @@ var ( // LogBlock logs a new block blue score as an information message // to show progress to the user. In order to prevent spam, it limits logging to // one message every 10 seconds with duration and totals included. -func LogBlock(block *externalapi.DomainBlock) error { +func LogBlock(block *externalapi.DomainBlock) { mtx.Lock() defer mtx.Unlock() @@ -32,7 +32,7 @@ func LogBlock(block *externalapi.DomainBlock) error { now := mstime.Now() duration := now.Sub(lastBlockLogTime) if duration < time.Second*10 { - return nil + return } // Truncate the duration to 10s of milliseconds. @@ -55,5 +55,4 @@ func LogBlock(block *externalapi.DomainBlock) error { receivedLogBlocks = 0 receivedLogTx = 0 lastBlockLogTime = now - return nil } diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index aeeb48360..7f5036d4a 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -15,17 +15,22 @@ import ( // relays newly unorphaned transactions and possibly rebroadcast // manually added transactions when not in IBD. func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { - err := blocklogger.LogBlock(block) + unorphanedBlocks, err := f.UnorphanBlocks(block) if err != nil { return err } - f.Domain().MiningManager().HandleNewBlockTransactions(block.Transactions) + newBlocks := append([]*externalapi.DomainBlock{block}, unorphanedBlocks...) + for _, newBlock := range newBlocks { + blocklogger.LogBlock(block) - if f.onBlockAddedToDAGHandler != nil { - err := f.onBlockAddedToDAGHandler(block) - if err != nil { - return err + f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) + + if f.onBlockAddedToDAGHandler != nil { + err := f.onBlockAddedToDAGHandler(newBlock) + if err != nil { + return err + } } } diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index 10a2ed92b..a8cd7d24c 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -51,6 +51,9 @@ type FlowContext struct { peers map[id.ID]*peerpkg.Peer peersMutex sync.RWMutex + + orphans map[externalapi.DomainHash]*externalapi.DomainBlock + orphansMutex sync.Mutex } // New returns a new instance of FlowContext. @@ -67,6 +70,7 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage sharedRequestedBlocks: blockrelay.NewSharedRequestedBlocks(), peers: make(map[id.ID]*peerpkg.Peer), transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction), + orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock), } } diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go new file mode 100644 index 000000000..2f683b688 --- /dev/null +++ b/app/protocol/flowcontext/orphans.go @@ -0,0 +1,111 @@ +package flowcontext + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/pkg/errors" +) + +func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { + f.orphansMutex.Lock() + defer f.orphansMutex.Unlock() + + orphanHash := consensusserialization.BlockHash(orphanBlock) + f.orphans[*orphanHash] = orphanBlock +} + +func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*externalapi.DomainBlock, error) { + f.orphansMutex.Lock() + defer f.orphansMutex.Unlock() + + // Find all the children of rootBlock among the orphans + // and add them to the process queue + rootBlockHash := consensusserialization.BlockHash(rootBlock) + processQueue := f.addChildOrphansToProcessQueue(rootBlockHash, []externalapi.DomainHash{}) + + var unorphanedBlocks []*externalapi.DomainBlock + for len(processQueue) > 0 { + var orphanHash externalapi.DomainHash + orphanHash, processQueue = processQueue[0], processQueue[1:] + orphanBlock := f.orphans[orphanHash] + + log.Tracef("Considering to unorphan block %s with parents %s", + orphanHash, orphanBlock.Header.ParentHashes) + + canBeUnorphaned := true + for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes { + orphanBlockParentInfo, err := f.domain.Consensus().GetBlockInfo(orphanBlockParentHash) + if err != nil { + return nil, err + } + if !orphanBlockParentInfo.Exists { + log.Tracef("Cannot unorphan block %s. It's missing at "+ + "least the following parent: %s", orphanHash, orphanBlockParentHash) + + canBeUnorphaned = false + break + } + } + if canBeUnorphaned { + err := f.unorphanBlock(orphanHash) + if err != nil { + return nil, err + } + unorphanedBlocks = append(unorphanedBlocks, orphanBlock) + processQueue = f.addChildOrphansToProcessQueue(&orphanHash, processQueue) + } + } + + return unorphanedBlocks, nil +} + +// addChildOrphansToProcessQueue finds all child orphans of `blockHash` +// and adds them to the given `processQueue` if they don't already exist +// inside of it +// Note that this method does not modify the given `processQueue` +func (f *FlowContext) addChildOrphansToProcessQueue(blockHash *externalapi.DomainHash, + processQueue []externalapi.DomainHash) []externalapi.DomainHash { + + blockChildren := f.findChildOrphansOfBlock(blockHash) + for _, blockChild := range blockChildren { + exists := false + for _, queueOrphan := range processQueue { + if queueOrphan == blockChild { + exists = true + break + } + } + if !exists { + processQueue = append(processQueue, blockChild) + } + } + return processQueue +} + +func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) []externalapi.DomainHash { + var childOrphans []externalapi.DomainHash + for orphanHash, orphanBlock := range f.orphans { + for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes { + if *orphanBlockParentHash == *blockHash { + childOrphans = append(childOrphans, orphanHash) + break + } + } + } + return childOrphans +} + +func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) error { + orphanBlock, ok := f.orphans[orphanHash] + if !ok { + return errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash) + } + err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock) + if err != nil { + return err + } + delete(f.orphans, orphanHash) + + log.Debugf("Unorphaned block %s", orphanHash) + return nil +} diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 65d517327..09cedc656 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -25,6 +25,7 @@ type RelayInvsContext interface { StartIBDIfRequired() error IsInIBD() bool Broadcast(message appmessage.Message) error + AddOrphan(orphanBlock *externalapi.DomainBlock) } type handleRelayInvsFlow struct { @@ -229,6 +230,9 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS return nil } + // Add the orphan to the orphan pool + flow.AddOrphan(block) + // Request the parents for the orphan block from the peer that sent it. for _, missingAncestor := range missingParentsError.MissingParentHashes { requestQueue.enqueueIfNotExists(missingAncestor) From 9eb5c4a0ed847bc9f8e597b1f01e9a6761ccb414 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 17 Nov 2020 15:04:27 +0200 Subject: [PATCH 060/351] [NOD-1532] Make all nets equal in mining difficulty (#1095) * [NOD-1532] Make all nets equal in mining difficulty * [NOD-1532] Fix comments --- domain/dagconfig/genesis.go | 50 ++++++++++++++++++------------------- domain/dagconfig/params.go | 11 ++++---- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 577e37b49..a4e1dcd0b 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -28,10 +28,10 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.DomainHash{ - 0xbb, 0xc1, 0x88, 0xdd, 0x56, 0x9d, 0x46, 0xbd, - 0x36, 0xb0, 0x31, 0x52, 0x49, 0x93, 0xac, 0x70, - 0x1d, 0x36, 0xf1, 0xb3, 0xd2, 0x2f, 0xe5, 0x51, - 0x7c, 0x8b, 0x1a, 0xaf, 0x3c, 0x82, 0x6f, 0x18, + 0x28, 0x31, 0x30, 0xca, 0xfe, 0x26, 0x47, 0xc1, + 0xa8, 0x43, 0x43, 0xb2, 0xcb, 0xa5, 0x7e, 0x97, + 0x4b, 0xa6, 0x62, 0x50, 0xd9, 0x8e, 0xff, 0x28, + 0xda, 0x9b, 0xf6, 0x96, 0xdd, 0x70, 0xe9, 0x1e, } // genesisMerkleRoot is the hash of the first transaction in the genesis block @@ -52,7 +52,7 @@ var genesisBlock = externalapi.DomainBlock{ HashMerkleRoot: genesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bc9e305a, + TimeInMilliseconds: 0x175d5fcb8f5, Bits: 0x207fffff, Nonce: 0x0, }, @@ -79,10 +79,10 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.DomainHash{ - 0x92, 0xb5, 0x28, 0xd3, 0xaa, 0x6d, 0x8b, 0x30, - 0x49, 0x19, 0x53, 0x6f, 0x62, 0xce, 0x9a, 0x82, - 0x2f, 0x91, 0xd4, 0x33, 0x24, 0xbc, 0x39, 0xe6, - 0xad, 0x53, 0xe3, 0x97, 0x5f, 0x03, 0x00, 0x00, + 0x54, 0x2c, 0x9c, 0xe0, 0x82, 0x2d, 0x41, 0x51, + 0xcf, 0x13, 0x03, 0xb5, 0x19, 0x58, 0xea, 0x3e, + 0xe8, 0x5c, 0xaf, 0x2f, 0x67, 0x50, 0x3a, 0xc9, + 0x36, 0x6a, 0xf6, 0x66, 0x3a, 0x78, 0xc3, 0x50, } // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -103,9 +103,9 @@ var devnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: devnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bca27b7f, - Bits: 0x1e7fffff, - Nonce: 0x1a9ba, + TimeInMilliseconds: 0x175d5fcb8f5, + Bits: 0x207fffff, + Nonce: 0x3, }, Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -129,10 +129,10 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0x84, 0x96, 0x38, 0xb6, 0x5c, 0x44, 0xc0, 0xb9, - 0x3c, 0x48, 0x03, 0x7c, 0x2e, 0xee, 0x0a, 0xbf, - 0xfb, 0x54, 0xc8, 0x5f, 0x99, 0xd6, 0x21, 0x3d, - 0x3f, 0xdd, 0xac, 0xb1, 0xe7, 0x30, 0x7e, 0x05, + 0xe0, 0xe2, 0x74, 0xea, 0xca, 0xcd, 0x52, 0x74, + 0xa8, 0x33, 0x7b, 0x4c, 0xc2, 0x53, 0xe8, 0xbb, + 0x7b, 0xc2, 0xa7, 0xcc, 0xf7, 0xfe, 0x4b, 0x10, + 0x9f, 0x87, 0x35, 0x51, 0x39, 0x79, 0xea, 0x32, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -153,9 +153,9 @@ var simnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: simnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bca27c39, + TimeInMilliseconds: 0x175d5fcb8f5, Bits: 0x207fffff, - Nonce: 0x1, + Nonce: 0x0, }, Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } @@ -177,10 +177,10 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.DomainHash{ - 0xa9, 0xbe, 0xa7, 0xd9, 0x0f, 0xd2, 0xbd, 0xfb, - 0xd8, 0x09, 0x4d, 0x6a, 0x49, 0xa7, 0x59, 0x93, - 0xd1, 0x35, 0xce, 0x61, 0x18, 0x07, 0x0b, 0xe6, - 0xb9, 0xec, 0xad, 0x68, 0xe4, 0x2d, 0x00, 0x00, + 0x19, 0xbe, 0x88, 0x5e, 0x70, 0x11, 0xf1, 0x11, + 0x76, 0xa5, 0x81, 0x30, 0x16, 0xbd, 0x44, 0x42, + 0x42, 0xb7, 0xbd, 0x98, 0x4a, 0xdc, 0x57, 0xa5, + 0x71, 0x99, 0xb7, 0x85, 0x2d, 0x11, 0x96, 0x7e, } // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -201,9 +201,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: testnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bcac06ec, - Bits: 0x1e7fffff, - Nonce: 0x568f, + TimeInMilliseconds: 0x175d5fcb8f5, + Bits: 0x207fffff, + Nonce: 0x0, }, Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index aeefbee5a..f191f408c 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -5,10 +5,11 @@ package dagconfig import ( - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "math/big" "time" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/app/appmessage" @@ -31,8 +32,8 @@ var ( mainPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) // testnetPowMax is the highest proof of work value a Kaspa block - // can have for the test network. It is the value 2^239 - 1. - testnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) + // can have for the test network. It is the value 2^255 - 1. + testnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) // simnetPowMax is the highest proof of work value a Kaspa block // can have for the simulation test network. It is the value 2^255 - 1. @@ -40,8 +41,8 @@ var ( // devnetPowMax is the highest proof of work value a Kaspa block // can have for the development network. It is the value - // 2^239 - 1. - devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) + // 2^255 - 1. + devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) ) const ( From c785ca0e520a98ec505d746ed8f0662e65c0667b Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 17 Nov 2020 15:23:52 +0200 Subject: [PATCH 061/351] Add more compactBits tests (#1096) --- domain/consensus/utils/math/math_test.go | 71 +++++++++++++++++------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/domain/consensus/utils/math/math_test.go b/domain/consensus/utils/math/math_test.go index ddefea4f0..007f3ad40 100644 --- a/domain/consensus/utils/math/math_test.go +++ b/domain/consensus/utils/math/math_test.go @@ -1,6 +1,7 @@ package math import ( + "fmt" "math" "math/big" "testing" @@ -43,10 +44,11 @@ func TestBigToCompact(t *testing.T) { in string out uint32 }{ - {"0", 0}, + {"0000000000000000000000000000000000000000000000000000000000000000", 0}, {"-1", 25231360}, {"9223372036854775807", 142606335}, {"922337203685477580712312312123487", 237861256}, + {"128", 0x02008000}, } for x, test := range tests { @@ -65,30 +67,57 @@ func TestBigToCompact(t *testing.T) { // representation to the expected big integers. func TestCompactToBig(t *testing.T) { tests := []struct { - in uint32 - out string + before uint32 + intHex string + after uint32 }{ - {0, "0"}, - {10000000, "0"}, - {math.MaxUint32, "-6311914495863998658485429352026283268468573753812676234178171506285465200675957" + - "87397376951158770808349115367298981082112562162319027637583517246275967980671962038665775867893645140" + - "22856089959012026469381002722748489975264028415685723882208353467651862351803217528553851158828320170" + - "89832330727351553686808317476632783024236208492771822246700842318520468733521003756809213629548010354" + - "33865968377930773213939300289069292503211567790599147939718451689002543278625341832829837474611074167" + - "86700705915281593002614032021233542099318559748885883681365573294332856023451874423425211080847063825" + - "199113186681992371681311588352", - }, - {142606335, "9223370937343148032"}, - {25231360, "-1"}, - {237861256, "922337129789886856855791696084992"}, + {math.MaxUint32, "-7fffff000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000", math.MaxUint32}, + {0x00000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x0989680, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x87fffff, "0000000000000000000000000000000000000000000000007fffff0000000000", 0x87fffff}, + {0x1810000, "-000000000000000000000000000000000000000000000000000000000000001", 0x1810000}, + {0xe2d7988, "0000000000000000000000000000000000002d79880000000000000000000000", 0xe2d7988}, + {0x00123456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x01003456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x02000056, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x03000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x04000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x00923456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x01803456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x02800056, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x03800000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x04800000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x01123456, "0000000000000000000000000000000000000000000000000000000000000012", 0x01120000}, + {0x02008000, "0000000000000000000000000000000000000000000000000000000000000080", 0x02008000}, + {0x01fedcba, "-00000000000000000000000000000000000000000000000000000000000007e", 0x01fe0000}, + {0x02123456, "0000000000000000000000000000000000000000000000000000000000001234", 0x02123400}, + {0x03123456, "0000000000000000000000000000000000000000000000000000000000123456", 0x03123456}, + {0x04123456, "0000000000000000000000000000000000000000000000000000000012345600", 0x04123456}, + {0x04923456, "-000000000000000000000000000000000000000000000000000000012345600", 0x04923456}, + {0x05009234, "0000000000000000000000000000000000000000000000000000000092340000", 0x05009234}, + {0x20123456, "1234560000000000000000000000000000000000000000000000000000000000", 0x20123456}, + {0xff123456, "123456000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 0xff123456}, } for i, test := range tests { - n := CompactToBig(test.in) - if n.String() != test.out { - t.Errorf("TestCompactToBig test #%d failed: got %s want %s", - i, n, test.out) - return + n := CompactToBig(test.before) + convertBack := BigToCompact(n) + got := fmt.Sprintf("%064x", n) + if got != test.intHex { + t.Errorf("TestCompactToBig test #%d failed: got %s want %s, input: 0x%08x", + i, got, test.intHex, test.before) + } + if convertBack != test.after { + t.Errorf("TestCompactToBig test #%d failed: got: 0x%08x want 0x%08x input: 0x%08x", i, convertBack, test.after, test.before) } } } From d4993c1d061ab6f0f79eedfb473e92a2eb4022a3 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 17 Nov 2020 15:28:01 +0200 Subject: [PATCH 062/351] [NOD-1542] Don't try to return more addresses then we have (#1097) * [NOD-1542] Don't try to return more addresses then we have * [NOD-1542] Allocate according to updated count --- .../network/addressmanager/addressrandomize.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/infrastructure/network/addressmanager/addressrandomize.go b/infrastructure/network/addressmanager/addressrandomize.go index 35c296293..03e17d26b 100644 --- a/infrastructure/network/addressmanager/addressrandomize.go +++ b/infrastructure/network/addressmanager/addressrandomize.go @@ -31,12 +31,15 @@ func (amc *AddressRandomize) RandomAddress(addresses []*appmessage.NetAddress) * // RandomAddresses returns count addresses at random from input list func (amc *AddressRandomize) RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress { + if len(addresses) < count { + count = len(addresses) + } + result := make([]*appmessage.NetAddress, 0, count) - if len(addresses) > 0 { - randomIndexes := rand.Perm(len(addresses)) - for i := 0; i < count; i++ { - result = append(result, addresses[randomIndexes[i]]) - } + + randomIndexes := rand.Perm(len(addresses)) + for i := 0; i < count; i++ { + result = append(result, addresses[randomIndexes[i]]) } return result From 60c24d8dea9ca3b702c52db38fb8c933b8aa4dca Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 17 Nov 2020 05:46:31 -0800 Subject: [PATCH 063/351] Fix TestBlueBlockWindow (#1098) * Fix TestBlueBlockWindow * Add comments --- app/protocol/flowcontext/orphans.go | 2 + .../serialization/blues_anticone_sizes.go | 3 +- ...interface_processes_dagtraversalmanager.go | 2 +- .../blockbuilder/test_block_builder.go | 7 +- .../calculate_past_utxo.go | 3 + .../consensusstatemanager/finality.go | 16 +- .../set_pruning_utxo_set.go | 11 +- .../dagtraversalmanager.go | 14 +- .../dagtraversalmanager/window_test.go | 260 ++++++++++++++++-- .../mergedepthmanager/merge_depth_manager.go | 12 +- .../pruningmanager/pruningmanager.go | 2 +- .../standalone/minimal_net_adapter.go | 3 + 12 files changed, 271 insertions(+), 64 deletions(-) diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 2f683b688..08010e623 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" ) +// AddOrphan adds the block to the orphan set func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphansMutex.Lock() defer f.orphansMutex.Unlock() @@ -14,6 +15,7 @@ func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphans[*orphanHash] = orphanBlock } +// UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore. func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*externalapi.DomainBlock, error) { f.orphansMutex.Lock() defer f.orphansMutex.Unlock() diff --git a/domain/consensus/database/serialization/blues_anticone_sizes.go b/domain/consensus/database/serialization/blues_anticone_sizes.go index 1b2359b61..19f526e02 100644 --- a/domain/consensus/database/serialization/blues_anticone_sizes.go +++ b/domain/consensus/database/serialization/blues_anticone_sizes.go @@ -10,8 +10,9 @@ func bluesAnticoneSizesToDBBluesAnticoneSizes(bluesAnticoneSizes map[externalapi dbBluesAnticoneSizes := make([]*DbBluesAnticoneSizes, len(bluesAnticoneSizes)) i := 0 for hash, anticoneSize := range bluesAnticoneSizes { + hashCopy := hash dbBluesAnticoneSizes[i] = &DbBluesAnticoneSizes{ - BlueHash: DomainHashToDbHash(&hash), + BlueHash: DomainHashToDbHash(&hashCopy), AnticoneSize: uint32(anticoneSize), } i++ diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index 550a0fc67..e3df498ce 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // DAGTraversalManager exposes methods for traversing blocks // in the DAG type DAGTraversalManager interface { - HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) + BlockAtDepth(highHash *externalapi.DomainHash, depth uint64) (*externalapi.DomainHash, error) LowestChainBlockAboveOrEqualToBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) SelectedParentIterator(highHash *externalapi.DomainHash) BlockIterator SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 57204c2d7..7b9236160 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -99,12 +99,7 @@ func (bb *testBlockBuilder) buildBlockWithParents( return nil, err } - selectedParentStatus, err := bb.testConsensus.BlockStatusStore().Get(bb.databaseContext, ghostdagData.SelectedParent) - if err != nil { - return nil, err - } - - selectedParentStatus, err = bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 7cbef09cb..417468732 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -159,6 +159,9 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap } isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore) + if !isAccepted { + return false, accumulatedMassBefore, nil + } } err = utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore) diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go index c63bd449a..f568733de 100644 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ b/domain/consensus/processes/consensusstatemanager/finality.go @@ -28,20 +28,8 @@ func (csm *consensusStateManager) checkFinalityViolation( func (csm *consensusStateManager) virtualFinalityPoint() ( *externalapi.DomainHash, error) { - virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - - finalityPointBlueScore := virtualGHOSTDAGData.BlueScore - csm.finalityDepth - if virtualGHOSTDAGData.BlueScore < csm.finalityDepth { - // if there's no `csm.finalityDepth` blocks in the DAG - // practically - returns the genesis - finalityPointBlueScore = 0 - } - - return csm.dagTraversalManager.HighestChainBlockBelowBlueScore( - model.VirtualBlockHash, finalityPointBlueScore) + return csm.dagTraversalManager.BlockAtDepth( + model.VirtualBlockHash, csm.finalityDepth) } func (csm *consensusStateManager) isViolatingFinality( diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 74926f69d..59a65a9ab 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -156,14 +156,5 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH } defer csm.ghostdagDataStore.Discard() - virtualHeaderGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, virtualHeaderHash) - if err != nil { - return nil, err - } - - blueScore := virtualHeaderGHOSTDAGData.BlueScore - csm.pruningDepth - if csm.pruningDepth > virtualHeaderGHOSTDAGData.BlueScore { - blueScore = 0 - } - return csm.dagTraversalManager.HighestChainBlockBelowBlueScore(virtualHeaderHash, blueScore) + return csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth) } diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 1379c8263..bc157f78d 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -64,17 +64,21 @@ func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.Dom } } -// HighestChainBlockBelowBlueScore returns the hash of the -// highest block with a blue score lower than the given -// blueScore in the selected-parent-chain of the block -// with the given highHash's selected parent chain -func (dtm *dagTraversalManager) HighestChainBlockBelowBlueScore(highHash *externalapi.DomainHash, requiredBlueScore uint64) (*externalapi.DomainHash, error) { +// BlockAtDepth returns the hash of the highest block with a blue score +// lower than (highHash.blueSore - depth) in the selected-parent-chain +// of the block with the given highHash's selected parent chain. +func (dtm *dagTraversalManager) BlockAtDepth(highHash *externalapi.DomainHash, depth uint64) (*externalapi.DomainHash, error) { currentBlockHash := highHash highBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, highHash) if err != nil { return nil, err } + requiredBlueScore := uint64(0) + if highBlockGHOSTDAGData.BlueScore > depth { + requiredBlueScore = highBlockGHOSTDAGData.BlueScore - depth + } + currentBlockGHOSTDAGData := highBlockGHOSTDAGData // If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore for currentBlockGHOSTDAGData.BlueScore >= requiredBlueScore { diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 3c3ba65c1..6a13f01be 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -12,25 +12,156 @@ import ( ) func TestBlueBlockWindow(t *testing.T) { - testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestBlueBlockWindow") - if err != nil { - t.Fatalf("NewTestConsensus: %s", err) - } - defer tearDown() - - windowSize := uint64(10) - blockByIDMap := make(map[string]*externalapi.DomainHash) - idByBlockMap := make(map[externalapi.DomainHash]string) - blockByIDMap["A"] = params.GenesisHash - idByBlockMap[*params.GenesisHash] = "A" - - blocksData := []*struct { - parents []string - id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash - expectedWindowWithGenesisPadding []string - }{ + tests := map[string][]*struct { + parents []string + id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash + expectedWindowWithGenesisPadding []string + }{ + "kaspa-mainnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + }, + }, + "kaspa-testnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + }, + }, + "kaspa-devnet": { { parents: []string{"A"}, id: "B", @@ -101,7 +232,96 @@ func TestBlueBlockWindow(t *testing.T) { id: "O", expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, }, + }, + "kaspa-simnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + }, + }, + } + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.K = 1 + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, "TestBlueBlockWindow") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) } + defer tearDown() + + windowSize := uint64(10) + blockByIDMap := make(map[string]*externalapi.DomainHash) + idByBlockMap := make(map[externalapi.DomainHash]string) + blockByIDMap["A"] = params.GenesisHash + idByBlockMap[*params.GenesisHash] = "A" + + blocksData := tests[params.Name] for _, blockData := range blocksData { parents := hashset.New() @@ -112,7 +332,7 @@ func TestBlueBlockWindow(t *testing.T) { block, err := tc.AddBlock(parents.ToSlice(), nil, nil) if err != nil { - t.Fatalf("AddBlock: %s", err) + t.Fatalf("AddBlock: %+v", err) } blockByIDMap[blockData.id] = block diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index 41419ade6..cbf29f331 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -50,7 +50,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma return nil } - finalityPoint, err := mdm.finalityPoint(ghostdagData) + finalityPoint, err := mdm.finalityPoint(blockHash) if err != nil { return err } @@ -88,7 +88,7 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues)) for _, blue := range ghostdagData.MergeSetBlues { - notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(ghostdagData, blue) + notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(blockHash, blue) if err != nil { return nil, err } @@ -101,8 +101,8 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter return nonBoundedMergeDepthViolatingBlues, nil } -func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(ghostdagData *model.BlockGHOSTDAGData, other *externalapi.DomainHash) (bool, error) { - finalityPoint, err := mdm.finalityPoint(ghostdagData) +func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(this, other *externalapi.DomainHash) (bool, error) { + finalityPoint, err := mdm.finalityPoint(this) if err != nil { return false, err } @@ -110,6 +110,6 @@ func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(ghostdagData return mdm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint, other) } -func (mdm *mergeDepthManager) finalityPoint(ghostdagData *model.BlockGHOSTDAGData) (*externalapi.DomainHash, error) { - return mdm.dagTraversalManager.HighestChainBlockBelowBlueScore(ghostdagData.SelectedParent, ghostdagData.BlueScore-mdm.finalityDepth) +func (mdm *mergeDepthManager) finalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + return mdm.dagTraversalManager.BlockAtDepth(blockHash, mdm.finalityDepth) } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index edc9766e7..36c397dc2 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -98,7 +98,7 @@ func (pm *pruningManager) FindNextPruningPoint() error { } // get Virtual(pruningDepth) - candidatePHash, err := pm.dagTraversalManager.HighestChainBlockBelowBlueScore(model.VirtualBlockHash, pm.pruningDepth) + candidatePHash, err := pm.dagTraversalManager.BlockAtDepth(model.VirtualBlockHash, pm.pruningDepth) if err != nil { return err } diff --git a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go index d0036b8bb..255780fe0 100644 --- a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go +++ b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go @@ -152,6 +152,9 @@ func (mna *MinimalNetAdapter) handleHandshake(routes *Routes, ourID *id.ID) erro err = routes.OutgoingRoute.Enqueue(&appmessage.MsgAddresses{ AddressList: []*appmessage.NetAddress{}, }) + if err != nil { + return err + } err = routes.OutgoingRoute.Enqueue(&appmessage.MsgRequestAddresses{ IncludeAllSubnetworks: true, From 891095563e6c3966667efb44b4ffaa09a63b83cf Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 17 Nov 2020 05:54:17 -0800 Subject: [PATCH 064/351] Fix blocks order (#1099) --- .../dagtraversalmanager/window_test.go | 292 +++++++++--------- 1 file changed, 146 insertions(+), 146 deletions(-) diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 6a13f01be..50b58d3dc 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -34,156 +34,12 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"C", "D"}, - id: "E", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"C", "D"}, - id: "F", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"A"}, - id: "G", - expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"G"}, - id: "H", - expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"H", "F"}, - id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"I"}, - id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"J"}, - id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, - }, - { - parents: []string{"K"}, - id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, - }, - { - parents: []string{"L"}, - id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, - }, - { - parents: []string{"M"}, - id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, - }, - { - parents: []string{"N"}, - id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, - }, - }, - "kaspa-testnet": { - { - parents: []string{"A"}, - id: "B", - expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"B"}, - id: "C", - expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"B"}, - id: "D", - expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"C", "D"}, - id: "E", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"C", "D"}, - id: "F", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"A"}, - id: "G", - expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"G"}, - id: "H", - expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"H", "F"}, - id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"I"}, - id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"J"}, - id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, - }, - { - parents: []string{"K"}, - id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, - }, - { - parents: []string{"L"}, - id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, - }, - { - parents: []string{"M"}, - id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, - }, - { - parents: []string{"N"}, - id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, - }, - }, - "kaspa-devnet": { - { - parents: []string{"A"}, - id: "B", - expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"B"}, - id: "C", - expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"B"}, - id: "D", - expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, - }, - { - parents: []string{"C", "D"}, + parents: []string{"D", "C"}, id: "E", expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"C", "D"}, + parents: []string{"D", "C"}, id: "F", expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, @@ -233,6 +89,150 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, }, }, + "kaspa-testnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"D", "C"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"D", "C"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + }, + }, + "kaspa-devnet": { + { + parents: []string{"A"}, + id: "B", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "C", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"B"}, + id: "D", + expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "E", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"C", "D"}, + id: "F", + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"A"}, + id: "G", + expectedWindowWithGenesisPadding: []string{"A", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"G"}, + id: "H", + expectedWindowWithGenesisPadding: []string{"G", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"H", "F"}, + id: "I", + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"I"}, + id: "J", + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + }, + { + parents: []string{"J"}, + id: "K", + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + }, + { + parents: []string{"K"}, + id: "L", + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + }, + { + parents: []string{"L"}, + id: "M", + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + }, + { + parents: []string{"M"}, + id: "N", + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + }, + { + parents: []string{"N"}, + id: "O", + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + }, + }, "kaspa-simnet": { { parents: []string{"A"}, From 7479f5f5e81af6cb9f3d8c37d218e09ac7490ec8 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 17 Nov 2020 16:40:55 +0200 Subject: [PATCH 065/351] [NOD-1545] Fix incorrect block difficulty calculation in buildHeader. (#1102) --- .../processes/blockbuilder/block_builder.go | 14 +++----------- .../processes/blockbuilder/test_block_builder.go | 7 +------ 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 1c30f2135..db34a4105 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -100,15 +100,11 @@ func (bb *blockBuilder) buildHeader(transactions []*externalapi.DomainTransactio if err != nil { return nil, err } - virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } timeInMilliseconds, err := bb.newBlockTime() if err != nil { return nil, err } - bits, err := bb.newBlockDifficulty(virtualGHOSTDAGData) + bits, err := bb.newBlockDifficulty() if err != nil { return nil, err } @@ -160,12 +156,8 @@ func (bb *blockBuilder) newBlockTime() (int64, error) { return newTimestamp, nil } -func (bb *blockBuilder) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) { - virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash) - if err != nil { - return 0, err - } - return bb.difficultyManager.RequiredDifficulty(virtualGHOSTDAGData.SelectedParent) +func (bb *blockBuilder) newBlockDifficulty() (uint32, error) { + return bb.difficultyManager.RequiredDifficulty(model.VirtualBlockHash) } func (bb *blockBuilder) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 7b9236160..addcaa558 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -39,16 +39,11 @@ func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.Do transactions []*externalapi.DomainTransaction, acceptanceData model.AcceptanceData, multiset model.Multiset) ( *externalapi.DomainBlockHeader, error) { - ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash) - if err != nil { - return nil, err - } - timeInMilliseconds, err := bb.pastMedianTimeManager.PastMedianTime(tempBlockHash) if err != nil { return nil, err } - bits, err := bb.newBlockDifficulty(ghostdagData) + bits, err := bb.newBlockDifficulty() if err != nil { return nil, err } From 184911f76e9d5164d6402f46e656e61971cbc4e9 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 17 Nov 2020 18:05:14 +0200 Subject: [PATCH 066/351] [NOD-1547] Make the SendAddresses flow not one-time for the sake of DNSSeeder (#1104) * [NOD-1547] Make the SendAddresses flow not one-time for the sake of DNSSeeder. * [NOD-1547] Add all special commands to chooseRouteForCommand. --- .../flows/addressexchange/sendaddresses.go | 29 +++++++++++-------- app/protocol/protocol.go | 2 +- .../network/netadapter/standalone/routes.go | 16 +++++++++- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/app/protocol/flows/addressexchange/sendaddresses.go b/app/protocol/flows/addressexchange/sendaddresses.go index 340640459..f7a9cdd17 100644 --- a/app/protocol/flows/addressexchange/sendaddresses.go +++ b/app/protocol/flows/addressexchange/sendaddresses.go @@ -16,20 +16,25 @@ type SendAddressesContext interface { // SendAddresses sends addresses to a peer that requests it. func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, outgoingRoute *router.Route) error { - message, err := incomingRoute.Dequeue() - if err != nil { - return err - } + for { + message, err := incomingRoute.Dequeue() + if err != nil { + return err + } - _, ok := message.(*appmessage.MsgRequestAddresses) - if !ok { - return protocolerrors.Errorf(true, "unexpected message. "+ - "Expected: %s, got: %s", appmessage.CmdRequestAddresses, message.Command()) - } - addresses := context.AddressManager().Addresses() - msgAddresses := appmessage.NewMsgAddresses(shuffleAddresses(addresses)) + _, ok := message.(*appmessage.MsgRequestAddresses) + if !ok { + return protocolerrors.Errorf(true, "unexpected message. "+ + "Expected: %s, got: %s", appmessage.CmdRequestAddresses, message.Command()) + } + addresses := context.AddressManager().Addresses() + msgAddresses := appmessage.NewMsgAddresses(shuffleAddresses(addresses)) - return outgoingRoute.Enqueue(msgAddresses) + err = outgoingRoute.Enqueue(msgAddresses) + if err != nil { + return err + } + } } // shuffleAddresses randomizes the given addresses sent if there are more than the maximum allowed in one message. diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 523018796..28c0ee772 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -118,7 +118,7 @@ func (m *Manager) registerAddressFlows(router *routerpkg.Router, isStopping *uin outgoingRoute := router.OutgoingRoute() return []*flow{ - m.registerOneTimeFlow("SendAddresses", router, []appmessage.MessageCommand{appmessage.CmdRequestAddresses}, isStopping, errChan, + m.registerFlow("SendAddresses", router, []appmessage.MessageCommand{appmessage.CmdRequestAddresses}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return addressexchange.SendAddresses(m.context, incomingRoute, outgoingRoute) }, diff --git a/infrastructure/network/netadapter/standalone/routes.go b/infrastructure/network/netadapter/standalone/routes.go index d2f7d0083..0f1dc830a 100644 --- a/infrastructure/network/netadapter/standalone/routes.go +++ b/infrastructure/network/netadapter/standalone/routes.go @@ -25,7 +25,8 @@ type Routes struct { func (r *Routes) WaitForMessageOfType(command appmessage.MessageCommand, timeout time.Duration) (appmessage.Message, error) { timeoutTime := time.Now().Add(timeout) for { - message, err := r.IncomingRoute.DequeueWithTimeout(timeoutTime.Sub(time.Now())) + route := r.chooseRouteForCommand(command) + message, err := route.DequeueWithTimeout(timeoutTime.Sub(time.Now())) if err != nil { return nil, errors.Wrapf(err, "error waiting for message of type %s", command) } @@ -35,6 +36,19 @@ func (r *Routes) WaitForMessageOfType(command appmessage.MessageCommand, timeout } } +func (r *Routes) chooseRouteForCommand(command appmessage.MessageCommand) *router.Route { + switch command { + case appmessage.CmdVersion, appmessage.CmdVerAck: + return r.handshakeRoute + case appmessage.CmdRequestAddresses, appmessage.CmdAddresses: + return r.addressesRoute + case appmessage.CmdPing: + return r.pingRoute + default: + return r.IncomingRoute + } +} + // WaitForDisconnect waits for a disconnect up to `timeout`, skipping all messages received while waiting func (r *Routes) WaitForDisconnect(timeout time.Duration) error { timeoutTime := time.Now().Add(timeout) From 5b037950d8d680c5f9f035fb0a64f15edb969dea Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Nov 2020 09:16:58 +0200 Subject: [PATCH 067/351] Fix double printing the mainnet has not launched yet message (#1101) --- app/app.go | 2 +- infrastructure/config/network.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/app.go b/app/app.go index b529ed27b..624da91ec 100644 --- a/app/app.go +++ b/app/app.go @@ -46,7 +46,7 @@ func StartApp() error { // initializes logging and configures it accordingly. cfg, err := config.LoadConfig() if err != nil { - fmt.Fprint(os.Stderr, err) + fmt.Fprintln(os.Stderr, err) return err } defer panics.HandlePanic(log, "MAIN", nil) diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index 78b06f882..e5bcd4767 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -48,10 +48,7 @@ func (networkFlags *NetworkFlags) ResolveNetwork(parser *flags.Parser) error { } if numNets == 0 { - message := "Mainnet has not launched yet, use --testnet to run in testnet mode" - err := errors.Errorf(message) - fmt.Fprintln(os.Stderr, err) - return err + return errors.Errorf("Mainnet has not launched yet, use --testnet to run in testnet mode") } return nil From 8500acd86b4809af37d93d8b3ce9896b96fbdfd2 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 18 Nov 2020 00:27:29 -0800 Subject: [PATCH 068/351] [NOD-1548] Remove PoW check from tests (#1105) * [NOD-1548] Add TestDifficulty and remove PoW check from tests * [NOD-1548] Add TestSkipProofOfWork * [NOD-1548] Remove TestDifficulty --- domain/consensus/factory.go | 4 +- .../consensus/model/testapi/test_consensus.go | 2 - .../processes/blockbuilder/block_builder.go | 13 ++++- .../blockbuilder/test_block_builder.go | 10 ++-- .../blockvalidator/block_header_in_context.go | 2 +- .../dagtopologymanager_external_test.go | 2 +- .../dagtraversalmanager/window_test.go | 18 +++---- .../pastmediantimemanager_test.go | 7 +-- domain/consensus/test_consensus.go | 15 +----- .../consensus/utils/testutils/for_all_nets.go | 11 ++-- domain/dagconfig/genesis.go | 50 +++++++++---------- domain/dagconfig/params.go | 11 ++-- domain/dagconfig/params_test.go | 17 +++++++ 13 files changed, 89 insertions(+), 73 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 3bd7883c2..446b4b6e8 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -2,7 +2,6 @@ package consensus import ( "io/ioutil" - "math/rand" "os" "sync" @@ -130,7 +129,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore) blockValidator := blockvalidator.New( dagParams.PowMax, - false, + dagParams.SkipProofOfWork, genesisHash, dagParams.EnableNonNativeSubnetworks, dagParams.DisableDifficultyAdjustment, @@ -324,7 +323,6 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager) tstConsensus := &testConsensus{ - rd: rand.New(rand.NewSource(0)), consensus: consensusAsImplementation, testConsensusStateManager: testConsensusStateManager, testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation. diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 37fbc8e67..e898e6e62 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -19,8 +19,6 @@ type TestConsensus interface { AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error) - SolveAndAddBlock(block *externalapi.DomainBlock) (*externalapi.DomainHash, error) - DiscardAllStores() AcceptanceDataStore() model.AcceptanceDataStore diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index db34a4105..fbd059ab7 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -145,8 +145,8 @@ func (bb *blockBuilder) newBlockTime() (int64, error) { // timestamp is truncated to a millisecond boundary before comparison since a // block timestamp does not supported a precision greater than one // millisecond. - newTimestamp := mstime.Now().UnixMilliseconds() + 1 - minTimestamp, err := bb.pastMedianTimeManager.PastMedianTime(model.VirtualBlockHash) + newTimestamp := mstime.Now().UnixMilliseconds() + minTimestamp, err := bb.minBlockTime(model.VirtualBlockHash) if err != nil { return 0, err } @@ -156,6 +156,15 @@ func (bb *blockBuilder) newBlockTime() (int64, error) { return newTimestamp, nil } +func (bb *blockBuilder) minBlockTime(hash *externalapi.DomainHash) (int64, error) { + pastMedianTime, err := bb.pastMedianTimeManager.PastMedianTime(hash) + if err != nil { + return 0, err + } + + return pastMedianTime + 1, nil +} + func (bb *blockBuilder) newBlockDifficulty() (uint32, error) { return bb.difficultyManager.RequiredDifficulty(model.VirtualBlockHash) } diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index addcaa558..1521a1079 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -13,6 +13,7 @@ import ( type testBlockBuilder struct { *blockBuilder testConsensus testapi.TestConsensus + nonceCounter uint64 } var tempBlockHash = &externalapi.DomainHash{ @@ -35,15 +36,16 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do return bb.buildBlockWithParents(parentHashes, coinbaseData, transactions) } -func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, +func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, transactions []*externalapi.DomainTransaction, acceptanceData model.AcceptanceData, multiset model.Multiset) ( *externalapi.DomainBlockHeader, error) { - timeInMilliseconds, err := bb.pastMedianTimeManager.PastMedianTime(tempBlockHash) + timeInMilliseconds, err := bb.minBlockTime(tempBlockHash) if err != nil { return nil, err } - bits, err := bb.newBlockDifficulty() + + bits, err := bb.difficultyManager.RequiredDifficulty(tempBlockHash) if err != nil { return nil, err } @@ -54,6 +56,7 @@ func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.Do } utxoCommitment := multiset.Hash() + bb.nonceCounter++ return &externalapi.DomainBlockHeader{ Version: constants.BlockVersion, ParentHashes: parentHashes, @@ -62,6 +65,7 @@ func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.Do UTXOCommitment: *utxoCommitment, TimeInMilliseconds: timeInMilliseconds, Bits: bits, + Nonce: bb.nonceCounter, }, nil } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 3ce784998..ae52d147a 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -107,7 +107,7 @@ func (v *blockValidator) validateMedianTime(header *externalapi.DomainBlockHeade return err } - if header.TimeInMilliseconds < pastMedianTime { + if header.TimeInMilliseconds <= pastMedianTime { return errors.Wrapf(ruleerrors.ErrTimeTooOld, "block timestamp of %d is not after expected %d", header.TimeInMilliseconds, pastMedianTime) } diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go index b060930e6..9cb4bf34f 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -12,7 +12,7 @@ import ( func TestIsAncestorOf(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestIsInPast") + tc, tearDown, err := factory.NewTestConsensus(params, "TestIsAncestorOf") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 50b58d3dc..782616e5f 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -108,12 +108,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"D", "C"}, id: "E", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"D", "C"}, id: "F", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -128,37 +128,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, }, }, "kaspa-devnet": { diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index c335a0d07..aa0184ab0 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -3,6 +3,7 @@ package pastmediantimemanager_test import ( "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "testing" @@ -29,12 +30,12 @@ func TestPastMedianTime(t *testing.T) { } block.Header.TimeInMilliseconds = blockTime - blockHash, err := tc.SolveAndAddBlock(block) + err = tc.ValidateAndInsertBlock(block) if err != nil { - t.Fatalf("SolveAndAddBlock: %s", err) + t.Fatalf("ValidateAndInsertBlock: %+v", err) } - blockHashes[i] = blockHash + blockHashes[i] = consensusserialization.BlockHash(block) } tests := []struct { diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 67d4be494..b01dc58fb 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -1,18 +1,13 @@ package consensus import ( - "math/rand" - - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" - "github.com/kaspanet/kaspad/domain/consensus/utils/mining" - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" ) type testConsensus struct { *consensus - rd *rand.Rand testBlockBuilder model.TestBlockBuilder testReachabilityManager model.TestReachabilityManager @@ -41,13 +36,7 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba return nil, err } - return tc.SolveAndAddBlock(block) -} - -func (tc *testConsensus) SolveAndAddBlock(block *externalapi.DomainBlock) (*externalapi.DomainHash, error) { - mining.SolveBlock(block, tc.rd) - - err := tc.blockProcessor.ValidateAndInsertBlock(block) + err = tc.blockProcessor.ValidateAndInsertBlock(block) if err != nil { return nil, err } diff --git a/domain/consensus/utils/testutils/for_all_nets.go b/domain/consensus/utils/testutils/for_all_nets.go index 14371c7d8..ad73ad9f2 100644 --- a/domain/consensus/utils/testutils/for_all_nets.go +++ b/domain/consensus/utils/testutils/for_all_nets.go @@ -8,7 +8,7 @@ import ( // ForAllNets runs the passed testFunc with all available networks // if setDifficultyToMinumum = true - will modify the net params to have minimal difficulty, like in SimNet -func ForAllNets(t *testing.T, setDifficultyToMinimum bool, testFunc func(*testing.T, *dagconfig.Params)) { +func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *dagconfig.Params)) { allParams := []dagconfig.Params{ dagconfig.MainnetParams, dagconfig.TestnetParams, @@ -17,11 +17,8 @@ func ForAllNets(t *testing.T, setDifficultyToMinimum bool, testFunc func(*testin } for _, params := range allParams { - if setDifficultyToMinimum { - params.DisableDifficultyAdjustment = dagconfig.SimnetParams.DisableDifficultyAdjustment - params.TargetTimePerBlock = dagconfig.SimnetParams.TargetTimePerBlock - } - - t.Run(params.Name, func(t *testing.T) { testFunc(t, ¶ms) }) + params.SkipProofOfWork = skipPow + t.Logf("Running test for %s", params.Name) + testFunc(t, ¶ms) } } diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index a4e1dcd0b..577e37b49 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -28,10 +28,10 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.DomainHash{ - 0x28, 0x31, 0x30, 0xca, 0xfe, 0x26, 0x47, 0xc1, - 0xa8, 0x43, 0x43, 0xb2, 0xcb, 0xa5, 0x7e, 0x97, - 0x4b, 0xa6, 0x62, 0x50, 0xd9, 0x8e, 0xff, 0x28, - 0xda, 0x9b, 0xf6, 0x96, 0xdd, 0x70, 0xe9, 0x1e, + 0xbb, 0xc1, 0x88, 0xdd, 0x56, 0x9d, 0x46, 0xbd, + 0x36, 0xb0, 0x31, 0x52, 0x49, 0x93, 0xac, 0x70, + 0x1d, 0x36, 0xf1, 0xb3, 0xd2, 0x2f, 0xe5, 0x51, + 0x7c, 0x8b, 0x1a, 0xaf, 0x3c, 0x82, 0x6f, 0x18, } // genesisMerkleRoot is the hash of the first transaction in the genesis block @@ -52,7 +52,7 @@ var genesisBlock = externalapi.DomainBlock{ HashMerkleRoot: genesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175d5fcb8f5, + TimeInMilliseconds: 0x175bc9e305a, Bits: 0x207fffff, Nonce: 0x0, }, @@ -79,10 +79,10 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.DomainHash{ - 0x54, 0x2c, 0x9c, 0xe0, 0x82, 0x2d, 0x41, 0x51, - 0xcf, 0x13, 0x03, 0xb5, 0x19, 0x58, 0xea, 0x3e, - 0xe8, 0x5c, 0xaf, 0x2f, 0x67, 0x50, 0x3a, 0xc9, - 0x36, 0x6a, 0xf6, 0x66, 0x3a, 0x78, 0xc3, 0x50, + 0x92, 0xb5, 0x28, 0xd3, 0xaa, 0x6d, 0x8b, 0x30, + 0x49, 0x19, 0x53, 0x6f, 0x62, 0xce, 0x9a, 0x82, + 0x2f, 0x91, 0xd4, 0x33, 0x24, 0xbc, 0x39, 0xe6, + 0xad, 0x53, 0xe3, 0x97, 0x5f, 0x03, 0x00, 0x00, } // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -103,9 +103,9 @@ var devnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: devnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175d5fcb8f5, - Bits: 0x207fffff, - Nonce: 0x3, + TimeInMilliseconds: 0x175bca27b7f, + Bits: 0x1e7fffff, + Nonce: 0x1a9ba, }, Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -129,10 +129,10 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0xe0, 0xe2, 0x74, 0xea, 0xca, 0xcd, 0x52, 0x74, - 0xa8, 0x33, 0x7b, 0x4c, 0xc2, 0x53, 0xe8, 0xbb, - 0x7b, 0xc2, 0xa7, 0xcc, 0xf7, 0xfe, 0x4b, 0x10, - 0x9f, 0x87, 0x35, 0x51, 0x39, 0x79, 0xea, 0x32, + 0x84, 0x96, 0x38, 0xb6, 0x5c, 0x44, 0xc0, 0xb9, + 0x3c, 0x48, 0x03, 0x7c, 0x2e, 0xee, 0x0a, 0xbf, + 0xfb, 0x54, 0xc8, 0x5f, 0x99, 0xd6, 0x21, 0x3d, + 0x3f, 0xdd, 0xac, 0xb1, 0xe7, 0x30, 0x7e, 0x05, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -153,9 +153,9 @@ var simnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: simnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175d5fcb8f5, + TimeInMilliseconds: 0x175bca27c39, Bits: 0x207fffff, - Nonce: 0x0, + Nonce: 0x1, }, Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } @@ -177,10 +177,10 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.DomainHash{ - 0x19, 0xbe, 0x88, 0x5e, 0x70, 0x11, 0xf1, 0x11, - 0x76, 0xa5, 0x81, 0x30, 0x16, 0xbd, 0x44, 0x42, - 0x42, 0xb7, 0xbd, 0x98, 0x4a, 0xdc, 0x57, 0xa5, - 0x71, 0x99, 0xb7, 0x85, 0x2d, 0x11, 0x96, 0x7e, + 0xa9, 0xbe, 0xa7, 0xd9, 0x0f, 0xd2, 0xbd, 0xfb, + 0xd8, 0x09, 0x4d, 0x6a, 0x49, 0xa7, 0x59, 0x93, + 0xd1, 0x35, 0xce, 0x61, 0x18, 0x07, 0x0b, 0xe6, + 0xb9, 0xec, 0xad, 0x68, 0xe4, 0x2d, 0x00, 0x00, } // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -201,9 +201,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: testnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175d5fcb8f5, - Bits: 0x207fffff, - Nonce: 0x0, + TimeInMilliseconds: 0x175bcac06ec, + Bits: 0x1e7fffff, + Nonce: 0x568f, }, Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index f191f408c..7a6f2b8e8 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -32,8 +32,8 @@ var ( mainPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) // testnetPowMax is the highest proof of work value a Kaspa block - // can have for the test network. It is the value 2^255 - 1. - testnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) + // can have for the test network. It is the value 2^239 - 1. + testnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) // simnetPowMax is the highest proof of work value a Kaspa block // can have for the simulation test network. It is the value 2^255 - 1. @@ -41,8 +41,8 @@ var ( // devnetPowMax is the highest proof of work value a Kaspa block // can have for the development network. It is the value - // 2^255 - 1. - devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) + // 2^239 - 1. + devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) ) const ( @@ -147,6 +147,9 @@ type Params struct { // DisableDifficultyAdjustment determine whether to use difficulty DisableDifficultyAdjustment bool + + // SkipProofOfWork indicates whether proof of work should be checked. + SkipProofOfWork bool } // NormalizeRPCServerAddress returns addr with the current network default diff --git a/domain/dagconfig/params_test.go b/domain/dagconfig/params_test.go index 345d927bd..ceb1219b8 100644 --- a/domain/dagconfig/params_test.go +++ b/domain/dagconfig/params_test.go @@ -69,3 +69,20 @@ func TestMustRegisterPanic(t *testing.T) { // Intentionally try to register duplicate params to force a panic. mustRegister(&MainnetParams) } + +// TestSkipProofOfWork ensures all of the hard coded network params don't set SkipProofOfWork as true. +func TestSkipProofOfWork(t *testing.T) { + allParams := []Params{ + MainnetParams, + TestnetParams, + SimnetParams, + DevnetParams, + } + + for _, params := range allParams { + if params.SkipProofOfWork { + t.Errorf("SkipProofOfWork is enabled for %s. This option should be "+ + "used only for tests.", params.Name) + } + } +} From 3f92ddd827dc7c4449a229d8f3deef968dbeefa5 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Nov 2020 11:19:12 +0200 Subject: [PATCH 069/351] Add blueScore to RPC GetBlock, and add more INFO logs (#1103) * Add BlueScore to RPC command GetBlock * Add info logs when getting new blocks from the p2p --- app/appmessage/rpc_get_block.go | 1 + app/protocol/flowcontext/orphans.go | 2 ++ app/protocol/flows/blockrelay/handle_relay_invs.go | 2 ++ app/rpc/rpccontext/verbosedata.go | 7 +++++++ app/rpc/rpchandlers/submit_block.go | 2 +- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/appmessage/rpc_get_block.go b/app/appmessage/rpc_get_block.go index 4e57406c5..91403402b 100644 --- a/app/appmessage/rpc_get_block.go +++ b/app/appmessage/rpc_get_block.go @@ -58,6 +58,7 @@ type BlockVerboseData struct { Difficulty float64 ParentHashes []string SelectedParentHash string + BlueScore uint64 } // TransactionVerboseData holds verbose data about a transaction diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 08010e623..896059432 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -13,6 +13,8 @@ func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { orphanHash := consensusserialization.BlockHash(orphanBlock) f.orphans[*orphanHash] = orphanBlock + + log.Infof("Received a block with missing parents, adding to orphan pool: %s", orphanHash) } // UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore. diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 09cedc656..3f10eff38 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -249,6 +249,8 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS return err } + log.Infof("Accepted block %s via relay", blockHash) + err = flow.StartIBDIfRequired() if err != nil { return err diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index c286d7d72..ad6dbd775 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -3,6 +3,7 @@ package rpccontext import ( "encoding/hex" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" "math/big" "strconv" @@ -25,6 +26,11 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ hash := consensusserialization.BlockHash(block) blockHeader := block.Header + blueScore, err := blocks.ExtractBlueScore(block) + if err != nil { + return nil, err + } + result := &appmessage.BlockVerboseData{ Hash: hash.String(), Version: blockHeader.Version, @@ -37,6 +43,7 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ Time: blockHeader.TimeInMilliseconds, Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits, ctx.Config.ActiveNetParams), + BlueScore: blueScore, } txIDs := make([]string, len(block.Transactions)) diff --git a/app/rpc/rpchandlers/submit_block.go b/app/rpc/rpchandlers/submit_block.go index 728a099af..eca17c389 100644 --- a/app/rpc/rpchandlers/submit_block.go +++ b/app/rpc/rpchandlers/submit_block.go @@ -21,7 +21,7 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap return errorMessage, nil } - log.Infof("Accepted domainBlock %s via submitBlock", consensusserialization.BlockHash(domainBlock)) + log.Infof("Accepted block %s via submitBlock", consensusserialization.BlockHash(domainBlock)) response := appmessage.NewSubmitBlockResponseMessage() return response, nil From 75d21d39ccf68fa62cba9e8e1e85c6267d7ec7cd Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 18 Nov 2020 12:19:30 +0200 Subject: [PATCH 070/351] [NOD-1549] Properly handle errors in unorphanBlock (#1107) * [NOD-1549] In AddBlock, simply log RuleErrors. * [NOD-1549] Properly handle errors in unorphanBlock. --- app/protocol/flowcontext/blocks.go | 6 ++++++ app/protocol/flowcontext/orphans.go | 16 +++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 7f5036d4a..ca92e2db5 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -2,6 +2,8 @@ package flowcontext import ( "github.com/kaspanet/kaspad/app/protocol/blocklogger" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/pkg/errors" "sync/atomic" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -81,6 +83,10 @@ func (f *FlowContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { err := f.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { + if errors.As(err, &ruleerrors.RuleError{}) { + log.Infof("Validation failed for block %s: %s", consensusserialization.BlockHash(block), err) + return nil + } return err } err = f.OnNewBlock(block) diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 896059432..f0e2e4e96 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -2,6 +2,7 @@ package flowcontext import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/pkg/errors" ) @@ -104,12 +105,17 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) error { if !ok { return errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash) } - err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock) - if err != nil { - return err - } delete(f.orphans, orphanHash) - log.Debugf("Unorphaned block %s", orphanHash) + 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) + return nil + } + return err + } + + log.Infof("Unorphaned block %s", orphanHash) return nil } From ed386bbc8f67b1ebfa0be376ea712d8cee68ff02 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 18 Nov 2020 13:37:14 +0200 Subject: [PATCH 071/351] [NOD-1550] Don't request blocks for invs that are known to be orphans (#1108) * [NOD-1550] Implement IsOrphan(). * [NOD-1550] Don't request blocks for invs that are known to be orphans. --- app/protocol/flowcontext/flow_context.go | 2 +- app/protocol/flowcontext/ibd.go | 6 +++++- app/protocol/flowcontext/orphans.go | 9 +++++++++ app/protocol/flows/blockrelay/handle_relay_invs.go | 5 +++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index a8cd7d24c..c88906a02 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -53,7 +53,7 @@ type FlowContext struct { peersMutex sync.RWMutex orphans map[externalapi.DomainHash]*externalapi.DomainBlock - orphansMutex sync.Mutex + orphansMutex sync.RWMutex } // New returns a new instance of FlowContext. diff --git a/app/protocol/flowcontext/ibd.go b/app/protocol/flowcontext/ibd.go index fd2a038ba..e7d8a7b92 100644 --- a/app/protocol/flowcontext/ibd.go +++ b/app/protocol/flowcontext/ibd.go @@ -58,11 +58,15 @@ func (f *FlowContext) selectPeerForIBD(syncInfo *externalapi.SyncInfo) (*peerpkg for _, peer := range f.peers { peerSelectedTipHash := peer.SelectedTipHash() + + if f.IsOrphan(peerSelectedTipHash) { + continue + } + blockInfo, err := f.domain.Consensus().GetBlockInfo(peerSelectedTipHash) if err != nil { return nil, err } - if syncInfo.State == externalapi.SyncStateHeadersFirst { if !blockInfo.Exists { return peer, nil diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index f0e2e4e96..5411dfb39 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -18,6 +18,15 @@ func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { log.Infof("Received a block with missing parents, adding to orphan pool: %s", orphanHash) } +// IsOrphan returns whether the given blockHash belongs to an orphan block +func (f *FlowContext) IsOrphan(blockHash *externalapi.DomainHash) bool { + f.orphansMutex.RLock() + defer f.orphansMutex.RUnlock() + + _, ok := f.orphans[*blockHash] + return ok +} + // UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore. func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*externalapi.DomainBlock, error) { f.orphansMutex.Lock() diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 3f10eff38..ed354f149 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -26,6 +26,7 @@ type RelayInvsContext interface { IsInIBD() bool Broadcast(message appmessage.Message) error AddOrphan(orphanBlock *externalapi.DomainBlock) + IsOrphan(blockHash *externalapi.DomainHash) bool } type handleRelayInvsFlow struct { @@ -71,6 +72,10 @@ func (flow *handleRelayInvsFlow) start() error { continue } + if flow.IsOrphan(inv.Hash) { + continue + } + err = flow.StartIBDIfRequired() if err != nil { return err From bb244706eadc8ad01455bb02fda51a7cfd62e7e1 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 18 Nov 2020 16:35:32 +0200 Subject: [PATCH 072/351] [NOD-1543] Optimize the performance of Count() in BlockHeaderStore and BlockStore (#1109) * [NOD-1543] Optimize Count() in BlockHeaderStore. * [NOD-1543] Optimize Count() in BlockStore. * [NOD-1543] Fix commitCount. * [NOD-1543] Explicitly initialize count to 0. --- .../database/serialization/dbobjects.pb.go | 137 +++++++++++- .../database/serialization/dbobjects.proto | 8 + .../blockheaderstore/blockheaderstore.go | 206 +++++++++++------- .../datastructures/blockstore/blockstore.go | 206 +++++++++++------- domain/consensus/factory.go | 14 +- ...terface_datastructures_blockheaderstore.go | 2 +- .../interface_datastructures_blockstore.go | 2 +- .../processes/syncmanager/syncinfo.go | 18 +- 8 files changed, 417 insertions(+), 176 deletions(-) diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index a451cc051..fa19c7c1e 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -1629,6 +1629,100 @@ func (x *DbVirtualDiffParents) GetVirtualDiffParents() []*DbHash { return nil } +type DbBlockCount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Count uint64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` +} + +func (x *DbBlockCount) Reset() { + *x = DbBlockCount{} + if protoimpl.UnsafeEnabled { + mi := &file_dbobjects_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DbBlockCount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DbBlockCount) ProtoMessage() {} + +func (x *DbBlockCount) ProtoReflect() protoreflect.Message { + mi := &file_dbobjects_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DbBlockCount.ProtoReflect.Descriptor instead. +func (*DbBlockCount) Descriptor() ([]byte, []int) { + return file_dbobjects_proto_rawDescGZIP(), []int{28} +} + +func (x *DbBlockCount) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +type DbBlockHeaderCount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Count uint64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` +} + +func (x *DbBlockHeaderCount) Reset() { + *x = DbBlockHeaderCount{} + if protoimpl.UnsafeEnabled { + mi := &file_dbobjects_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DbBlockHeaderCount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DbBlockHeaderCount) ProtoMessage() {} + +func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { + mi := &file_dbobjects_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DbBlockHeaderCount.ProtoReflect.Descriptor instead. +func (*DbBlockHeaderCount) Descriptor() ([]byte, []int) { + return file_dbobjects_proto_rawDescGZIP(), []int{29} +} + +func (x *DbBlockHeaderCount) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + var File_dbobjects_proto protoreflect.FileDescriptor var file_dbobjects_proto_rawDesc = []byte{ @@ -1858,10 +1952,15 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x73, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1876,7 +1975,7 @@ func file_dbobjects_proto_rawDescGZIP() []byte { return file_dbobjects_proto_rawDescData } -var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 30) var file_dbobjects_proto_goTypes = []interface{}{ (*DbBlock)(nil), // 0: serialization.DbBlock (*DbBlockHeader)(nil), // 1: serialization.DbBlockHeader @@ -1906,6 +2005,8 @@ var file_dbobjects_proto_goTypes = []interface{}{ (*DbHeaderTips)(nil), // 25: serialization.DbHeaderTips (*DbTips)(nil), // 26: serialization.DbTips (*DbVirtualDiffParents)(nil), // 27: serialization.DbVirtualDiffParents + (*DbBlockCount)(nil), // 28: serialization.DbBlockCount + (*DbBlockHeaderCount)(nil), // 29: serialization.DbBlockHeaderCount } var file_dbobjects_proto_depIdxs = []int32{ 1, // 0: serialization.DbBlock.header:type_name -> serialization.DbBlockHeader @@ -2292,6 +2393,30 @@ func file_dbobjects_proto_init() { return nil } } + file_dbobjects_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DbBlockCount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dbobjects_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DbBlockHeaderCount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -2299,7 +2424,7 @@ func file_dbobjects_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_dbobjects_proto_rawDesc, NumEnums: 0, - NumMessages: 28, + NumMessages: 30, NumExtensions: 0, NumServices: 0, }, diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 79c811228..65a84bcb7 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -150,3 +150,11 @@ message DbTips { message DbVirtualDiffParents { repeated DbHash virtualDiffParents = 1; } + +message DbBlockCount { + uint64 count = 1; +} + +message DbBlockHeaderCount { + uint64 count = 1; +} diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index 3869ed443..27e08451c 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -9,85 +9,119 @@ import ( ) var bucket = dbkeys.MakeBucket([]byte("block-headers")) +var countKey = dbkeys.MakeBucket().Key([]byte("block-headers-count")) // blockHeaderStore represents a store of blocks type blockHeaderStore struct { staging map[externalapi.DomainHash]*externalapi.DomainBlockHeader toDelete map[externalapi.DomainHash]struct{} + count uint64 } // New instantiates a new BlockHeaderStore -func New() model.BlockHeaderStore { - return &blockHeaderStore{ +func New(dbContext model.DBReader) (model.BlockHeaderStore, error) { + blockHeaderStore := &blockHeaderStore{ staging: make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader), toDelete: make(map[externalapi.DomainHash]struct{}), } -} -// Stage stages the given block header for the given blockHash -func (bms *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error { - clone, err := bms.cloneHeader(blockHeader) - if err != nil { - return err - } - - bms.staging[*blockHash] = clone - return nil -} - -func (bms *blockHeaderStore) IsStaged() bool { - return len(bms.staging) != 0 || len(bms.toDelete) != 0 -} - -func (bms *blockHeaderStore) Discard() { - bms.staging = make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader) - bms.toDelete = make(map[externalapi.DomainHash]struct{}) -} - -func (bms *blockHeaderStore) Commit(dbTx model.DBTransaction) error { - for hash, header := range bms.staging { - headerBytes, err := bms.serializeHeader(header) - if err != nil { - return err - } - err = dbTx.Put(bms.hashAsKey(&hash), headerBytes) - if err != nil { - return err - } - } - - for hash := range bms.toDelete { - err := dbTx.Delete(bms.hashAsKey(&hash)) - if err != nil { - return err - } - } - - bms.Discard() - return nil -} - -// BlockHeader gets the block header associated with the given blockHash -func (bms *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { - if header, ok := bms.staging[*blockHash]; ok { - return header, nil - } - - headerBytes, err := dbContext.Get(bms.hashAsKey(blockHash)) + err := blockHeaderStore.initializeCount(dbContext) if err != nil { return nil, err } - return bms.deserializeHeader(headerBytes) + return blockHeaderStore, nil +} + +func (bhs *blockHeaderStore) initializeCount(dbContext model.DBReader) error { + count := uint64(0) + hasCountBytes, err := dbContext.Has(countKey) + if err != nil { + return err + } + if hasCountBytes { + countBytes, err := dbContext.Get(countKey) + if err != nil { + return err + } + count, err = bhs.deserializeHeaderCount(countBytes) + if err != nil { + return err + } + } + bhs.count = count + return nil +} + +// Stage stages the given block header for the given blockHash +func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error { + clone, err := bhs.cloneHeader(blockHeader) + if err != nil { + return err + } + + bhs.staging[*blockHash] = clone + return nil +} + +func (bhs *blockHeaderStore) IsStaged() bool { + return len(bhs.staging) != 0 || len(bhs.toDelete) != 0 +} + +func (bhs *blockHeaderStore) Discard() { + bhs.staging = make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader) + bhs.toDelete = make(map[externalapi.DomainHash]struct{}) +} + +func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error { + for hash, header := range bhs.staging { + headerBytes, err := bhs.serializeHeader(header) + if err != nil { + return err + } + err = dbTx.Put(bhs.hashAsKey(&hash), headerBytes) + if err != nil { + return err + } + } + + for hash := range bhs.toDelete { + err := dbTx.Delete(bhs.hashAsKey(&hash)) + if err != nil { + return err + } + } + + err := bhs.commitCount(dbTx) + if err != nil { + return err + } + + bhs.Discard() + return nil +} + +// BlockHeader gets the block header associated with the given blockHash +func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { + if header, ok := bhs.staging[*blockHash]; ok { + return header, nil + } + + headerBytes, err := dbContext.Get(bhs.hashAsKey(blockHash)) + if err != nil { + return nil, err + } + + return bhs.deserializeHeader(headerBytes) } // HasBlock returns whether a block header with a given hash exists in the store. -func (bms *blockHeaderStore) HasBlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { - if _, ok := bms.staging[*blockHash]; ok { +func (bhs *blockHeaderStore) HasBlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { + if _, ok := bhs.staging[*blockHash]; ok { return true, nil } - exists, err := dbContext.Has(bms.hashAsKey(blockHash)) + exists, err := dbContext.Has(bhs.hashAsKey(blockHash)) if err != nil { return false, err } @@ -96,11 +130,11 @@ func (bms *blockHeaderStore) HasBlockHeader(dbContext model.DBReader, blockHash } // BlockHeaders gets the block headers associated with the given blockHashes -func (bms *blockHeaderStore) BlockHeaders(dbContext model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) { +func (bhs *blockHeaderStore) BlockHeaders(dbContext model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) { headers := make([]*externalapi.DomainBlockHeader, len(blockHashes)) for i, hash := range blockHashes { var err error - headers[i], err = bms.BlockHeader(dbContext, hash) + headers[i], err = bhs.BlockHeader(dbContext, hash) if err != nil { return nil, err } @@ -109,24 +143,24 @@ func (bms *blockHeaderStore) BlockHeaders(dbContext model.DBReader, blockHashes } // Delete deletes the block associated with the given blockHash -func (bms *blockHeaderStore) Delete(blockHash *externalapi.DomainHash) { - if _, ok := bms.staging[*blockHash]; ok { - delete(bms.staging, *blockHash) +func (bhs *blockHeaderStore) Delete(blockHash *externalapi.DomainHash) { + if _, ok := bhs.staging[*blockHash]; ok { + delete(bhs.staging, *blockHash) return } - bms.toDelete[*blockHash] = struct{}{} + bhs.toDelete[*blockHash] = struct{}{} } -func (bms *blockHeaderStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { +func (bhs *blockHeaderStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } -func (bms *blockHeaderStore) serializeHeader(header *externalapi.DomainBlockHeader) ([]byte, error) { +func (bhs *blockHeaderStore) serializeHeader(header *externalapi.DomainBlockHeader) ([]byte, error) { dbBlockHeader := serialization.DomainBlockHeaderToDbBlockHeader(header) return proto.Marshal(dbBlockHeader) } -func (bms *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi.DomainBlockHeader, error) { +func (bhs *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi.DomainBlockHeader, error) { dbBlockHeader := &serialization.DbBlockHeader{} err := proto.Unmarshal(headerBytes, dbBlockHeader) if err != nil { @@ -135,23 +169,43 @@ func (bms *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi return serialization.DbBlockHeaderToDomainBlockHeader(dbBlockHeader) } -func (bms *blockHeaderStore) cloneHeader(header *externalapi.DomainBlockHeader) (*externalapi.DomainBlockHeader, error) { - serialized, err := bms.serializeHeader(header) +func (bhs *blockHeaderStore) cloneHeader(header *externalapi.DomainBlockHeader) (*externalapi.DomainBlockHeader, error) { + serialized, err := bhs.serializeHeader(header) if err != nil { return nil, err } - return bms.deserializeHeader(serialized) + return bhs.deserializeHeader(serialized) } -func (bms *blockHeaderStore) Count(dbContext model.DBReader) (uint64, error) { - cursor, err := dbContext.Cursor(bucket) +func (bhs *blockHeaderStore) Count() uint64 { + return bhs.count + uint64(len(bhs.staging)) - uint64(len(bhs.toDelete)) +} + +func (bhs *blockHeaderStore) deserializeHeaderCount(countBytes []byte) (uint64, error) { + dbBlockHeaderCount := &serialization.DbBlockHeaderCount{} + err := proto.Unmarshal(countBytes, dbBlockHeaderCount) if err != nil { return 0, err } - count := uint64(0) - for cursor.Next() { - count++ - } - return count, nil + return dbBlockHeaderCount.Count, nil +} + +func (bhs *blockHeaderStore) commitCount(dbTx model.DBTransaction) error { + count := bhs.Count() + countBytes, err := bhs.serializeHeaderCount(count) + if err != nil { + return err + } + err = dbTx.Put(countKey, countBytes) + if err != nil { + return err + } + bhs.count = count + return nil +} + +func (bhs *blockHeaderStore) serializeHeaderCount(count uint64) ([]byte, error) { + dbBlockHeaderCount := &serialization.DbBlockHeaderCount{Count: count} + return proto.Marshal(dbBlockHeaderCount) } diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index e7619c6cd..6824e11d8 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -9,85 +9,119 @@ import ( ) var bucket = dbkeys.MakeBucket([]byte("blocks")) +var countKey = dbkeys.MakeBucket().Key([]byte("blocks-count")) // blockStore represents a store of blocks type blockStore struct { staging map[externalapi.DomainHash]*externalapi.DomainBlock toDelete map[externalapi.DomainHash]struct{} + count uint64 } // New instantiates a new BlockStore -func New() model.BlockStore { - return &blockStore{ +func New(dbContext model.DBReader) (model.BlockStore, error) { + blockStore := &blockStore{ staging: make(map[externalapi.DomainHash]*externalapi.DomainBlock), toDelete: make(map[externalapi.DomainHash]struct{}), } -} -// Stage stages the given block for the given blockHash -func (bms *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error { - clone, err := bms.clone(block) - if err != nil { - return err - } - - bms.staging[*blockHash] = clone - return nil -} - -func (bms *blockStore) IsStaged() bool { - return len(bms.staging) != 0 || len(bms.toDelete) != 0 -} - -func (bms *blockStore) Discard() { - bms.staging = make(map[externalapi.DomainHash]*externalapi.DomainBlock) - bms.toDelete = make(map[externalapi.DomainHash]struct{}) -} - -func (bms *blockStore) Commit(dbTx model.DBTransaction) error { - for hash, block := range bms.staging { - blockBytes, err := bms.serializeBlock(block) - if err != nil { - return err - } - err = dbTx.Put(bms.hashAsKey(&hash), blockBytes) - if err != nil { - return err - } - } - - for hash := range bms.toDelete { - err := dbTx.Delete(bms.hashAsKey(&hash)) - if err != nil { - return err - } - } - - bms.Discard() - return nil -} - -// Block gets the block associated with the given blockHash -func (bms *blockStore) Block(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { - if block, ok := bms.staging[*blockHash]; ok { - return block, nil - } - - blockBytes, err := dbContext.Get(bms.hashAsKey(blockHash)) + err := blockStore.initializeCount(dbContext) if err != nil { return nil, err } - return bms.deserializeBlock(blockBytes) + return blockStore, nil +} + +func (bs *blockStore) initializeCount(dbContext model.DBReader) error { + count := uint64(0) + hasCountBytes, err := dbContext.Has(countKey) + if err != nil { + return err + } + if hasCountBytes { + countBytes, err := dbContext.Get(countKey) + if err != nil { + return err + } + count, err = bs.deserializeBlockCount(countBytes) + if err != nil { + return err + } + } + bs.count = count + return nil +} + +// Stage stages the given block for the given blockHash +func (bs *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error { + clone, err := bs.clone(block) + if err != nil { + return err + } + + bs.staging[*blockHash] = clone + return nil +} + +func (bs *blockStore) IsStaged() bool { + return len(bs.staging) != 0 || len(bs.toDelete) != 0 +} + +func (bs *blockStore) Discard() { + bs.staging = make(map[externalapi.DomainHash]*externalapi.DomainBlock) + bs.toDelete = make(map[externalapi.DomainHash]struct{}) +} + +func (bs *blockStore) Commit(dbTx model.DBTransaction) error { + for hash, block := range bs.staging { + blockBytes, err := bs.serializeBlock(block) + if err != nil { + return err + } + err = dbTx.Put(bs.hashAsKey(&hash), blockBytes) + if err != nil { + return err + } + } + + for hash := range bs.toDelete { + err := dbTx.Delete(bs.hashAsKey(&hash)) + if err != nil { + return err + } + } + + err := bs.commitCount(dbTx) + if err != nil { + return err + } + + bs.Discard() + return nil +} + +// Block gets the block associated with the given blockHash +func (bs *blockStore) Block(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { + if block, ok := bs.staging[*blockHash]; ok { + return block, nil + } + + blockBytes, err := dbContext.Get(bs.hashAsKey(blockHash)) + if err != nil { + return nil, err + } + + return bs.deserializeBlock(blockBytes) } // HasBlock returns whether a block with a given hash exists in the store. -func (bms *blockStore) HasBlock(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { - if _, ok := bms.staging[*blockHash]; ok { +func (bs *blockStore) HasBlock(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { + if _, ok := bs.staging[*blockHash]; ok { return true, nil } - exists, err := dbContext.Has(bms.hashAsKey(blockHash)) + exists, err := dbContext.Has(bs.hashAsKey(blockHash)) if err != nil { return false, err } @@ -96,11 +130,11 @@ func (bms *blockStore) HasBlock(dbContext model.DBReader, blockHash *externalapi } // Blocks gets the blocks associated with the given blockHashes -func (bms *blockStore) Blocks(dbContext model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlock, error) { +func (bs *blockStore) Blocks(dbContext model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlock, error) { blocks := make([]*externalapi.DomainBlock, len(blockHashes)) for i, hash := range blockHashes { var err error - blocks[i], err = bms.Block(dbContext, hash) + blocks[i], err = bs.Block(dbContext, hash) if err != nil { return nil, err } @@ -109,20 +143,20 @@ func (bms *blockStore) Blocks(dbContext model.DBReader, blockHashes []*externala } // Delete deletes the block associated with the given blockHash -func (bms *blockStore) Delete(blockHash *externalapi.DomainHash) { - if _, ok := bms.staging[*blockHash]; ok { - delete(bms.staging, *blockHash) +func (bs *blockStore) Delete(blockHash *externalapi.DomainHash) { + if _, ok := bs.staging[*blockHash]; ok { + delete(bs.staging, *blockHash) return } - bms.toDelete[*blockHash] = struct{}{} + bs.toDelete[*blockHash] = struct{}{} } -func (bms *blockStore) serializeBlock(block *externalapi.DomainBlock) ([]byte, error) { +func (bs *blockStore) serializeBlock(block *externalapi.DomainBlock) ([]byte, error) { dbBlock := serialization.DomainBlockToDbBlock(block) return proto.Marshal(dbBlock) } -func (bms *blockStore) deserializeBlock(blockBytes []byte) (*externalapi.DomainBlock, error) { +func (bs *blockStore) deserializeBlock(blockBytes []byte) (*externalapi.DomainBlock, error) { dbBlock := &serialization.DbBlock{} err := proto.Unmarshal(blockBytes, dbBlock) if err != nil { @@ -131,27 +165,47 @@ func (bms *blockStore) deserializeBlock(blockBytes []byte) (*externalapi.DomainB return serialization.DbBlockToDomainBlock(dbBlock) } -func (bms *blockStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { +func (bs *blockStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } -func (bms *blockStore) clone(block *externalapi.DomainBlock) (*externalapi.DomainBlock, error) { - serialized, err := bms.serializeBlock(block) +func (bs *blockStore) clone(block *externalapi.DomainBlock) (*externalapi.DomainBlock, error) { + serialized, err := bs.serializeBlock(block) if err != nil { return nil, err } - return bms.deserializeBlock(serialized) + return bs.deserializeBlock(serialized) } -func (bms *blockStore) Count(dbContext model.DBReader) (uint64, error) { - cursor, err := dbContext.Cursor(bucket) +func (bs *blockStore) Count() uint64 { + return bs.count + uint64(len(bs.staging)) - uint64(len(bs.toDelete)) +} + +func (bs *blockStore) deserializeBlockCount(countBytes []byte) (uint64, error) { + dbBlockCount := &serialization.DbBlockCount{} + err := proto.Unmarshal(countBytes, dbBlockCount) if err != nil { return 0, err } - count := uint64(0) - for cursor.Next() { - count++ - } - return count, nil + return dbBlockCount.Count, nil +} + +func (bs *blockStore) commitCount(dbTx model.DBTransaction) error { + count := bs.Count() + countBytes, err := bs.serializeBlockCount(count) + if err != nil { + return err + } + err = dbTx.Put(countKey, countBytes) + if err != nil { + return err + } + bs.count = count + return nil +} + +func (bs *blockStore) serializeBlockCount(count uint64) ([]byte, error) { + dbBlockCount := &serialization.DbBlockCount{Count: count} + return proto.Marshal(dbBlockCount) } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 446b4b6e8..5ea856d72 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -59,10 +59,18 @@ func NewFactory() Factory { // NewConsensus instantiates a new Consensus func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) { + dbManager := consensusdatabase.New(db) + // Data Structures acceptanceDataStore := acceptancedatastore.New() - blockStore := blockstore.New() - blockHeaderStore := blockheaderstore.New() + blockStore, err := blockstore.New(dbManager) + if err != nil { + return nil, err + } + blockHeaderStore, err := blockheaderstore.New(dbManager) + if err != nil { + return nil, err + } blockRelationStore := blockrelationstore.New() blockStatusStore := blockstatusstore.New() multisetStore := multisetstore.New() @@ -73,8 +81,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore := ghostdagdatastore.New() headerTipsStore := headertipsstore.New() - dbManager := consensusdatabase.New(db) - // Processes reachabilityManager := reachabilitymanager.New( dbManager, diff --git a/domain/consensus/model/interface_datastructures_blockheaderstore.go b/domain/consensus/model/interface_datastructures_blockheaderstore.go index adbe97b5d..e6d5be9b0 100644 --- a/domain/consensus/model/interface_datastructures_blockheaderstore.go +++ b/domain/consensus/model/interface_datastructures_blockheaderstore.go @@ -11,5 +11,5 @@ type BlockHeaderStore interface { HasBlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) BlockHeaders(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) Delete(blockHash *externalapi.DomainHash) - Count(dbContext DBReader) (uint64, error) + Count() uint64 } diff --git a/domain/consensus/model/interface_datastructures_blockstore.go b/domain/consensus/model/interface_datastructures_blockstore.go index 4c36ed3be..0ebc8dc69 100644 --- a/domain/consensus/model/interface_datastructures_blockstore.go +++ b/domain/consensus/model/interface_datastructures_blockstore.go @@ -11,5 +11,5 @@ type BlockStore interface { HasBlock(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) Blocks(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlock, error) Delete(blockHash *externalapi.DomainHash) - Count(dbContext DBReader) (uint64, error) + Count() uint64 } diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 02990d9af..1680721a8 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -25,14 +25,8 @@ func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { } } - headerCount, err := sm.getHeaderCount() - if err != nil { - return nil, err - } - blockCount, err := sm.getBlockCount() - if err != nil { - return nil, err - } + headerCount := sm.getHeaderCount() + blockCount := sm.getBlockCount() return &externalapi.SyncInfo{ State: syncState, @@ -123,10 +117,10 @@ func (sm *syncManager) areHeaderTipsSynced(headerVirtualSelectedParentHash *exte return timeDifference <= maxTimeDifference, nil } -func (sm *syncManager) getHeaderCount() (uint64, error) { - return sm.blockHeaderStore.Count(sm.databaseContext) +func (sm *syncManager) getHeaderCount() uint64 { + return sm.blockHeaderStore.Count() } -func (sm *syncManager) getBlockCount() (uint64, error) { - return sm.blockStore.Count(sm.databaseContext) +func (sm *syncManager) getBlockCount() uint64 { + return sm.blockStore.Count() } From 950dd0cc8dd74d718261c33b55d866ee82afac26 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 19 Nov 2020 11:17:05 +0200 Subject: [PATCH 073/351] [NOD-1556] Add some logs (#1110) * [NOD-1556] Add logs regarding block status and virtual blue score * [NOD-1556] UTXODiffAlgebra: add the offending outpoint to the text of errors * [NOD-1556] Make checkIntersectionWithRule return ok as well --- .../blockprocessor/validateandinsertblock.go | 7 +++ .../add_block_to_virtual.go | 3 ++ .../resolve_block_status.go | 1 + .../utxoalgebra/diff_algebra.go | 44 ++++++++++--------- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 01971331e..d7c4c5c00 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -1,6 +1,7 @@ package blockprocessor 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/consensusserialization" @@ -155,6 +156,12 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } log.Debugf("Block %s validated and inserted", hash) + virtualGhostDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash) + if err != nil { + return err + } + log.Debugf("New virtual's blue score: %d", virtualGhostDAGData.BlueScore) + return nil } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 3f9c80269..b55d04f3e 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -26,6 +26,9 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai return err } } + } else { + log.Debugf("Block %s is not next virtual selected parent. Therefore leaving him with status `%s`", + blockHash, externalapi.StatusUTXOPendingVerification) } newTips, err := csm.addTip(blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index ea2a8152d..2b5d993e4 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -42,6 +42,7 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma csm.blockStatusStore.Stage(unverifiedBlockHash, blockStatus) selectedParentStatus = blockStatus + log.Debugf("Block %s status resolved to `%s`", unverifiedBlockHash, blockStatus) } return blockStatus, nil diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go index bf534c3cb..58bb13f81 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go +++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go @@ -18,18 +18,21 @@ func checkIntersection(collection1 model.UTXOCollection, collection2 model.UTXOC } // checkIntersectionWithRule checks if there is an intersection between two model.UTXOCollections satisfying arbitrary rule +// returns the first outpoint in the two collections' intersection satsifying the rule, and a boolean indicating whether +// such outpoint exists func checkIntersectionWithRule(collection1 model.UTXOCollection, collection2 model.UTXOCollection, - extraRule func(*externalapi.DomainOutpoint, *externalapi.UTXOEntry, *externalapi.UTXOEntry) bool) bool { + extraRule func(*externalapi.DomainOutpoint, *externalapi.UTXOEntry, *externalapi.UTXOEntry) bool) ( + *externalapi.DomainOutpoint, bool) { for outpoint, utxoEntry := range collection1 { if diffEntry, ok := CollectionGet(collection2, &outpoint); ok { if extraRule(&outpoint, utxoEntry, diffEntry) { - return true + return &outpoint, true } } } - return false + return nil, false } // minInt returns the smaller of x or y integer values @@ -143,8 +146,9 @@ func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { collectionContainsWithBlueScore(other.ToRemove, outpoint, utxoEntry.BlockBlueScore))) } - if checkIntersectionWithRule(this.ToRemove, other.ToAdd, isNotAddedOutputRemovedWithBlueScore) { - return nil, errors.New("diffFrom: outpoint both in this.ToAdd and in other.ToRemove") + if offendingOutpoint, ok := + checkIntersectionWithRule(this.ToRemove, other.ToAdd, isNotAddedOutputRemovedWithBlueScore); ok { + return nil, errors.Errorf("diffFrom: outpoint %s both in this.ToAdd and in other.ToRemove", offendingOutpoint) } //check that NOT (entries with unequal blue score AND utxoEntry is in this.ToRemove and/or other.ToAdd) -> Error @@ -156,18 +160,19 @@ func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { collectionContainsWithBlueScore(other.ToAdd, outpoint, utxoEntry.BlockBlueScore))) } - if checkIntersectionWithRule(this.ToAdd, other.ToRemove, isNotRemovedOutputAddedWithBlueScore) { - return nil, errors.New("diffFrom: outpoint both in this.ToRemove and in other.ToAdd") + if offendingOutpoint, ok := + checkIntersectionWithRule(this.ToAdd, other.ToRemove, isNotRemovedOutputAddedWithBlueScore); ok { + return nil, errors.Errorf("diffFrom: outpoint %s both in this.ToRemove and in other.ToAdd", offendingOutpoint) } // if have the same entry in this.ToRemove and other.ToRemove // and existing entry is with different blue score, in this case - this is an error - if checkIntersectionWithRule(this.ToRemove, other.ToRemove, + if offendingOutpoint, ok := checkIntersectionWithRule(this.ToRemove, other.ToRemove, func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry *externalapi.UTXOEntry) bool { return utxoEntry.BlockBlueScore != diffEntry.BlockBlueScore - }) { - return nil, errors.New("diffFrom: outpoint both in this.ToRemove and other.ToRemove with different " + - "blue scores, with no corresponding entry in this.ToAdd") + }); ok { + return nil, errors.Errorf("diffFrom: outpoint %s both in this.ToRemove and other.ToRemove with different "+ + "blue scores, with no corresponding entry in this.ToAdd", offendingOutpoint) } result := model.UTXODiff{ @@ -203,21 +208,20 @@ func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { // WithDiffInPlace applies provided diff to this diff in-place, that would be the result if // first d, and than diff were applied to the same base func WithDiffInPlace(this *model.UTXODiff, diff *model.UTXODiff) error { - if checkIntersectionWithRule(diff.ToRemove, this.ToRemove, + if offendingOutpoint, ok := checkIntersectionWithRule(diff.ToRemove, this.ToRemove, func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry *externalapi.UTXOEntry) bool { return !collectionContainsWithBlueScore(this.ToAdd, outpoint, entryToAdd.BlockBlueScore) - - }) { - return errors.New( - "withDiffInPlace: outpoint both in this.ToRemove and in diff.ToRemove") + }); ok { + return errors.Errorf( + "withDiffInPlace: outpoint %s both in this.ToRemove and in diff.ToRemove", offendingOutpoint) } - if checkIntersectionWithRule(diff.ToAdd, this.ToAdd, + if offendingOutpoint, ok := checkIntersectionWithRule(diff.ToAdd, this.ToAdd, func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry *externalapi.UTXOEntry) bool { return !collectionContainsWithBlueScore(diff.ToRemove, outpoint, existingEntry.BlockBlueScore) - }) { - return errors.New( - "withDiffInPlace: outpoint both in this.ToAdd and in diff.ToAdd") + }); ok { + return errors.Errorf( + "withDiffInPlace: outpoint %s both in this.ToAdd and in diff.ToAdd", offendingOutpoint) } intersection := make(model.UTXOCollection, minInt(len(diff.ToRemove), len(this.ToAdd))) From b3a3121725da3a063e76d418c30a6ec39bb351eb Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 22 Nov 2020 12:30:27 +0200 Subject: [PATCH 074/351] Add TestFinality back (#1129) * Add VirtualFinalityPoint to TestConsensusStateManager * Add TestFinality back --- domain/consensus/finality_test.go | 169 ++++++++++++++++++ ...terface_processes_consensusstatemanager.go | 1 + .../test_consensus_state_manager.go | 4 + 3 files changed, 174 insertions(+) create mode 100644 domain/consensus/finality_test.go diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go new file mode 100644 index 000000000..24af2edb9 --- /dev/null +++ b/domain/consensus/finality_test.go @@ -0,0 +1,169 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + + "testing" +) + +func TestFinality(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // Set finalityInterval to 50 blocks, so that test runs quickly + params.FinalityDuration = 50 * params.TargetTimePerBlock + + factory := NewFactory() + consensus, teardown, err := factory.NewTestConsensus(params, "TestFinality") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + buildAndInsertBlock := func(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) { + block, err := consensus.BuildBlockWithParents(parentHashes, nil, nil) + if err != nil { + return nil, err + } + + err = consensus.ValidateAndInsertBlock(block) + if err != nil { + return nil, err + } + return block, nil + } + + // Build a chain of `finalityInterval - 1` blocks + finalityInterval := params.FinalityDepth() + var mainChainTip *externalapi.DomainBlock + mainChainTipHash := params.GenesisHash + + for i := uint64(0); i < finalityInterval-1; i++ { + mainChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{mainChainTipHash}) + if err != nil { + t.Fatalf("TestFinality: Failed to process Block #%d: %v", i, err) + } + mainChainTipHash = consensusserialization.BlockHash(mainChainTip) + + blockInfo, err := consensus.GetBlockInfo(mainChainTipHash) + if err != nil { + t.Fatalf("TestFinality: Block #%d failed to get info: %v", i, err) + } + if blockInfo.BlockStatus != externalapi.StatusValid { + t.Fatalf("Block #%d in main chain expected to have status '%s', but got '%s'", + i, externalapi.StatusValid, blockInfo.BlockStatus) + } + } + + // Mine another chain of `finality-Interval - 2` blocks + var sideChainTip *externalapi.DomainBlock + sideChainTipHash := params.GenesisHash + for i := uint64(0); i < finalityInterval-2; i++ { + sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash}) + if err != nil { + t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) + } + sideChainTipHash = consensusserialization.BlockHash(sideChainTip) + + blockInfo, err := consensus.GetBlockInfo(sideChainTipHash) + if err != nil { + t.Fatalf("TestFinality: Block #%d failed to get info: %v", i, err) + } else if !blockInfo.Exists { + t.Fatalf("TestFinality: Failed getting block info, doesn't exists") + } + if blockInfo.BlockStatus != externalapi.StatusUTXOPendingVerification { + t.Fatalf("Block #%d in side chain expected to have status '%s', but got '%s'", + i, externalapi.StatusUTXOPendingVerification, blockInfo.BlockStatus) + } + } + + // Add two more blocks in the side-chain until it becomes the selected chain + for i := uint64(0); i < 2; i++ { + sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash}) + if err != nil { + t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) + } + sideChainTipHash = consensusserialization.BlockHash(sideChainTip) + } + + // Make sure that now the sideChainTip is valid and selectedTip + blockInfo, err := consensus.GetBlockInfo(sideChainTipHash) + if err != nil { + t.Fatalf("TestFinality: Failed to get block info: %v", err) + } else if !blockInfo.Exists { + t.Fatalf("TestFinality: Failed getting block info, doesn't exists") + } + if blockInfo.BlockStatus != externalapi.StatusValid { + t.Fatalf("TestFinality: Overtaking block in side-chain expected to have status '%s', but got '%s'", + externalapi.StatusValid, blockInfo.BlockStatus) + } + selectedTip, err := consensus.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) + } + if *consensusserialization.BlockHash(selectedTip) != *sideChainTipHash { + t.Fatalf("Overtaking block in side-chain is not selectedTip") + } + + // Add two more blocks to main chain, to move finality point to first non-genesis block in mainChain + for i := uint64(0); i < 2; i++ { + mainChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{mainChainTipHash}) + if err != nil { + t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) + } + mainChainTipHash = consensusserialization.BlockHash(mainChainTip) + } + + virtualFinality, err := consensus.ConsensusStateManager().VirtualFinalityPoint() + if err != nil { + t.Fatalf("TestFinality: Failed getting the virtual's finality point: %v", err) + } + + if *virtualFinality == *params.GenesisHash { + t.Fatalf("virtual's finalityPoint is still genesis after adding finalityInterval + 1 blocks to the main chain") + } + + // TODO: Make sure that a finality conflict notification is sent + // Add two more blocks to the side chain, so that it violates finality and gets status UTXOPendingVerification even + // though it is the block with the highest blue score. + for i := uint64(0); i < 2; i++ { + sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash}) + if err != nil { + t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) + } + sideChainTipHash = consensusserialization.BlockHash(sideChainTip) + } + + // Check that sideChainTip hash higher blue score than the selected parent + selectedTip, err = consensus.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) + } + selectedTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), consensusserialization.BlockHash(selectedTip)) + if err != nil { + t.Fatalf("TestFinality: Failed getting the ghost dag data of the selected tip: %v", err) + } + + sideChainTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), sideChainTipHash) + if err != nil { + t.Fatalf("TestFinality: Failed getting the ghost dag data of the sidechain tip: %v", err) + } + + if selectedTipGhostDagData.BlueScore > sideChainTipGhostDagData.BlueScore { + t.Fatalf("sideChainTip is not the bluest tip when it is expected to be") + } + + // Blocks violating finality should have a UTXOPendingVerification status + blockInfo, err = consensus.GetBlockInfo(sideChainTipHash) + if err != nil { + t.Fatalf("TestFinality: Failed to get block info: %v", err) + } else if !blockInfo.Exists { + t.Fatalf("TestFinality: Failed getting block info, doesn't exists") + } + if blockInfo.BlockStatus != externalapi.StatusUTXOPendingVerification { + t.Fatalf("TestFinality: Finality violating block expected to have status '%s', but got '%s'", + externalapi.StatusUTXOPendingVerification, blockInfo.BlockStatus) + } + }) +} diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 78dc6c5d9..96105d5c7 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -18,4 +18,5 @@ type TestConsensusStateManager interface { AddUTXOToMultiset(multiset Multiset, entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) + VirtualFinalityPoint() (*externalapi.DomainHash, error) } diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go index 93750f161..e867382b3 100644 --- a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -23,3 +23,7 @@ func (csm testConsensusStateManager) AddUTXOToMultiset( func (csm testConsensusStateManager) ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { return csm.resolveBlockStatus(blockHash) } + +func (csm testConsensusStateManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) { + return csm.virtualFinalityPoint() +} From c56a5336f3db75e1013ebaaf9452bb0733611fed Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 22 Nov 2020 17:04:13 +0200 Subject: [PATCH 075/351] Re-add TestPruningDepth (#1132) --- domain/consensus/pruning_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 domain/consensus/pruning_test.go diff --git a/domain/consensus/pruning_test.go b/domain/consensus/pruning_test.go new file mode 100644 index 000000000..8ca354d82 --- /dev/null +++ b/domain/consensus/pruning_test.go @@ -0,0 +1,25 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "testing" +) + +func TestPruningDepth(t *testing.T) { + expectedResult := map[string]uint64{ + "kaspa-mainnet": 244838, + "kaspa-testnet": 244838, + "kaspa-devnet": 244838, + "kaspa-simnet": 192038, + } + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + expected, found := expectedResult[params.Name] + if !found { + t.Fatalf("TestPruningDepth: expectedResult doesn't contain '%s'", params.Name) + } + if params.PruningDepth() != expected { + t.Errorf("pruningDepth in %s is expected to be %d but got %d", params.Name, expected, params.PruningDepth()) + } + }) +} From fafe1d534f3d53bd1755d8d281a77aeeea3b985f Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 22 Nov 2020 17:17:39 +0200 Subject: [PATCH 076/351] Add TestSequenceLocksActive back (#1133) --- .../transaction_in_context_test.go | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 domain/consensus/processes/transactionvalidator/transaction_in_context_test.go diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_context_test.go new file mode 100644 index 000000000..6ef68ffa8 --- /dev/null +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context_test.go @@ -0,0 +1,44 @@ +package transactionvalidator + +import ( + "github.com/kaspanet/kaspad/util/mstime" + "testing" +) + +// TestSequenceLocksActive tests the SequenceLockActive function to ensure it +// works as expected in all possible combinations/scenarios. +func TestSequenceLocksActive(t *testing.T) { + tests := []struct { + seqLock sequenceLock + blockBlueScore uint64 + mtp mstime.Time + + want bool + }{ + // Block based sequence lock with equal block blue score. + {seqLock: sequenceLock{-1, 1000}, blockBlueScore: 1001, mtp: mstime.UnixMilliseconds(9), want: true}, + + // Time based sequence lock with mtp past the absolute time. + {seqLock: sequenceLock{30, -1}, blockBlueScore: 2, mtp: mstime.UnixMilliseconds(31), want: true}, + + // Block based sequence lock with current blue score below seq lock block blue score. + {seqLock: sequenceLock{-1, 1000}, blockBlueScore: 90, mtp: mstime.UnixMilliseconds(9), want: false}, + + // Time based sequence lock with current time before lock time. + {seqLock: sequenceLock{30, -1}, blockBlueScore: 2, mtp: mstime.UnixMilliseconds(29), want: false}, + + // Block based sequence lock at the same blue score, so shouldn't yet be active. + {seqLock: sequenceLock{-1, 1000}, blockBlueScore: 1000, mtp: mstime.UnixMilliseconds(9), want: false}, + + // Time based sequence lock with current time equal to lock time, so shouldn't yet be active. + {seqLock: sequenceLock{30, -1}, blockBlueScore: 2, mtp: mstime.UnixMilliseconds(30), want: false}, + } + + validator := transactionValidator{} + for i, test := range tests { + got := validator.sequenceLockActive(&test.seqLock, test.blockBlueScore, test.mtp.UnixMilliseconds()) + if got != test.want { + t.Fatalf("SequenceLockActive #%d got %v want %v", i, got, test.want) + } + } +} From 5211727206682ce00ccba7e669ebbbb4d0ade933 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 23 Nov 2020 13:08:10 +0200 Subject: [PATCH 077/351] [NOD-1557] Cover the consensusStateManager package in trace logs (#1135) * [NOD-1557] Add trace logs in add_block_to_virtual.go. * [NOD-1557] Add trace logs in resolve_block_status.go. * [NOD-1557] Add trace logs in calculate_past_utxo.go. * [NOD-1557] Add trace logs in finality.go. * [NOD-1557] Add trace logs in multisets.go. * [NOD-1557] Fix compilation errors. * [NOD-1557] Add trace logs to verify_and_build_utxo.go. * [NOD-1557] Add trace logs to update_virtual.go. * [NOD-1557] Add trace logs to set_pruning_utxo_set.go. * [NOD-1557] Add trace logs to populate_tx_with_utxo_entries.go. * [NOD-1557] Add trace logs to pick_virtual_parents.go. * [NOD-1557] Make go vet happy. * [NOD-1557] Clarify that some logic in AddBlockToVirtual is there for the sake of logging alone. * [NOD-1557] Call blockStatusStore directly in AddBlockToVirtual when refetching the block status. --- .../add_block_to_virtual.go | 45 ++++++++++- .../calculate_past_utxo.go | 78 +++++++++++++++++-- .../consensusstatemanager/finality.go | 25 +++++- .../consensusstatemanager/multisets.go | 23 +++++- .../pick_virtual_parents.go | 63 +++++++++++++-- .../populate_tx_with_utxo_entries.go | 16 +++- .../resolve_block_status.go | 66 ++++++++++++++-- .../set_pruning_utxo_set.go | 26 ++++++- .../consensusstatemanager/update_virtual.go | 24 ++++++ .../verify_and_build_utxo.go | 44 +++++++++++ 10 files changed, 385 insertions(+), 25 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index b55d04f3e..6eca25669 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -9,33 +9,53 @@ import ( // 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) + + log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash) isNextVirtualSelectedParent, err := csm.isNextVirtualSelectedParent(blockHash) if err != nil { return err } if isNextVirtualSelectedParent { + log.Tracef("Block %s is the new virtual. Resolving its block status", blockHash) blockStatus, err := csm.resolveBlockStatus(blockHash) if err != nil { return 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 + } } + + log.Debugf("Block %s is the next virtual selected parent. "+ + "Its resolved status is `%s`", blockHash, blockStatus) } else { - log.Debugf("Block %s is not next virtual selected parent. Therefore leaving him with status `%s`", - blockHash, externalapi.StatusUTXOPendingVerification) + log.Debugf("Block %s is not the next virtual selected parent, "+ + "therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification) } + log.Tracef("Adding block %s to the DAG tips", blockHash) newTips, err := csm.addTip(blockHash) if err != nil { return 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) if err != nil { return err @@ -45,7 +65,12 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai } 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) + if *blockHash == *csm.genesisHash { + log.Tracef("Block %s is the genesis block, therefore it is "+ + "the selected parent by definition", blockHash) return true, nil } @@ -54,30 +79,43 @@ func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externa return false, err } + log.Tracef("Selecting the next selected parent between "+ + "the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent) nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent, blockHash) if err != nil { return false, err } + log.Tracef("The next selected parent is: %s", nextVirtualSelectedParent) return *blockHash == *nextVirtualSelectedParent, nil } func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (newTips []*externalapi.DomainHash, err error) { + log.Tracef("addTip start for new tip %s", newTipHash) + defer log.Tracef("addTip end for new tip %s", newTipHash) + + log.Tracef("Calculating the new tips for new tip %s", newTipHash) newTips, err = csm.calculateNewTips(newTipHash) if err != nil { return nil, err } + log.Tracef("The new tips are: %s", newTips) err = csm.consensusStateStore.StageTips(newTips) if err != nil { return nil, err } + log.Tracef("Staged the new tips %s", newTips) return newTips, nil } func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + log.Tracef("calculateNewTips start for new tip %s", newTipHash) + defer log.Tracef("calculateNewTips end for new tip %s", newTipHash) + if *newTipHash == *csm.genesisHash { + log.Tracef("The new tip is the genesis block, therefore it is the only tip by definition") return []*externalapi.DomainHash{newTipHash}, nil } @@ -85,11 +123,13 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai if err != nil { return nil, err } + log.Tracef("The current tips are: %s", currentTips) newTipParents, err := csm.dagTopologyManager.Parents(newTipHash) if err != nil { return nil, err } + log.Tracef("The parents of the new tip are: %s", newTipParents) newTips := []*externalapi.DomainHash{newTipHash} @@ -105,6 +145,7 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai newTips = append(newTips, currentTip) } } + log.Tracef("The calculated new tips are: %s", newTips) return newTips, nil } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 417468732..c2e2ffdba 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -1,6 +1,7 @@ package consensusstatemanager import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" "github.com/pkg/errors" @@ -15,8 +16,12 @@ import ( func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( *model.UTXODiff, model.AcceptanceData, model.Multiset, error) { - // The genesis block has an empty UTXO diff, empty acceptance data, and a blank multiset + log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) + defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) + if *blockHash == *csm.genesisHash { + log.Tracef("Block %s is the genesis. By definition, "+ + "it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash) return &model.UTXODiff{}, model.AcceptanceData{}, multiset.New(), nil } @@ -24,40 +29,56 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * if err != nil { return nil, nil, nil, err } + + log.Tracef("Restoring the past UTXO of block %s with selectedParent %s", + blockHash, blockGHOSTDAGData.SelectedParent) selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent) if err != nil { return nil, nil, nil, err } + + log.Tracef("Applying blue blocks to the selected parent past UTXO of block %s", blockHash) acceptanceData, utxoDiff, err := csm.applyBlueBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err } + + log.Tracef("Calculating the multiset of %s", blockHash) multiset, err := csm.calculateMultiset(acceptanceData, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err } + log.Tracef("The multiset of block %s resolved to: %s", blockHash, multiset.Hash()) return utxoDiff, acceptanceData, multiset, nil } func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainHash) (*model.UTXODiff, error) { + log.Tracef("restorePastUTXO start for block %s", blockHash) + defer log.Tracef("restorePastUTXO end for block %s", blockHash) + var err error - // collect the UTXO diffs + log.Tracef("Collecting UTXO diffs for block %s", blockHash) var utxoDiffs []*model.UTXODiff nextBlockHash := blockHash for { + log.Tracef("Collecting UTXO diff for block %s", nextBlockHash) utxoDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, nextBlockHash) if err != nil { return nil, err } utxoDiffs = append(utxoDiffs, utxoDiff) + log.Tracef("Collected UTXO diff for block %s: %s", nextBlockHash, utxoDiff) exists, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, nextBlockHash) if err != nil { return nil, err } if !exists { + log.Tracef("Block %s does not have a UTXO diff child, "+ + "meaning we reached the virtual. Returning the collected "+ + "UTXO diffs: %s", nextBlockHash, utxoDiffs) break } @@ -66,11 +87,15 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH return nil, err } if nextBlockHash == nil { + log.Tracef("Block %s does not have a UTXO diff child, "+ + "meaning we reached the virtual. Returning the collected "+ + "UTXO diffs: %s", nextBlockHash, utxoDiffs) break } } // apply the diffs in reverse order + log.Tracef("Applying the collected UTXO diffs for block %s in reverse order", blockHash) accumulatedDiff := model.NewUTXODiff() for i := len(utxoDiffs) - 1; i >= 0; i-- { accumulatedDiff, err = utxoalgebra.WithDiff(accumulatedDiff, utxoDiffs[i]) @@ -78,6 +103,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH return nil, err } } + log.Tracef("The accumulated diff for block %s is: %s", blockHash, accumulatedDiff) return accumulatedDiff, nil } @@ -86,6 +112,9 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH selectedParentPastUTXODiff *model.UTXODiff, ghostdagData *model.BlockGHOSTDAGData) ( model.AcceptanceData, *model.UTXODiff, error) { + log.Tracef("applyBlueBlocks start for block %s", blockHash) + defer log.Tracef("applyBlueBlocks end for block %s", blockHash) + blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues) if err != nil { return nil, nil, err @@ -95,30 +124,39 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH if err != nil { return nil, nil, err } + log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime) multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks)) accumulatedUTXODiff := utxoalgebra.DiffClone(selectedParentPastUTXODiff) accumulatedMass := uint64(0) for i, blueBlock := range blueBlocks { + blueBlockHash := consensusserialization.BlockHash(blueBlock) + log.Tracef("Applying blue block %s", blueBlockHash) blockAcceptanceData := &model.BlockAcceptanceData{ TransactionAcceptanceData: make([]*model.TransactionAcceptanceData, len(blueBlock.Transactions)), } isSelectedParent := i == 0 + log.Tracef("Is blue block %s the selected parent: %t", blueBlockHash, isSelectedParent) for j, transaction := range blueBlock.Transactions { var isAccepted bool - var fee uint64 + + transactionID := consensusserialization.TransactionID(transaction) + log.Tracef("Attempting to accept transaction %s in block %s", + transactionID, blueBlockHash) isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent, accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore) if err != nil { return nil, nil, err } + log.Tracef("Transaction %s in block %s isAccepted: %t, fee: %d", + transactionID, blueBlockHash, isAccepted, transaction.Fee) blockAcceptanceData.TransactionAcceptanceData[j] = &model.TransactionAcceptanceData{ Transaction: transaction, - Fee: fee, + Fee: transaction.Fee, IsAccepted: isAccepted, } } @@ -133,6 +171,11 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap accumulatedMassBefore uint64, selectedParentPastMedianTime int64, blockBlueScore uint64) ( isAccepted bool, accumulatedMassAfter uint64, err error) { + transactionID := consensusserialization.TransactionID(transaction) + log.Tracef("maybeAcceptTransaction start for transaction %s in block %s", transactionID, blockHash) + defer log.Tracef("maybeAcceptTransaction end for transaction %s in block %s", transactionID, blockHash) + + log.Tracef("Populating transaction %s with UTXO entries", transactionID) err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, accumulatedUTXODiff) if err != nil { if !errors.As(err, &(ruleerrors.RuleError{})) { @@ -145,9 +188,14 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap // Coinbase transaction outputs are added to the UTXO-set only if they are in the selected parent chain. if transactionhelper.IsCoinBase(transaction) { if !isSelectedParent { + log.Tracef("Transaction %s is the coinbase of block %s "+ + "but said block is not in the selected parent chain. "+ + "As such, it is not accepted", transactionID, blockHash) return false, accumulatedMassBefore, nil } + log.Tracef("Transaction %s is the coinbase of block %s", transactionID, blockHash) } else { + log.Tracef("Validating transaction %s in block %s", transactionID, blockHash) err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( transaction, blockHash, selectedParentPastMedianTime) if err != nil { @@ -155,15 +203,22 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap return false, 0, err } + log.Tracef("Validation failed for transaction %s "+ + "in block %s: %s", transactionID, blockHash, err) return false, accumulatedMassBefore, nil } + log.Tracef("Validation passed for transaction %s in block %s", transactionID, blockHash) + log.Tracef("Check mass for transaction %s in block %s", transactionID, blockHash) isAccepted, accumulatedMassAfter = csm.checkTransactionMass(transaction, accumulatedMassBefore) if !isAccepted { + log.Tracef("Transaction %s in block %s has too much mass, "+ + "and cannot be accepted", transactionID, blockHash) return false, accumulatedMassBefore, nil } } + log.Tracef("Adding transaction %s in block %s to the accumulated diff", transactionID, blockHash) err = utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore) if err != nil { return false, 0, err @@ -176,7 +231,14 @@ func (csm *consensusStateManager) checkTransactionMass( transaction *externalapi.DomainTransaction, accumulatedMassBefore uint64) ( isAccepted bool, accumulatedMassAfter uint64) { + transactionID := consensusserialization.TransactionID(transaction) + log.Tracef("checkTransactionMass start for transaction %s", transactionID) + defer log.Tracef("checkTransactionMass end for transaction %s", transactionID) + + log.Tracef("Adding transaction %s with mass %d to the "+ + "so-far accumulated mass of %d", transactionID, transaction.Mass, accumulatedMassBefore) accumulatedMassAfter = accumulatedMassBefore + transaction.Mass + log.Tracef("Accumulated mass including transaction %s: %d", transactionID, accumulatedMassAfter) // We could potentially overflow the accumulator so check for // overflow as well. @@ -187,7 +249,13 @@ func (csm *consensusStateManager) checkTransactionMass( return true, accumulatedMassAfter } -func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (model.ReadOnlyUTXOSetIterator, error) { +func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) ( + model.ReadOnlyUTXOSetIterator, error) { + + log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash) + defer log.Tracef("RestorePastUTXOSetIterator end for block %s", blockHash) + + log.Tracef("Calculating UTXO diff for block %s", blockHash) blockDiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) if err != nil { return nil, err diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go index f568733de..88c77612e 100644 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ b/domain/consensus/processes/consensusstatemanager/finality.go @@ -8,7 +8,12 @@ import ( func (csm *consensusStateManager) checkFinalityViolation( blockHash *externalapi.DomainHash) error { + log.Tracef("checkFinalityViolation start for block %s", blockHash) + defer log.Tracef("checkFinalityViolation end for block %s", blockHash) + if *blockHash == *csm.genesisHash { + log.Tracef("Block %s is the genesis block, "+ + "and does not violate finality by definition", blockHash) return nil } @@ -20,7 +25,9 @@ func (csm *consensusStateManager) checkFinalityViolation( if isViolatingFinality { csm.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash) + return nil } + log.Tracef("Block %s does not violate finality", blockHash) return nil } @@ -28,21 +35,37 @@ func (csm *consensusStateManager) checkFinalityViolation( func (csm *consensusStateManager) virtualFinalityPoint() ( *externalapi.DomainHash, error) { - return csm.dagTraversalManager.BlockAtDepth( + log.Tracef("virtualFinalityPoint start") + defer log.Tracef("virtualFinalityPoint end") + + virtualFinalityPoint, err := csm.dagTraversalManager.BlockAtDepth( model.VirtualBlockHash, csm.finalityDepth) + if err != nil { + return nil, err + } + log.Tracef("The current virtual finality block is: %s", virtualFinalityPoint) + + return virtualFinalityPoint, nil } func (csm *consensusStateManager) isViolatingFinality( blockHash *externalapi.DomainHash) (bool, error) { + log.Tracef("isViolatingFinality start for block %s", blockHash) + defer log.Tracef("isViolatingFinality end for block %s", blockHash) + virtualFinalityPoint, err := csm.virtualFinalityPoint() if err != nil { return false, err } + log.Tracef("The virtual finality point is: %s", virtualFinalityPoint) isInSelectedParentChain, err := csm.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 } diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index f1b131ea1..fc77e95d2 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -11,7 +11,12 @@ import ( func (csm *consensusStateManager) calculateMultiset( acceptanceData model.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) { + log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent) + defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent) + if blockGHOSTDAGData.SelectedParent == nil { + log.Tracef("Selected parent is nil, which could only happen for the genesis. " + + "The genesis, by definition, has an empty multiset") return multiset.New(), nil } @@ -19,21 +24,26 @@ func (csm *consensusStateManager) calculateMultiset( if err != nil { return nil, err } + log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent, ms.Hash()) for _, blockAcceptanceData := range acceptanceData { for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { + transaction := transactionAcceptanceData.Transaction + transactionID := consensusserialization.TransactionID(transaction) if !transactionAcceptanceData.IsAccepted { + log.Tracef("Skipping transaction %s because it was not accepted", transactionID) continue } - transaction := transactionAcceptanceData.Transaction - isCoinbase := i == 0 + log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase) + var err error err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore, isCoinbase) if err != nil { return nil, err } + log.Tracef("Added transaction %s to the multiset", transactionID) } } @@ -43,7 +53,13 @@ func (csm *consensusStateManager) calculateMultiset( func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.DomainTransaction, blockBlueScore uint64, isCoinbase bool) error { + transactionID := consensusserialization.TransactionID(transaction) + log.Tracef("addTransactionToMultiset start for transaction %s", transactionID) + defer log.Tracef("addTransactionToMultiset end for transaction %s", transactionID) + for _, input := range transaction.Inputs { + log.Tracef("Removing input %s at index %d from the multiset", + input.PreviousOutpoint.TransactionID, input.PreviousOutpoint.Index) err := removeUTXOFromMultiset(multiset, input.UTXOEntry, &input.PreviousOutpoint) if err != nil { return err @@ -52,7 +68,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi. for i, output := range transaction.Outputs { outpoint := &externalapi.DomainOutpoint{ - TransactionID: *consensusserialization.TransactionID(transaction), + TransactionID: *transactionID, Index: uint32(i), } utxoEntry := &externalapi.UTXOEntry{ @@ -61,6 +77,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi. BlockBlueScore: blockBlueScore, IsCoinbase: isCoinbase, } + log.Tracef("Adding input %s at index %d from the multiset", transactionID, i) err := addUTXOToMultiset(multiset, utxoEntry, outpoint) if err != nil { return err diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 3e123ef26..bf86175da 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -10,6 +10,10 @@ import ( ) func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + log.Tracef("pickVirtualParents start for tips: %s", tips) + defer log.Tracef("pickVirtualParents end for tips: %s", tips) + + log.Tracef("Pushing all tips into a DownHeap") candidatesHeap := csm.dagTraversalManager.NewDownHeap() for _, tip := range tips { err := candidatesHeap.Push(tip) @@ -26,6 +30,7 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH if err != nil { return nil, err } + log.Tracef("The selected parent of the virtual is: %s", virtualSelectedParent) selectedVirtualParents := hashset.NewFromSlice(virtualSelectedParent) @@ -33,28 +38,44 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH for candidatesHeap.Len() > 0 && len(selectedVirtualParents) < constants.MaxBlockParents { candidate := candidatesHeap.Pop() + + log.Tracef("Attempting to add %s to the virtual parents", candidate) + log.Tracef("The current merge set size is %d", mergeSetSize) + mergeSetIncrease, err := csm.mergeSetIncrease(candidate, selectedVirtualParents) if err != nil { return nil, err } + log.Tracef("The merge set would increase by %d with block %s", mergeSetIncrease, candidate) if mergeSetSize+mergeSetIncrease > constants.MergeSetSizeLimit { + log.Tracef("Cannot add block %s since that would violate the merge set size limit", candidate) continue } selectedVirtualParents.Add(candidate) mergeSetSize += mergeSetIncrease + log.Tracef("Added block %s to the virtual parents set", candidate) } boundedMergeBreakingParents, err := csm.boundedMergeBreakingParents(selectedVirtualParents.ToSlice()) if err != nil { return nil, err } + log.Tracef("The following parents are omitted for "+ + "breaking the bounded merge set: %s", boundedMergeBreakingParents) - return selectedVirtualParents.Subtract(boundedMergeBreakingParents).ToSlice(), nil + virtualParents := selectedVirtualParents.Subtract(boundedMergeBreakingParents).ToSlice() + log.Tracef("The virtual parents resolved to be: %s", virtualParents) + return virtualParents, nil } -func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap model.BlockHeap) (*externalapi.DomainHash, error) { +func (csm *consensusStateManager) selectVirtualSelectedParent( + candidatesHeap model.BlockHeap) (*externalapi.DomainHash, error) { + + log.Tracef("selectVirtualSelectedParent start") + defer log.Tracef("selectVirtualSelectedParent end") + disqualifiedCandidates := hashset.New() for { @@ -63,20 +84,24 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod } selectedParentCandidate := candidatesHeap.Pop() + log.Tracef("Checking block %s for selected parent eligibility", selectedParentCandidate) selectedParentCandidateStatus, err := csm.blockStatusStore.Get(csm.databaseContext, selectedParentCandidate) if err != nil { return nil, err } if selectedParentCandidateStatus == externalapi.StatusValid { + log.Tracef("Block %s is valid. Returning it as the selected parent", selectedParentCandidate) return selectedParentCandidate, nil } + log.Tracef("Block %s is not valid. Adding it to the disqualified set", selectedParentCandidate) disqualifiedCandidates.Add(selectedParentCandidate) candidateParents, err := csm.dagTopologyManager.Parents(selectedParentCandidate) if err != nil { return nil, err } + log.Tracef("The parents of block %s are: %s", selectedParentCandidate, candidateParents) for _, parent := range candidateParents { parentChildren, err := csm.dagTopologyManager.Children(parent) if err != nil { @@ -90,8 +115,11 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod break } } + log.Tracef("The children of block %s are: %s", parent, parentChildren) if disqualifiedCandidates.ContainsAllInSlice(parentChildren) { + log.Tracef("The disqualified set contains all the "+ + "children of %s. Adding it to the candidate heap", parentChildren) err := candidatesHeap.Push(parent) if err != nil { return nil, err @@ -104,6 +132,9 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(candidatesHeap mod func (csm *consensusStateManager) mergeSetIncrease( candidate *externalapi.DomainHash, selectedVirtualParents hashset.HashSet) (int, error) { + log.Tracef("mergeSetIncrease start") + defer log.Tracef("mergeSetIncrease end") + visited := hashset.New() queue := csm.dagTraversalManager.NewDownHeap() err := queue.Push(candidate) @@ -114,15 +145,20 @@ func (csm *consensusStateManager) mergeSetIncrease( for queue.Len() > 0 { current := queue.Pop() + log.Tracef("Attempting to increment the merge set size increase for block %s", current) + isInPastOfSelectedVirtualParents, err := csm.dagTopologyManager.IsAncestorOfAny( current, selectedVirtualParents.ToSlice()) if err != nil { return 0, err } if isInPastOfSelectedVirtualParents { + log.Tracef("Skipping block %s because it's in the past of one "+ + "(or more) of the selected virtual parents", current) continue } + log.Tracef("Incrementing the merge set size increase") mergeSetIncrease++ parents, err := csm.dagTopologyManager.Parents(current) @@ -139,12 +175,18 @@ func (csm *consensusStateManager) mergeSetIncrease( } } } + log.Tracef("The resolved merge set size increase is: %d", mergeSetIncrease) return mergeSetIncrease, nil } -func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externalapi.DomainHash) (hashset.HashSet, error) { - // Temporarily set virtual to all parents, so that we can run ghostdag on it +func (csm *consensusStateManager) boundedMergeBreakingParents( + parents []*externalapi.DomainHash) (hashset.HashSet, error) { + + log.Tracef("boundedMergeBreakingParents start for parents: %s", parents) + defer log.Tracef("boundedMergeBreakingParents end for parents: %s", parents) + + log.Tracef("Temporarily setting virtual to all parents, so that we can run ghostdag on it") err := csm.dagTopologyManager.SetParents(model.VirtualBlockHash, parents) if err != nil { return nil, err @@ -159,24 +201,29 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa if err != nil { return nil, err } + log.Tracef("The potentially kosherizing blocks are: %s", potentiallyKosherizingBlocks) virtualFinalityPoint, err := csm.virtualFinalityPoint() if err != nil { return nil, err } + log.Tracef("The finality point of the virtual is: %s", virtualFinalityPoint) - badReds := []*externalapi.DomainHash{} + var badReds []*externalapi.DomainHash virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err } for _, redBlock := range virtualGHOSTDAGData.MergeSetReds { + log.Tracef("Check whether red block %s is kosherized", redBlock) isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock) if err != nil { return nil, err } if isFinalityPointInPast { + log.Tracef("Skipping red block %s because it has the virtual's"+ + " finality point in its past", redBlock) continue } @@ -186,17 +233,21 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa if err != nil { return nil, err } + log.Tracef("Red block %s is an ancestor of potentially kosherizing "+ + "block %s, therefore the red block is kosher", redBlock, potentiallyKosherizingBlock) if isKosherized { break } } if !isKosherized { + log.Tracef("Red block %s is not kosher. Adding it to the bad reds set", redBlock) badReds = append(badReds, redBlock) } } boundedMergeBreakingParents := hashset.New() for _, parent := range parents { + log.Tracef("Checking whether parent %s breaks the bounded merge set", parent) isBadRedInPast := false for _, badRedBlock := range badReds { isBadRedInPast, err = csm.dagTopologyManager.IsAncestorOf(parent, badRedBlock) @@ -204,10 +255,12 @@ func (csm *consensusStateManager) boundedMergeBreakingParents(parents []*externa return nil, err } if isBadRedInPast { + log.Tracef("Parent %s is an ancestor of bad red %s", parent, badRedBlock) break } } if isBadRedInPast { + log.Tracef("Adding parent %s to the bounded merge breaking parents set", parent) boundedMergeBreakingParents.Add(parent) } } diff --git a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go index 08006f55e..08147f004 100644 --- a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go +++ b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" ) // PopulateTransactionWithUTXOEntries populates the transaction UTXO entries with data from the virtual's UTXO set. @@ -18,22 +19,31 @@ func (csm *consensusStateManager) PopulateTransactionWithUTXOEntries(transaction func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualOrDiff( transaction *externalapi.DomainTransaction, utxoDiff *model.UTXODiff) error { - missingOutpoints := []*externalapi.DomainOutpoint{} + transactionID := consensusserialization.TransactionID(transaction) + log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff start for transaction %s", transactionID) + defer log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff end for transaction %s", transactionID) + var missingOutpoints []*externalapi.DomainOutpoint for _, transactionInput := range transaction.Inputs { // skip all inputs that have a pre-filled utxo entry if transactionInput.UTXOEntry != nil { + log.Tracef("Skipping outpoint %s:%d because it is already populated", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) continue } // check if utxoDiff says anything about the input's outpoint if utxoDiff != nil { if utxoEntry, ok := utxoalgebra.CollectionGet(utxoDiff.ToAdd, &transactionInput.PreviousOutpoint); ok { + log.Tracef("Populating outpoint %s:%d from the given utxoDiff", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) transactionInput.UTXOEntry = utxoEntry continue } if utxoalgebra.CollectionContains(utxoDiff.ToRemove, &transactionInput.PreviousOutpoint) { + log.Tracef("Outpoint %s:%d is missing in the given utxoDiff", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint) continue } @@ -45,10 +55,14 @@ func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualO return err } if !hasUTXOEntry { + log.Tracef("Outpoint %s:%d is missing in the database", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint) continue } + log.Tracef("Populating outpoint %s:%d from the database", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) utxoEntry, err := csm.consensusStateStore.UTXOByOutpoint(csm.databaseContext, &transactionInput.PreviousOutpoint) if err != nil { return err diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 2b5d993e4..086748ad6 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -9,25 +9,40 @@ import ( ) func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { - // get list of all blocks in the selected parent chain that have not yet resolved their status + log.Tracef("resolveBlockStatus start for block %s", blockHash) + defer log.Tracef("resolveBlockStatus end for block %s", blockHash) + + log.Tracef("Getting a list of all blocks in the selected "+ + "parent chain of %s that have no yet resolved their status", blockHash) unverifiedBlocks, err := csm.getUnverifiedChainBlocks(blockHash) if err != nil { return 0, err } + log.Tracef("Got %d unverified blocks in the selected parent "+ + "chain of %s: %s", len(unverifiedBlocks), blockHash, unverifiedBlocks) // If there's no unverified blocks in the given block's chain - this means the given block already has a // UTXO-verified status, and therefore it should be retrieved from the store and returned if len(unverifiedBlocks) == 0 { - return csm.blockStatusStore.Get(csm.databaseContext, blockHash) + log.Tracef("There are not unverified blocks in %s's selected parent chain. "+ + "This means that the block already has a UTXO-verified status.", blockHash) + status, err := csm.blockStatusStore.Get(csm.databaseContext, blockHash) + if err != nil { + return 0, err + } + log.Tracef("Block %s's status resolved to: %s", blockHash, status) + return status, nil } + log.Tracef("Finding the status of the selected parent of %s", blockHash) selectedParentStatus, err := csm.findSelectedParentStatus(unverifiedBlocks) if err != nil { return 0, err } + log.Tracef("The status of the selected parent of %s is: %s", blockHash, selectedParentStatus) + log.Tracef("Resolving the unverified blocks' status in reverse order (past to present)") var blockStatus externalapi.BlockStatus - // resolve the unverified blocks' statuses in opposite order for i := len(unverifiedBlocks) - 1; i >= 0; i-- { unverifiedBlockHash := unverifiedBlocks[i] @@ -51,8 +66,14 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma // findSelectedParentStatus returns the status of the selectedParent of the last block in the unverifiedBlocks chain func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*externalapi.DomainHash) ( externalapi.BlockStatus, error) { + + log.Tracef("findSelectedParentStatus start") + defer log.Tracef("findSelectedParentStatus end") + lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1] if *lastUnverifiedBlock == *csm.genesisHash { + log.Tracef("the most recent unverified block is the genesis block, "+ + "which by definition has status: %s", externalapi.StatusValid) return externalapi.StatusValid, nil } lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, lastUnverifiedBlock) @@ -65,17 +86,24 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e func (csm *consensusStateManager) getUnverifiedChainBlocks( blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - unverifiedBlocks := []*externalapi.DomainHash{} + log.Tracef("getUnverifiedChainBlocks start for block %s", blockHash) + defer log.Tracef("getUnverifiedChainBlocks end for block %s", blockHash) + + var unverifiedBlocks []*externalapi.DomainHash currentHash := blockHash for { + log.Tracef("Getting status for block %s", currentHash) currentBlockStatus, err := csm.blockStatusStore.Get(csm.databaseContext, currentHash) if err != nil { return nil, err } if currentBlockStatus != externalapi.StatusUTXOPendingVerification { + log.Tracef("Block %s has status %s. Returning all the "+ + "unverified blocks prior to it: %s", currentHash, currentBlockStatus, unverifiedBlocks) return unverifiedBlocks, nil } + log.Tracef("Block %s is unverified. Adding it to the unverified block collection", currentHash) unverifiedBlocks = append(unverifiedBlocks, currentHash) currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, currentHash) @@ -84,7 +112,9 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks( } if currentBlockGHOSTDAGData.SelectedParent == nil { - return unverifiedBlocks, nil // this means we reached genesis + log.Tracef("Genesis block reached. Returning all the "+ + "unverified blocks prior to it: %s", unverifiedBlocks) + return unverifiedBlocks, nil } currentHash = currentBlockGHOSTDAGData.SelectedParent @@ -92,11 +122,16 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks( } func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { + log.Tracef("resolveSingleBlockStatus start for block %s", blockHash) + defer log.Tracef("resolveSingleBlockStatus end for block %s", blockHash) + + log.Tracef("Calculating pastUTXO and acceptance data and multiset for block %s", blockHash) pastUTXODiff, acceptanceData, multiset, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) if err != nil { return 0, err } + log.Tracef("Staging the calculated acceptance data of block %s", blockHash) err = csm.acceptanceDataStore.Stage(blockHash, acceptanceData) if err != nil { return 0, err @@ -107,20 +142,27 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap return 0, err } + log.Tracef("verifying the UTXO of block %s", blockHash) err = csm.verifyUTXO(block, blockHash, pastUTXODiff, acceptanceData, multiset) if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { + log.Debugf("UTXO verification for block %s failed: %s", blockHash, err) return externalapi.StatusDisqualifiedFromChain, nil } return 0, err } + log.Debugf("UTXO verification for block %s passed", blockHash) + log.Tracef("Staging the multiset of block %s", blockHash) csm.multisetStore.Stage(blockHash, multiset) + + log.Tracef("Staging the utxoDiff of block %s", blockHash) err = csm.utxoDiffStore.Stage(blockHash, pastUTXODiff, nil) if err != nil { return 0, err } + log.Tracef("Updating the parent utxoDiffs of block %s", blockHash) err = csm.updateParentDiffs(blockHash, pastUTXODiff) if err != nil { return 0, err @@ -130,10 +172,15 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap } func (csm *consensusStateManager) updateParentDiffs( blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { + log.Tracef("updateParentDiffs start for block %s", blockHash) + defer log.Tracef("updateParentDiffs end for block %s", blockHash) + parentHashes, err := csm.dagTopologyManager.Parents(blockHash) if err != nil { return err } + log.Tracef("Parent hashes for block %s are: %s", blockHash, parentHashes) + for _, parentHash := range parentHashes { // skip all parents that already have a utxo-diff child parentHasUTXODiffChild, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, parentHash) @@ -141,6 +188,8 @@ func (csm *consensusStateManager) updateParentDiffs( return err } if parentHasUTXODiffChild { + log.Tracef("Skipping parent %s of block %s because it "+ + "already has a UTXO diff-child", parentHash, blockHash) continue } @@ -149,11 +198,14 @@ func (csm *consensusStateManager) updateParentDiffs( return err } if parentStatus != externalapi.StatusValid { + log.Tracef("Skipping parent %s of block %s because it "+ + "has a non-valid status %s", parentHash, blockHash, parentStatus) continue } - // parents that till now didn't have a utxo-diff child - were actually virtual's diffParents. + // parents that didn't have a utxo-diff child until now were actually virtual's diffParents. // Update them to have the new block as their utxo-diff child + log.Tracef("Resolving new UTXO diff of parent %s", parentHash) parentCurrentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, parentHash) if err != nil { return err @@ -162,7 +214,9 @@ func (csm *consensusStateManager) updateParentDiffs( if err != nil { return err } + log.Tracef("The new UTXO diff parent %s resolved to: %s", parentHash, parentNewDiff) + log.Tracef("Staging the new UTXO diff and diff child for parent %s", parentHash) err = csm.utxoDiffStore.Stage(parentHash, parentNewDiff, blockHash) if err != nil { return err diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 59a65a9ab..7ccfee5c8 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -32,10 +32,14 @@ func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byt } func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byte) error { + log.Tracef("setPruningPointUTXOSet start") + defer log.Tracef("setPruningPointUTXOSet end") + headerTipsPruningPoint, err := csm.HeaderTipsPruningPoint() if err != nil { return err } + log.Tracef("The pruning point of the header tips is: %s", headerTipsPruningPoint) protoUTXOSet := &utxoserialization.ProtoUTXOSet{} err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet) @@ -47,27 +51,34 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt if err != nil { return err } + log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash()) headerTipsPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, headerTipsPruningPoint) if err != nil { return err } + log.Tracef("The multiset in the header of the header tip pruning point: %s", + headerTipsPruningPointHeader.UTXOCommitment) if headerTipsPruningPointHeader.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()) } + log.Tracef("Header tip pruning point multiset validation passed") + log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips") err = csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes) if err != nil { return err } + log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents") err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes) if err != nil { return err } + log.Tracef("Staging the virtual UTXO set") err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet)) if err != nil { return err @@ -78,11 +89,13 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt return err } + log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff") err = csm.updateVirtualDiffParents(headerTipsPruningPoint, model.NewUTXODiff()) if err != nil { return err } + log.Tracef("Staging the status of the header tips pruning point as %s", externalapi.StatusValid) csm.blockStatusStore.Stage(headerTipsPruningPoint, externalapi.StatusValid) return nil } @@ -136,18 +149,22 @@ func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.Proto } 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) err = csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{ Parents: headerTips, }) if err != nil { return nil, err } - defer csm.blockRelationStore.Discard() err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash) @@ -156,5 +173,10 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH } defer csm.ghostdagDataStore.Discard() - return csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth) + 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 } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index fb0df7df4..ee7471510 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -8,38 +8,49 @@ import ( ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error { + log.Tracef("updateVirtual start for block %s", newBlockHash) + defer log.Tracef("updateVirtual end for block %s", newBlockHash) + + log.Tracef("Picking virtual parents from the tips: %s", tips) virtualParents, err := csm.pickVirtualParents(tips) if err != nil { return err } + log.Tracef("Picked virtual parents: %s", virtualParents) err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, virtualParents) if err != nil { return err } + log.Tracef("Set new parents for the virtual block hash") err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash) if err != nil { return 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 } + log.Tracef("Staging new acceptance data for the virtual block") err = csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) if err != nil { return err } + log.Tracef("Staging new multiset for the virtual block") csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) + log.Tracef("Staging new UTXO diff for the virtual block") err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) if err != nil { return err } + log.Tracef("Updating the virtual diff parents after adding %s to the DAG", newBlockHash) err = csm.updateVirtualDiffParents(newBlockHash, virtualUTXODiff) if err != nil { return err @@ -51,14 +62,20 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain func (csm *consensusStateManager) updateVirtualDiffParents( newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error { + log.Tracef("updateVirtualDiffParents start for block %s", newBlockHash) + defer log.Tracef("updateVirtualDiffParents end for block %s", newBlockHash) + var newVirtualDiffParents []*externalapi.DomainHash if *newBlockHash == *csm.genesisHash { + log.Tracef("Block %s is the genesis, so by definition "+ + "it is the only member of the new virtual diff parents set", newBlockHash) newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} } else { oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { return err } + log.Tracef("The old virtual's diff parents are: %s", oldVirtualDiffParents) // If the status of the new block is not `Valid` - virtualDiffParents didn't change status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) @@ -66,8 +83,11 @@ func (csm *consensusStateManager) updateVirtualDiffParents( return err } if status != externalapi.StatusValid { + log.Tracef("The status of the new block %s is non-valid. "+ + "As such, don't change the diff parents of the virtual", newBlockHash) newVirtualDiffParents = oldVirtualDiffParents } else { + log.Tracef("Block %s is valid. Updating the virtual diff parents", newBlockHash) newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) if err != nil { return err @@ -82,8 +102,10 @@ func (csm *consensusStateManager) updateVirtualDiffParents( } } } + log.Tracef("The new virtual diff parents are: %s", newVirtualDiffParents) for _, virtualDiffParent := range newVirtualDiffParents { + log.Tracef("Calculating new UTXO diff for virtual diff parent %s", virtualDiffParent) virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { return err @@ -92,11 +114,13 @@ func (csm *consensusStateManager) updateVirtualDiffParents( if err != nil { return err } + log.Tracef("Staging new UTXO diff for virtual diff parent %s: %s", virtualDiffParent, newDiff) err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil) if err != nil { return err } } + log.Tracef("Staging the new virtual UTXO diff parents") return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) } diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 2b7b72b20..0b6966209 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -21,26 +21,38 @@ import ( func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error { + log.Tracef("verifyUTXO start for block %s", blockHash) + defer log.Tracef("verifyUTXO end for block %s", blockHash) + + log.Tracef("Validating UTXO commitment for block %s", blockHash) err := csm.validateUTXOCommitment(block, blockHash, multiset) if err != nil { return err } + log.Tracef("UTXO commitment validation passed for block %s", blockHash) + log.Tracef("Validating acceptedIDMerkleRoot for block %s", blockHash) err = csm.validateAcceptedIDMerkleRoot(block, blockHash, acceptanceData) if err != nil { return err } + log.Tracef("AcceptedIDMerkleRoot validation passed for block %s", blockHash) coinbaseTransaction := block.Transactions[0] + log.Tracef("Validating coinbase transaction %s for block %s", + consensusserialization.TransactionID(coinbaseTransaction), blockHash) err = csm.validateCoinbaseTransaction(blockHash, coinbaseTransaction) if err != nil { return err } + 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) if err != nil { return err } + log.Tracef("Transactions against past UTXO validation passed for block %s", blockHash) return nil } @@ -48,25 +60,38 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, err error) error { + log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash) + defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash) + selectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(blockHash) if err != nil { return err } + log.Tracef("The past median time of %s is %d", blockHash, selectedParentMedianTime) for i, transaction := range block.Transactions { + transactionID := consensusserialization.TransactionID(transaction) + log.Tracef("Validating transaction %s in block %s against "+ + "the block's past UTXO", transactionID, blockHash) if i == transactionhelper.CoinbaseTransactionIndex { + log.Tracef("Skipping transaction %s because it is the coinbase", transactionID) continue } + + log.Tracef("Populating transaction %s with UTXO entries", transactionID) err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, pastUTXODiff) if err != nil { return err } + log.Tracef("Validating transaction %s and populating it with mass and fee", transactionID) err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( transaction, blockHash, selectedParentMedianTime) if err != nil { return err } + log.Tracef("Validation against the block's past UTXO "+ + "passed for transaction %s in block %s", transactionID, blockHash) } return nil } @@ -74,6 +99,9 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error { + log.Tracef("validateAcceptedIDMerkleRoot start for block %s", blockHash) + defer log.Tracef("validateAcceptedIDMerkleRoot end for block %s", blockHash) + calculatedAcceptedIDMerkleRoot := calculateAcceptedIDMerkleRoot(acceptanceData) if block.Header.AcceptedIDMerkleRoot != *calculatedAcceptedIDMerkleRoot { return errors.Wrapf(ruleerrors.ErrBadMerkleRoot, "block %s accepted ID merkle root is invalid - block "+ @@ -87,6 +115,9 @@ func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalap func (csm *consensusStateManager) validateUTXOCommitment( block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, multiset model.Multiset) error { + log.Tracef("validateUTXOCommitment start for block %s", blockHash) + defer log.Tracef("validateUTXOCommitment end for block %s", blockHash) + multisetHash := multiset.Hash() if block.Header.UTXOCommitment != *multisetHash { return errors.Wrapf(ruleerrors.ErrBadUTXOCommitment, "block %s UTXO commitment is invalid - block "+ @@ -97,6 +128,9 @@ func (csm *consensusStateManager) validateUTXOCommitment( } func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData) *externalapi.DomainHash { + log.Tracef("calculateAcceptedIDMerkleRoot start") + defer log.Tracef("calculateAcceptedIDMerkleRoot end") + var acceptedTransactions []*externalapi.DomainTransaction for _, blockAcceptanceData := range multiblockAcceptanceData { @@ -117,11 +151,18 @@ func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData } func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externalapi.DomainHash, coinbaseTransaction *externalapi.DomainTransaction) error { + + log.Tracef("validateCoinbaseTransaction start for block %s", blockHash) + defer log.Tracef("validateCoinbaseTransaction end for block %s", blockHash) + + log.Tracef("Extracting coinbase data for coinbase transaction %s in block %s", + consensusserialization.TransactionID(coinbaseTransaction), blockHash) _, coinbaseData, err := coinbase.ExtractCoinbaseDataAndBlueScore(coinbaseTransaction) if err != nil { return err } + log.Tracef("Calculating the expected coinbase transaction for the given coinbase data and block %s", blockHash) expectedCoinbaseTransaction, err := csm.coinbaseManager.ExpectedCoinbaseTransaction(blockHash, coinbaseData) if err != nil { return err @@ -129,6 +170,9 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa coinbaseTransactionHash := consensusserialization.TransactionHash(coinbaseTransaction) expectedCoinbaseTransactionHash := consensusserialization.TransactionHash(expectedCoinbaseTransaction) + log.Tracef("given coinbase hash: %s, expected coinbase hash: %s", + coinbaseTransactionHash, expectedCoinbaseTransactionHash) + if *coinbaseTransactionHash != *expectedCoinbaseTransactionHash { return errors.Wrap(ruleerrors.ErrBadCoinbaseTransaction, "coinbase transaction is not built as expected") } From dec9ef5f75d610a5afd5d9e59155c68f149d03ca Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 23 Nov 2020 14:29:41 +0200 Subject: [PATCH 078/351] [NOD-1555] Implement TestResolveBlockStatusSanity (#1138) * [NOD-1555] Implement TestResolveBlockStatusSanity. * [NOD-1555] Fix the test name string. --- .../resolve_block_status_test.go | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index b7b8d9e64..4bcd70d20 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -148,3 +148,89 @@ func TestDoubleSpends(t *testing.T) { } }) } + +func TestResolveBlockStatusSanity(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + consensus, teardown, err := consensus.NewFactory().NewTestConsensus(params, "TestResolveBlockStatusSanity") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + genesisHash := params.GenesisHash + allHashes := []*externalapi.DomainHash{genesisHash} + + // Make sure that the status of genesisHash is valid + genesisStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), genesisHash) + if err != nil { + t.Fatalf("error getting genesis status: %s", err) + } + if genesisStatus != externalapi.StatusValid { + t.Fatalf("genesis is unexpectedly non-valid. Its status is: %s", genesisStatus) + } + + chainLength := int(params.K) + 1 + + // Add a chain of blocks over the genesis and make sure all their + // statuses are valid + currentHash := genesisHash + for i := 0; i < chainLength; i++ { + addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil) + if err != nil { + t.Fatalf("error adding block %d: %s", i, err) + } + blockStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), addedBlockHash) + if err != nil { + t.Fatalf("error getting block %d (%s) status: %s", i, addedBlockHash, err) + } + if blockStatus != externalapi.StatusValid { + t.Fatalf("block %d (%s) is unexpectedly non-valid. Its status is: %s", i, addedBlockHash, blockStatus) + } + currentHash = addedBlockHash + allHashes = append(allHashes, addedBlockHash) + } + + // Add another chain of blocks over the genesis that's shorter than + // the original chain by 1. Here we expect all the statuses to be + // StatusUTXOPendingVerification + currentHash = genesisHash + for i := 0; i < chainLength-1; i++ { + addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil) + if err != nil { + t.Fatalf("error adding block %d: %s", i, err) + } + blockStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), addedBlockHash) + if err != nil { + t.Fatalf("error getting block %d (%s) status: %s", i, addedBlockHash, err) + } + if blockStatus != externalapi.StatusUTXOPendingVerification { + t.Fatalf("block %d (%s) has unexpected status. "+ + "Want: %s, got: %s", i, addedBlockHash, externalapi.StatusUTXOPendingVerification, blockStatus) + } + currentHash = addedBlockHash + allHashes = append(allHashes, addedBlockHash) + } + + // 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) + if err != nil { + t.Fatalf("error adding block %d: %s", i, err) + } + currentHash = addedBlockHash + allHashes = append(allHashes, addedBlockHash) + } + + // Make sure that all the blocks in the DAG now have StatusValid + for _, hash := range allHashes { + blockStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), hash) + if err != nil { + t.Fatalf("error getting block %s status: %s", hash, err) + } + if blockStatus != externalapi.StatusValid { + t.Fatalf("block %s is unexpectedly non-valid. Its status is: %s", hash, blockStatus) + } + } + }) +} From c1505b47489a966e5561b485a0ab17eaa5894362 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 23 Nov 2020 05:09:39 -0800 Subject: [PATCH 079/351] [NOD-1555] Use stageDiff to update virtualDiffParents (#1139) * [NOD-1555] Filter ancestors in updateVirtualDiffParents * [NOD-1555] Use stageDiff to update virtualDiffParents * [NOD-1555] Don't add existing blocks in addToVirtualDiffParents * [NOD-1555] Remove redundant check * [NOD-1555] Fix log and rename removeAncestorsFromVirtualDiffParents->removeAncestorsFromVirtualDiffParentsAndAssignDiffChild * [NOD-1555] Add logs * [NOD-1555] Fix comment * [NOD-1555] Fix logs --- .../blockstatusstore/blockstatusstore.go | 4 +- .../resolve_block_status.go | 56 ++++++------- .../set_pruning_utxo_set.go | 2 +- .../consensusstatemanager/update_virtual.go | 59 +++---------- .../consensusstatemanager/utxo_diffs.go | 84 +++++++++++++++++++ 5 files changed, 126 insertions(+), 79 deletions(-) create mode 100644 domain/consensus/processes/consensusstatemanager/utxo_diffs.go diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index 5a3f3fb18..4b62be445 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -62,7 +62,7 @@ func (bss *blockStatusStore) Get(dbContext model.DBReader, blockHash *externalap return 0, err } - return bss.deserializeHeader(statusBytes) + return bss.deserializeBlockStatus(statusBytes) } // Exists returns true if the blockStatus for the given blockHash exists @@ -84,7 +84,7 @@ func (bss *blockStatusStore) serializeBlockStatus(status externalapi.BlockStatus return proto.Marshal(dbBlockStatus) } -func (bss *blockStatusStore) deserializeHeader(statusBytes []byte) (externalapi.BlockStatus, error) { +func (bss *blockStatusStore) deserializeBlockStatus(statusBytes []byte) (externalapi.BlockStatus, error) { dbBlockStatus := &serialization.DbBlockStatus{} err := proto.Unmarshal(statusBytes, dbBlockStatus) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 086748ad6..57c45e4e7 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -157,67 +157,67 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap csm.multisetStore.Stage(blockHash, multiset) log.Tracef("Staging the utxoDiff of block %s", blockHash) - err = csm.utxoDiffStore.Stage(blockHash, pastUTXODiff, nil) + err = csm.stageDiff(blockHash, pastUTXODiff, nil) if err != nil { return 0, err } - log.Tracef("Updating the parent utxoDiffs of block %s", blockHash) - err = csm.updateParentDiffs(blockHash, pastUTXODiff) + log.Tracef("Remove block ancestors from virtual diff parents and assign %s as their diff child", blockHash) + err = csm.removeAncestorsFromVirtualDiffParentsAndAssignDiffChild(blockHash, pastUTXODiff) if err != nil { return 0, err } return externalapi.StatusValid, nil } -func (csm *consensusStateManager) updateParentDiffs( - blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { - log.Tracef("updateParentDiffs start for block %s", blockHash) - defer log.Tracef("updateParentDiffs end for block %s", blockHash) - parentHashes, err := csm.dagTopologyManager.Parents(blockHash) +func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssignDiffChild( + blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { + + log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild start for block %s", blockHash) + defer log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild end for block %s", blockHash) + + if *blockHash == *csm.genesisHash { + log.Tracef("Genesis block doesn't have ancestors to remove from the virtual diff parents") + return nil + } + + virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { return err } - log.Tracef("Parent hashes for block %s are: %s", blockHash, parentHashes) - for _, parentHash := range parentHashes { - // skip all parents that already have a utxo-diff child - parentHasUTXODiffChild, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, parentHash) - if err != nil { - return err - } - if parentHasUTXODiffChild { - log.Tracef("Skipping parent %s of block %s because it "+ - "already has a UTXO diff-child", parentHash, blockHash) + for _, virtualDiffParent := range virtualDiffParents { + if *virtualDiffParent == *blockHash { + log.Tracef("Skipping updating virtual diff parent %s "+ + "because it was updated before.", virtualDiffParent) continue } - parentStatus, err := csm.blockStatusStore.Get(csm.databaseContext, parentHash) + isAncestorOfBlock, err := csm.dagTopologyManager.IsAncestorOf(virtualDiffParent, blockHash) if err != nil { return err } - if parentStatus != externalapi.StatusValid { - log.Tracef("Skipping parent %s of block %s because it "+ - "has a non-valid status %s", parentHash, blockHash, parentStatus) + + if !isAncestorOfBlock { + log.Tracef("Skipping block %s because it's not an "+ + "ancestor of %s", virtualDiffParent, blockHash) continue } // parents that didn't have a utxo-diff child until now were actually virtual's diffParents. // Update them to have the new block as their utxo-diff child - log.Tracef("Resolving new UTXO diff of parent %s", parentHash) - parentCurrentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, parentHash) + log.Tracef("Updating %s to be the diff child of %s", blockHash, virtualDiffParent) + currentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { return err } - parentNewDiff, err := utxoalgebra.DiffFrom(pastUTXODiff, parentCurrentDiff) + newDiff, err := utxoalgebra.DiffFrom(pastUTXODiff, currentDiff) if err != nil { return err } - log.Tracef("The new UTXO diff parent %s resolved to: %s", parentHash, parentNewDiff) - log.Tracef("Staging the new UTXO diff and diff child for parent %s", parentHash) - err = csm.utxoDiffStore.Stage(parentHash, parentNewDiff, blockHash) + err = csm.stageDiff(virtualDiffParent, newDiff, blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 7ccfee5c8..9f8f58913 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -90,7 +90,7 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt } log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff") - err = csm.updateVirtualDiffParents(headerTipsPruningPoint, model.NewUTXODiff()) + err = csm.updateVirtualDiffParents(model.NewUTXODiff()) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index ee7471510..3a5a36382 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -4,7 +4,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashset" ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error { @@ -51,7 +50,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain } log.Tracef("Updating the virtual diff parents after adding %s to the DAG", newBlockHash) - err = csm.updateVirtualDiffParents(newBlockHash, virtualUTXODiff) + err = csm.updateVirtualDiffParents(virtualUTXODiff) if err != nil { return err } @@ -59,52 +58,16 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain return nil } -func (csm *consensusStateManager) updateVirtualDiffParents( - newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error { +func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff *model.UTXODiff) error { + log.Tracef("updateVirtualDiffParents start") + defer log.Tracef("updateVirtualDiffParents end") - log.Tracef("updateVirtualDiffParents start for block %s", newBlockHash) - defer log.Tracef("updateVirtualDiffParents end for block %s", newBlockHash) - - var newVirtualDiffParents []*externalapi.DomainHash - if *newBlockHash == *csm.genesisHash { - log.Tracef("Block %s is the genesis, so by definition "+ - "it is the only member of the new virtual diff parents set", newBlockHash) - newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} - } else { - oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) - if err != nil { - return err - } - log.Tracef("The old virtual's diff parents are: %s", oldVirtualDiffParents) - - // If the status of the new block is not `Valid` - virtualDiffParents didn't change - status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) - if err != nil { - return err - } - if status != externalapi.StatusValid { - log.Tracef("The status of the new block %s is non-valid. "+ - "As such, don't change the diff parents of the virtual", newBlockHash) - newVirtualDiffParents = oldVirtualDiffParents - } else { - log.Tracef("Block %s is valid. Updating the virtual diff parents", newBlockHash) - newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) - if err != nil { - return err - } - newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) - - newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} - for _, virtualDiffParent := range oldVirtualDiffParents { - if !newBlockParents.Contains(virtualDiffParent) { - newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) - } - } - } + virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err } - log.Tracef("The new virtual diff parents are: %s", newVirtualDiffParents) - for _, virtualDiffParent := range newVirtualDiffParents { + for _, virtualDiffParent := range virtualDiffParents { log.Tracef("Calculating new UTXO diff for virtual diff parent %s", virtualDiffParent) virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { @@ -114,13 +77,13 @@ func (csm *consensusStateManager) updateVirtualDiffParents( if err != nil { return err } + log.Tracef("Staging new UTXO diff for virtual diff parent %s: %s", virtualDiffParent, newDiff) - err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil) + err = csm.stageDiff(virtualDiffParent, newDiff, nil) if err != nil { return err } } - log.Tracef("Staging the new virtual UTXO diff parents") - return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) + return nil } diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go new file mode 100644 index 000000000..385f577ab --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go @@ -0,0 +1,84 @@ +package consensusstatemanager + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" +) + +func (csm *consensusStateManager) stageDiff(blockHash *externalapi.DomainHash, + utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { + + log.Tracef("stageDiff start for block %s", blockHash) + defer log.Tracef("stageDiff end for block %s", blockHash) + + log.Tracef("Staging block %s as the diff child of %s", utxoDiffChild, blockHash) + err := csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild) + if err != nil { + return err + } + + if utxoDiffChild == nil { + log.Tracef("Adding block %s to the virtual diff parents", blockHash) + return csm.addToVirtualDiffParents(blockHash) + } + + log.Tracef("Removing block %s from the virtual diff parents", blockHash) + return csm.removeFromVirtualDiffParents(blockHash) +} + +func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi.DomainHash) error { + log.Tracef("addToVirtualDiffParents start for block %s", blockHash) + defer log.Tracef("addToVirtualDiffParents end for block %s", blockHash) + + var oldVirtualDiffParents []*externalapi.DomainHash + if *blockHash != *csm.genesisHash { + var err error + oldVirtualDiffParents, err = csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err + } + } + + isInVirtualDiffParents := false + for _, diffParent := range oldVirtualDiffParents { + if *diffParent == *blockHash { + isInVirtualDiffParents = true + break + } + } + + if isInVirtualDiffParents { + log.Tracef("Block %s is already a virtual diff parent, so there's no need to add it", blockHash) + return nil + } + + newVirtualDiffParents := append([]*externalapi.DomainHash{blockHash}, oldVirtualDiffParents...) + log.Tracef("Staging virtual diff parents after adding %s to it", blockHash) + return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) +} + +func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *externalapi.DomainHash) error { + log.Tracef("removeFromVirtualDiffParents start for block %s", blockHash) + defer log.Tracef("removeFromVirtualDiffParents end for block %s", blockHash) + + oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err + } + + newVirtualDiffParents := make([]*externalapi.DomainHash, 0, len(oldVirtualDiffParents)-1) + for _, diffParent := range oldVirtualDiffParents { + if *diffParent != *blockHash { + newVirtualDiffParents = append(newVirtualDiffParents, diffParent) + } + } + + if len(newVirtualDiffParents) != len(oldVirtualDiffParents)-1 { + return errors.Errorf("expected to remove one member from virtual diff parents and "+ + "have a length of %d but got length of %d", len(oldVirtualDiffParents)-1, len(newVirtualDiffParents)) + } + + log.Tracef("Staging virtual diff parents after removing %s from it", blockHash) + return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) +} From bb2d7f72acb5b66bfc8cf773ac47f342f19755e5 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 23 Nov 2020 06:28:59 -0800 Subject: [PATCH 080/351] [NOD-1560] Add TestValidateTransactionInIsolation (#1140) * [NOD-1560] Add TestValidateTransactionInIsolation * [NOD-1560] Make ForAllNets copy the params before mutating them * [NOD-1560] Remove redundant continue * [NOD-1560] Don't change finality duration --- .../transaction_in_isolation_test.go | 162 ++++++++++++++++++ .../consensus/utils/testutils/for_all_nets.go | 5 +- .../consensus/utils/transactionhelper/new.go | 17 ++ 3 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go new file mode 100644 index 000000000..3c2051c96 --- /dev/null +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -0,0 +1,162 @@ +package transactionvalidator_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util" + "github.com/pkg/errors" + "testing" +) + +type txSubnetworkData struct { + subnetworkID externalapi.DomainSubnetworkID + gas uint64 + payload []byte +} + +func TestValidateTransactionInIsolation(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, "TestValidateTransactionInIsolation") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + tests := []struct { + name string + numInputs uint32 + numOutputs uint32 + outputValue uint64 + nodeSubnetworkID externalapi.DomainSubnetworkID + txSubnetworkData *txSubnetworkData + extraModificationsFunc func(*externalapi.DomainTransaction) + expectedErr error + }{ + {"good one", 1, 1, 1, subnetworks.SubnetworkIDNative, nil, nil, nil}, + {"no inputs", 0, 1, 1, subnetworks.SubnetworkIDNative, nil, nil, ruleerrors.ErrNoTxInputs}, + {"no outputs", 1, 0, 1, subnetworks.SubnetworkIDNative, nil, nil, nil}, + {"too much sompi in one output", 1, 1, util.MaxSompi + 1, + subnetworks.SubnetworkIDNative, + nil, + nil, + ruleerrors.ErrBadTxOutValue}, + {"too much sompi in total outputs", 1, 2, util.MaxSompi - 1, + subnetworks.SubnetworkIDNative, + nil, + nil, + ruleerrors.ErrBadTxOutValue}, + {"duplicate inputs", 2, 1, 1, + subnetworks.SubnetworkIDNative, + nil, + func(tx *externalapi.DomainTransaction) { tx.Inputs[1].PreviousOutpoint.Index = 0 }, + ruleerrors.ErrDuplicateTxInputs}, + {"1 input coinbase", + 1, + 1, + 1, + subnetworks.SubnetworkIDNative, + &txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, nil}, + nil, + nil}, + {"no inputs coinbase", + 0, + 1, + 1, + subnetworks.SubnetworkIDNative, + &txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, nil}, + nil, + nil}, + {"too long payload coinbase", + 1, + 1, + 1, + subnetworks.SubnetworkIDNative, + &txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, make([]byte, constants.MaxCoinbasePayloadLength+1)}, + nil, + ruleerrors.ErrBadCoinbasePayloadLen}, + {"non-zero gas in Kaspa", 1, 1, 0, + subnetworks.SubnetworkIDNative, + nil, + func(tx *externalapi.DomainTransaction) { + tx.Gas = 1 + }, + ruleerrors.ErrInvalidGas}, + {"non-zero gas in subnetwork registry", 1, 1, 0, + subnetworks.SubnetworkIDRegistry, + &txSubnetworkData{subnetworks.SubnetworkIDRegistry, 1, []byte{}}, + nil, + ruleerrors.ErrInvalidGas}, + {"non-zero payload in Kaspa", 1, 1, 0, + subnetworks.SubnetworkIDNative, + nil, + func(tx *externalapi.DomainTransaction) { + tx.Payload = []byte{1} + }, + ruleerrors.ErrInvalidPayload}, + {"invalid payload hash", 1, 1, 0, + externalapi.DomainSubnetworkID{123}, + &txSubnetworkData{externalapi.DomainSubnetworkID{123}, 0, []byte{1}}, + func(tx *externalapi.DomainTransaction) { + tx.PayloadHash = externalapi.DomainHash{} + }, + ruleerrors.ErrInvalidPayloadHash}, + {"invalid payload hash in native subnetwork", 1, 1, 0, + subnetworks.SubnetworkIDNative, + nil, + func(tx *externalapi.DomainTransaction) { + tx.PayloadHash = *hashes.HashData(tx.Payload) + }, + ruleerrors.ErrInvalidPayloadHash}, + } + + for _, test := range tests { + tx := createTxForTest(test.numInputs, test.numOutputs, test.outputValue, test.txSubnetworkData) + + if test.extraModificationsFunc != nil { + test.extraModificationsFunc(tx) + } + + err := tc.TransactionValidator().ValidateTransactionInIsolation(tx) + if !errors.Is(err, test.expectedErr) { + t.Errorf("TestValidateTransactionInIsolation: '%s': unexpected error %+v", test.name, err) + } + } + }) +} + +func createTxForTest(numInputs uint32, numOutputs uint32, outputValue uint64, subnetworkData *txSubnetworkData) *externalapi.DomainTransaction { + txIns := []*externalapi.DomainTransactionInput{} + txOuts := []*externalapi.DomainTransactionOutput{} + + for i := uint32(0); i < numInputs; i++ { + txIns = append(txIns, &externalapi.DomainTransactionInput{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: i, + }, + SignatureScript: []byte{}, + Sequence: constants.MaxTxInSequenceNum, + }) + } + + for i := uint32(0); i < numOutputs; i++ { + txOuts = append(txOuts, &externalapi.DomainTransactionOutput{ + ScriptPublicKey: []byte{}, + Value: outputValue, + }) + } + + if subnetworkData != nil { + return transactionhelper.NewSubnetworkTransaction(constants.TransactionVersion, txIns, txOuts, &subnetworkData.subnetworkID, subnetworkData.gas, subnetworkData.payload) + } + + return transactionhelper.NewNativeTransaction(constants.TransactionVersion, txIns, txOuts) +} diff --git a/domain/consensus/utils/testutils/for_all_nets.go b/domain/consensus/utils/testutils/for_all_nets.go index ad73ad9f2..689cf4053 100644 --- a/domain/consensus/utils/testutils/for_all_nets.go +++ b/domain/consensus/utils/testutils/for_all_nets.go @@ -17,8 +17,9 @@ func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *dagconfig } for _, params := range allParams { - params.SkipProofOfWork = skipPow + paramsCopy := params + paramsCopy.SkipProofOfWork = skipPow t.Logf("Running test for %s", params.Name) - testFunc(t, ¶ms) + testFunc(t, ¶msCopy) } } diff --git a/domain/consensus/utils/transactionhelper/new.go b/domain/consensus/utils/transactionhelper/new.go index 2c42bd035..927d3c032 100644 --- a/domain/consensus/utils/transactionhelper/new.go +++ b/domain/consensus/utils/transactionhelper/new.go @@ -3,6 +3,7 @@ package transactionhelper import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" ) // NewSubnetworkTransaction returns a new trsnactions in the specified subnetwork with specified gas and payload @@ -24,3 +25,19 @@ func NewSubnetworkTransaction(version int32, inputs []*externalapi.DomainTransac Mass: 0, } } + +// NewNativeTransaction returns a new native transaction +func NewNativeTransaction(version int32, inputs []*externalapi.DomainTransactionInput, + outputs []*externalapi.DomainTransactionOutput) *externalapi.DomainTransaction { + return &externalapi.DomainTransaction{ + Version: version, + Inputs: inputs, + Outputs: outputs, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + Gas: 0, + Payload: []byte{}, + Fee: 0, + Mass: 0, + } +} From 8264369c813a0e7faf8da98083e5c8f6831280ae Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 23 Nov 2020 07:18:30 -0800 Subject: [PATCH 081/351] [NOD-1561] Add TestValidateMedianTime (#1141) * [NOD-1561] Add TestValidateMedianTime * [NOD-1561] Remove redundant variable --- .../block_header_in_context_test.go | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 domain/consensus/processes/blockvalidator/block_header_in_context_test.go diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go new file mode 100644 index 000000000..eea7db5b2 --- /dev/null +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -0,0 +1,83 @@ +package blockvalidator_test + +import ( + "errors" + "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/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "testing" +) + +func TestValidateMedianTime(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, "TestValidateMedianTime") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + addBlock := func(blockTime int64, parents []*externalapi.DomainHash, expectedErr error) (*externalapi.DomainBlock, *externalapi.DomainHash) { + block, err := tc.BuildBlockWithParents(parents, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + block.Header.TimeInMilliseconds = blockTime + err = tc.ValidateAndInsertBlock(block) + if !errors.Is(err, expectedErr) { + t.Fatalf("expected error %s but got %+v", expectedErr, err) + } + + return block, consensusserialization.BlockHash(block) + } + + pastMedianTime := func(parents ...*externalapi.DomainHash) int64 { + var tempHash externalapi.DomainHash + err := tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{ + Parents: parents, + Children: nil, + }) + if err != nil { + t.Fatalf("StageBlockRelation: %+v", err) + } + defer tc.BlockRelationStore().Discard() + + err = tc.GHOSTDAGManager().GHOSTDAG(&tempHash) + if err != nil { + t.Fatalf("GHOSTDAG: %+v", err) + } + defer tc.GHOSTDAGDataStore().Discard() + + pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(&tempHash) + if err != nil { + t.Fatalf("PastMedianTime: %+v", err) + } + + return pastMedianTime + } + + tip := params.GenesisBlock + tipHash := params.GenesisHash + + blockTime := tip.Header.TimeInMilliseconds + + for i := 0; i < 100; i++ { + blockTime += 1000 + _, tipHash = addBlock(blockTime, []*externalapi.DomainHash{tipHash}, nil) + } + + // Checks that a block is invalid if it has timestamp equals to past median time + addBlock(pastMedianTime(tipHash), []*externalapi.DomainHash{tipHash}, ruleerrors.ErrTimeTooOld) + + // Checks that a block is valid if its timestamp is after past median time + addBlock(pastMedianTime(tipHash)+1, []*externalapi.DomainHash{tipHash}, nil) + + // Checks that a block is invalid if its timestamp is before past median time + addBlock(pastMedianTime(tipHash)-1, []*externalapi.DomainHash{tipHash}, ruleerrors.ErrTimeTooOld) + }) +} From 96d9e5800fba31a18f72344068783105b39b3afa Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 23 Nov 2020 08:27:44 -0800 Subject: [PATCH 082/351] [NOD-1561] Add TestCheckParentsIncest and fix validation order (#1143) --- .../blockvalidator/block_header_in_context.go | 5 -- .../block_header_in_context_test.go | 70 +++++++++++++++++++ .../processes/blockvalidator/proof_of_work.go | 9 ++- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index ae52d147a..1d76108ed 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -16,11 +16,6 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa return err } - err = v.checkParentsIncest(header) - if err != nil { - return err - } - isHeadersOnlyBlock, err := v.isHeadersOnlyBlock(blockHash) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index eea7db5b2..781a15e26 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -81,3 +81,73 @@ func TestValidateMedianTime(t *testing.T) { addBlock(pastMedianTime(tipHash)-1, []*externalapi.DomainHash{tipHash}, ruleerrors.ErrTimeTooOld) }) } + +func TestCheckParentsIncest(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, "TestCheckParentsIncest") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + 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) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + c, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + directParentsRelationBlock := &externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 0, + ParentHashes: []*externalapi.DomainHash{a, b}, + HashMerkleRoot: externalapi.DomainHash{}, + AcceptedIDMerkleRoot: externalapi.DomainHash{}, + UTXOCommitment: externalapi.DomainHash{}, + TimeInMilliseconds: 0, + Bits: 0, + Nonce: 0, + }, + Transactions: nil, + } + + err = tc.ValidateAndInsertBlock(directParentsRelationBlock) + if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) { + t.Fatalf("unexpected error %+v", err) + } + + indirectParentsRelationBlock := &externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 0, + ParentHashes: []*externalapi.DomainHash{params.GenesisHash, b}, + HashMerkleRoot: externalapi.DomainHash{}, + AcceptedIDMerkleRoot: externalapi.DomainHash{}, + UTXOCommitment: externalapi.DomainHash{}, + TimeInMilliseconds: 0, + Bits: 0, + Nonce: 0, + }, + Transactions: nil, + } + + 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) + if err != nil { + t.Fatalf("AddBlock: %s", err) + } + }) +} diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index 49175ffb5..6014a0282 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -15,12 +15,17 @@ func (v *blockValidator) ValidateProofOfWorkAndDifficulty(blockHash *externalapi return err } - err = v.checkProofOfWork(header) + err = v.checkParentsExist(header) if err != nil { return err } - err = v.checkParentsExist(header) + err = v.checkParentsIncest(header) + if err != nil { + return err + } + + err = v.checkProofOfWork(header) if err != nil { return err } From 2096a28d1c249272d325ebe95a1bb883efb4d55f Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 23 Nov 2020 08:33:45 -0800 Subject: [PATCH 083/351] [NOD-1563] Add TestMaxHeaders (#1144) --- app/protocol/flows/ibd/handle_request_headers.go | 3 ++- .../flows/ibd/handle_request_headers_test.go | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 app/protocol/flows/ibd/handle_request_headers_test.go diff --git a/app/protocol/flows/ibd/handle_request_headers.go b/app/protocol/flows/ibd/handle_request_headers.go index 4ac94450e..d8b6d29e3 100644 --- a/app/protocol/flows/ibd/handle_request_headers.go +++ b/app/protocol/flows/ibd/handle_request_headers.go @@ -10,6 +10,7 @@ import ( ) const ibdBatchSize = router.DefaultMaxMessages +const maxHeaders = appmessage.MaxInvPerMsg // RequestIBDBlocksContext is the interface for the context needed for the HandleRequestHeaders flow. type RequestIBDBlocksContext interface { @@ -97,7 +98,7 @@ func (flow *handleRequestBlocksFlow) buildMsgBlockHeaders(lowHash *externalapi.D if err != nil { return nil, err } - const maxHeaders = appmessage.MaxInvPerMsg + if len(blockHashes) > maxHeaders { blockHashes = blockHashes[:maxHeaders] } diff --git a/app/protocol/flows/ibd/handle_request_headers_test.go b/app/protocol/flows/ibd/handle_request_headers_test.go new file mode 100644 index 000000000..63573cdc3 --- /dev/null +++ b/app/protocol/flows/ibd/handle_request_headers_test.go @@ -0,0 +1,15 @@ +package ibd + +import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "testing" +) + +func TestMaxHeaders(t *testing.T) { + testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { + if params.FinalityDepth() > maxHeaders { + t.Errorf("FinalityDepth() in %s should be lower or equal to appmessage.MaxInvPerMsg", params.Name) + } + }) +} From d65f382c80f16948d10a48c9a3e4055dd8a3087a Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 24 Nov 2020 11:34:02 +0200 Subject: [PATCH 084/351] [NOD-1565] Reorder getSyncInfo in a way that won't unnecessarily call HeaderTipsPruningPoint. (#1146) --- .../processes/syncmanager/syncinfo.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 1680721a8..ce24f3097 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -57,6 +57,14 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { return externalapi.SyncStateHeadersFirst, nil } + virtualSelectedParentHash, err := sm.virtualSelectedParentHash() + if err != nil { + return 0, err + } + if *virtualSelectedParentHash == *headerVirtualSelectedParentHash { + return externalapi.SyncStateRelay, nil + } + // 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 @@ -75,15 +83,7 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { return externalapi.SyncStateMissingUTXOSet, nil } - virtualSelectedParentHash, err := sm.virtualSelectedParentHash() - if err != nil { - return 0, err - } - if *virtualSelectedParentHash != *headerVirtualSelectedParentHash { - return externalapi.SyncStateMissingBlockBodies, nil - } - - return externalapi.SyncStateRelay, nil + return externalapi.SyncStateMissingBlockBodies, nil } func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, error) { From 2334f8b4eb5f3f0877bde0d834dde1b7bedca3a6 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 24 Nov 2020 01:42:53 -0800 Subject: [PATCH 085/351] [NOD-1564] Add TestChainedTransactions (#1145) * [NOD-1564] Add TestChainedTransactions * [NOD-1564] Fix errors --- .../block_body_in_isolation_test.go | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go new file mode 100644 index 000000000..e7b1b95ca --- /dev/null +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -0,0 +1,74 @@ +package blockvalidator_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" + "testing" +) + +func TestChainedTransactions(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.BlockCoinbaseMaturity = 0 + + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + block1Hash, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + block1, err := tc.GetBlock(block1Hash) + if err != nil { + t.Fatalf("Error getting block1: %+v", err) + } + + tx1, err := testutils.CreateTransaction(block1.Transactions[0]) + if err != nil { + t.Fatalf("Error creating tx1: %+v", err) + } + + chainedTx, err := testutils.CreateTransaction(tx1) + if err != nil { + t.Fatalf("Error creating chainedTx: %+v", err) + } + + // Check that a block is invalid if it contains chained transactions + _, 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) + if err != nil { + t.Fatalf("unexpected error %+v", err) + } + + block2, err := tc.GetBlock(block2Hash) + if err != nil { + t.Fatalf("Error getting block2: %+v", err) + } + + tx2, err := testutils.CreateTransaction(block2.Transactions[0]) + if err != nil { + t.Fatalf("Error creating tx2: %+v", err) + } + + // Check that a block is valid if it contains two non chained transactions + _, err = tc.AddBlock([]*externalapi.DomainHash{block2Hash}, nil, + []*externalapi.DomainTransaction{tx1, tx2}) + if err != nil { + t.Fatalf("unexpected error %+v", err) + } + }) +} From afc634d871f1341902e35c233e811105e7b19318 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 24 Nov 2020 16:57:40 +0200 Subject: [PATCH 086/351] Add TestCheckBlockSanity back (#1137) --- .../block_body_in_isolation_test.go | 937 ++++++++++++++++++ 1 file changed, 937 insertions(+) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index e7b1b95ca..29f2588a7 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -4,9 +4,12 @@ import ( "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" + "math" "testing" ) @@ -72,3 +75,937 @@ func TestChainedTransactions(t *testing.T) { } }) } + +// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works +// as expected. +func TestCheckBlockSanity(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + consensus, teardown, err := factory.NewTestConsensus(params, "TestCheckBlockSanity") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + blockHash := consensusserialization.BlockHash(&exampleValidBlock) + if len(exampleValidBlock.Transactions) < 3 { + t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions)) + } + + err = consensus.BlockStore().Stage(blockHash, &exampleValidBlock) + if err != nil { + t.Fatalf("Failed storing block: %v", err) + } + + err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) + if err != nil { + t.Fatalf("Failed validating block in isolation: %v", err) + } + + // Test with block with wrong transactions sorting order + blockHash = consensusserialization.BlockHash(&blockWithWrongTxOrder) + err = consensus.BlockStore().Stage(blockHash, &blockWithWrongTxOrder) + if err != nil { + t.Fatalf("Failed storing block: %v", err) + } + err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) + if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) { + t.Errorf("CheckBlockSanity: Expected ErrTransactionsNotSorted error, instead got %v", err) + } + + // Test a block with invalid parents order + // We no longer require blocks to have ordered parents + blockHash = consensusserialization.BlockHash(&unOrderedParentsBlock) + err = consensus.BlockStore().Stage(blockHash, &unOrderedParentsBlock) + if err != nil { + t.Fatalf("Failed storing block: %v", err) + } + err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) + if err != nil { + t.Errorf("CheckBlockSanity: Expected block to be be body in isolation valid, got error instead: %v", err) + } + }) +} + +var unOrderedParentsBlock = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 0x10000000, + ParentHashes: []*externalapi.DomainHash{ + { + 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, + 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, + 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, + 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, + }, + { + 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, + }, + }, + HashMerkleRoot: externalapi.DomainHash{ + 0xa2, 0x60, 0x5a, 0x45, 0xfe, 0x01, 0x41, 0xc9, + 0xc2, 0x8d, 0xe2, 0xc3, 0x2d, 0x00, 0xa4, 0x29, + 0xd4, 0x01, 0x57, 0x2d, 0x2f, 0xcd, 0x49, 0xd4, + 0xff, 0x6f, 0xab, 0xd2, 0xd1, 0x96, 0x38, 0xb9, + }, + AcceptedIDMerkleRoot: externalapi.DomainHash{ + 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, + 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, + 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, + 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, + }, + UTXOCommitment: externalapi.DomainHash{ + 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, + 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, + 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, + 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, + }, + TimeInMilliseconds: 0x5cd18053000, + Bits: 0x207fffff, + Nonce: 0x1, + }, + Transactions: []*externalapi.DomainTransaction{ + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x02, 0x10, 0x27, 0x08, 0xac, 0x29, 0x2f, 0x2f, + 0xcf, 0x70, 0xb0, 0x7e, 0x0b, 0x2f, 0x50, 0x32, + 0x53, 0x48, 0x2f, 0x62, 0x74, 0x63, 0x64, 0x2f, + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0x12a05f200, // 5000000000 + ScriptPublicKey: []byte{ + 0x51, + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDCoinbase, + Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, + PayloadHash: externalapi.DomainHash{ + 0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0, + 0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc, + 0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16, + 0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7, + }, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, + 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, + 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, + 0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87, + }), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03 + Index: 0, + }, + SignatureScript: []byte{ + 0x49, // OP_DATA_73 + 0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3, + 0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6, + 0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94, + 0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58, + 0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00, + 0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62, + 0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c, + 0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60, + 0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48, + 0x01, // 73-byte signature + 0x41, // OP_DATA_65 + 0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d, + 0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38, + 0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25, + 0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e, + 0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8, + 0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd, + 0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b, + 0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3, + 0xd3, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0x2123e300, // 556000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60, + 0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e, + 0xf7, 0xf5, 0x8b, 0x32, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + { + Value: 0x108e20f00, // 4444000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f, + 0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b, + 0x52, 0xde, 0x3d, 0x7c, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, + 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, + 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, + 0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf, + }), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3 + Index: 1, + }, + SignatureScript: []byte{ + 0x47, // OP_DATA_71 + 0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf, + 0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5, + 0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34, + 0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31, + 0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee, + 0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f, + 0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c, + 0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e, + 0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01, + 0x41, // OP_DATA_65 + 0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78, + 0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5, + 0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39, + 0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21, + 0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee, + 0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3, + 0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95, + 0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85, + 0x0f, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0xf4240, // 1000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04, + 0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d, + 0xad, 0xbe, 0x7e, 0x10, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + { + Value: 0x11d260c0, // 299000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1, + 0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab, + 0xb3, 0x40, 0x9c, 0xd9, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, + 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, + 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, + 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, + }), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b + Index: 0, + }, + SignatureScript: []byte{ + 0x49, // OP_DATA_73 + 0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2, + 0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c, + 0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd, + 0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f, + 0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00, + 0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14, + 0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb, + 0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c, + 0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3, + 0x01, // 73-byte signature + 0x41, // OP_DATA_65 + 0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97, + 0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18, + 0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17, + 0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94, + 0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65, + 0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f, + 0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce, + 0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f, + 0xbb, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0xf4240, // 1000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7, + 0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b, + 0xf2, 0xeb, 0x9e, 0xe0, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + }, +} + +// exampleValidBlock defines a sample valid block +var exampleValidBlock = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 0x10000000, + ParentHashes: []*externalapi.DomainHash{ + { + 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, + }, + { + 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, + 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, + 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, + 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, + }, + }, + HashMerkleRoot: externalapi.DomainHash{ + 0xce, 0xea, 0x78, 0x53, 0x7e, 0x89, 0x67, 0xaf, + 0xdc, 0x4a, 0xd1, 0x67, 0xb0, 0xc4, 0xfc, 0x6e, + 0xe5, 0x4b, 0x87, 0xb0, 0x55, 0x8f, 0xf4, 0x6b, + 0x05, 0x4d, 0x43, 0x0a, 0xb6, 0xbb, 0xe8, 0xdf, + }, + AcceptedIDMerkleRoot: externalapi.DomainHash{ + 0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3, + 0x5d, 0x4e, 0x2c, 0xc9, 0x57, 0x88, 0x30, 0x65, + 0x81, 0xb8, 0xa0, 0x68, 0x77, 0xc4, 0x02, 0x1e, + 0x3c, 0xb1, 0x16, 0x8f, 0x5f, 0x6b, 0x45, 0x87, + }, + UTXOCommitment: [32]byte{}, + TimeInMilliseconds: 0x17305aa654a, + Bits: 0x207fffff, + Nonce: 1, + }, + Transactions: []*externalapi.DomainTransaction{ + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{ + 0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50, + 0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33, + 0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a, + 0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f, + }, + Index: 0xffffffff, + }, + SignatureScript: nil, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0x12a05f200, // 5000000000 + ScriptPublicKey: []byte{ + 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, + 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, + 0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87, + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDCoinbase, + Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, + PayloadHash: externalapi.DomainHash{ + 0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0, + 0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc, + 0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16, + 0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7, + }, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: 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, + }, + Sequence: math.MaxUint64, + }, + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{ + 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, + 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, + 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, + 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, + }, + Index: 0xffffffff, + }, + Sequence: math.MaxUint64, + }, + }, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, + 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, + 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, + 0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87, + }), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03 + Index: 0, + }, + SignatureScript: []byte{ + 0x49, // OP_DATA_73 + 0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3, + 0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6, + 0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94, + 0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58, + 0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00, + 0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62, + 0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c, + 0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60, + 0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48, + 0x01, // 73-byte signature + 0x41, // OP_DATA_65 + 0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d, + 0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38, + 0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25, + 0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e, + 0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8, + 0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd, + 0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b, + 0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3, + 0xd3, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0x2123e300, // 556000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60, + 0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e, + 0xf7, 0xf5, 0x8b, 0x32, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + { + Value: 0x108e20f00, // 4444000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f, + 0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b, + 0x52, 0xde, 0x3d, 0x7c, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, + 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, + 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, + 0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf, + }), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3 + Index: 1, + }, + SignatureScript: []byte{ + 0x47, // OP_DATA_71 + 0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf, + 0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5, + 0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34, + 0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31, + 0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee, + 0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f, + 0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c, + 0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e, + 0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01, + 0x41, // OP_DATA_65 + 0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78, + 0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5, + 0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39, + 0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21, + 0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee, + 0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3, + 0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95, + 0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85, + 0x0f, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0xf4240, // 1000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04, + 0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d, + 0xad, 0xbe, 0x7e, 0x10, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + { + Value: 0x11d260c0, // 299000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1, + 0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab, + 0xb3, 0x40, 0x9c, 0xd9, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{ + 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, + 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, + 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, + 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, + }, // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b + Index: 0, + }, + SignatureScript: []byte{ + 0x49, // OP_DATA_73 + 0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2, + 0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c, + 0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd, + 0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f, + 0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00, + 0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14, + 0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb, + 0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c, + 0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3, + 0x01, // 73-byte signature + 0x41, // OP_DATA_65 + 0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97, + 0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18, + 0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17, + 0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94, + 0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65, + 0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f, + 0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce, + 0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f, + 0xbb, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0xf4240, // 1000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7, + 0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b, + 0xf2, 0xeb, 0x9e, 0xe0, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + }, +} + +// blockWithWrongTxOrder defines invalid block 100,000 of the block DAG. +var blockWithWrongTxOrder = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 1, + ParentHashes: []*externalapi.DomainHash{ + { + 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, + }, + { + 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, + 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, + 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, + 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, + }, + }, + HashMerkleRoot: externalapi.DomainHash{ + 0xac, 0xa4, 0x21, 0xe1, 0xa6, 0xc3, 0xbe, 0x5d, + 0x52, 0x66, 0xf3, 0x0b, 0x21, 0x87, 0xbc, 0xf3, + 0xf3, 0x2d, 0xd1, 0x05, 0x64, 0xb5, 0x16, 0x76, + 0xe4, 0x66, 0x7d, 0x51, 0x53, 0x18, 0x6d, 0xb1, + }, + AcceptedIDMerkleRoot: externalapi.DomainHash{ + 0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, + 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, + 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, + 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, + }, + UTXOCommitment: externalapi.DomainHash{ + 0x00, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, + 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, + 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, + 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, + }, + TimeInMilliseconds: 0x5cd16eaa000, + Bits: 0x207fffff, + Nonce: 1, + }, + Transactions: []*externalapi.DomainTransaction{ + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{ + 0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50, + 0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33, + 0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a, + 0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f, + }, + Index: 0xffffffff, + }, + SignatureScript: nil, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0x12a05f200, // 5000000000 + ScriptPublicKey: []byte{ + 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, + 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, + 0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87, + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDCoinbase, + Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, + PayloadHash: externalapi.DomainHash{ + 0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0, + 0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc, + 0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16, + 0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7, + }, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: 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, + }, + Sequence: math.MaxUint64, + }, + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{ + 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, + 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, + 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, + 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, + }, + Index: 0xffffffff, + }, + Sequence: math.MaxUint64, + }, + }, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, + 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, + 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, + 0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87, + }), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03 + Index: 0, + }, + SignatureScript: []byte{ + 0x49, // OP_DATA_73 + 0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3, + 0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6, + 0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94, + 0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58, + 0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00, + 0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62, + 0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c, + 0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60, + 0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48, + 0x01, // 73-byte signature + 0x41, // OP_DATA_65 + 0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d, + 0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38, + 0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25, + 0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e, + 0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8, + 0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd, + 0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b, + 0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3, + 0xd3, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0x2123e300, // 556000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60, + 0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e, + 0xf7, 0xf5, 0x8b, 0x32, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + { + Value: 0x108e20f00, // 4444000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f, + 0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b, + 0x52, 0xde, 0x3d, 0x7c, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: externalapi.DomainSubnetworkID{11}, + Payload: []byte{}, + PayloadHash: [32]byte{0xFF, 0xFF}, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, + 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, + 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, + 0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf, + }), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3 + Index: 1, + }, + SignatureScript: []byte{ + 0x47, // OP_DATA_71 + 0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf, + 0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5, + 0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34, + 0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31, + 0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee, + 0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f, + 0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c, + 0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e, + 0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01, + 0x41, // OP_DATA_65 + 0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78, + 0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5, + 0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39, + 0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21, + 0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee, + 0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3, + 0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95, + 0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85, + 0x0f, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0xf4240, // 1000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04, + 0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d, + 0xad, 0xbe, 0x7e, 0x10, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + { + Value: 0x11d260c0, // 299000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1, + 0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab, + 0xb3, 0x40, 0x9c, 0xd9, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID([32]byte{ + 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, + 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, + 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, + 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, + }), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b + Index: 0, + }, + SignatureScript: []byte{ + 0x49, // OP_DATA_73 + 0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2, + 0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c, + 0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd, + 0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f, + 0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00, + 0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14, + 0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb, + 0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c, + 0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3, + 0x01, // 73-byte signature + 0x41, // OP_DATA_65 + 0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97, + 0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18, + 0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17, + 0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94, + 0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65, + 0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f, + 0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce, + 0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f, + 0xbb, // 65-byte pubkey + }, + Sequence: math.MaxUint64, + }, + }, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 0xf4240, // 1000000 + ScriptPublicKey: []byte{ + 0x76, // OP_DUP + 0xa9, // OP_HASH160 + 0x14, // OP_DATA_20 + 0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7, + 0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b, + 0xf2, 0xeb, 0x9e, 0xe0, + 0x88, // OP_EQUALVERIFY + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + }, + }, +} From 45d9b63572b2da087d6187cbefea41f52c0f76d2 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 24 Nov 2020 07:56:18 -0800 Subject: [PATCH 087/351] [NOD-1567] Add clone methods to data stores types (#1149) * [NOD-1567] Add clone methods to data stores types * [NOD-1567] Fix comments * [NOD-1567] Fix test --- .../acceptancedatastore.go | 19 +--- .../blockheaderstore/blockheaderstore.go | 19 +--- .../blockrelationstore/blockrelationstore.go | 19 +--- .../blockstatusstore/blockstatusstore.go | 2 +- .../datastructures/blockstore/blockstore.go | 19 +--- .../consensusstatestore/tips.go | 21 +---- .../consensusstatestore/utxo.go | 34 +------- .../virtual_diff_parents.go | 21 +---- .../ghostdagdatastore/ghostdagdatastore.go | 19 +--- .../headertipsstore/headertipsstore.go | 21 +---- .../multisetstore/multisetstore.go | 4 +- .../pruningstore/pruningstore.go | 2 +- .../reachabilitydatastore.go | 19 +--- .../utxodiffstore/utxodiffstore.go | 25 +----- domain/consensus/model/acceptancedata.go | 40 +++++++++ domain/consensus/model/blockrelations.go | 12 +++ domain/consensus/model/externalapi/block.go | 35 ++++++++ .../model/externalapi/blockstatus.go | 5 ++ domain/consensus/model/externalapi/hash.go | 13 ++- .../model/externalapi/subnetworkid.go | 10 +++ .../model/externalapi/transaction.go | 87 +++++++++++++++++++ .../consensus/model/externalapi/utxoentry.go | 17 ++++ domain/consensus/model/ghostdag.go | 20 +++++ ...face_datastructures_acceptancedatastore.go | 2 +- ...terface_datastructures_blockheaderstore.go | 2 +- ...rface_datastructures_blockrelationstore.go | 2 +- .../interface_datastructures_blockstore.go | 2 +- ...face_datastructures_consensusstatestore.go | 4 +- ...erface_datastructures_ghostdagdatastore.go | 2 +- ...nterface_datastructures_headertipsstore.go | 2 +- ...ce_datastructures_reachabilitydatastore.go | 2 +- .../interface_datastructures_utxodiffstore.go | 2 +- domain/consensus/model/multiset.go | 2 +- domain/consensus/model/reachabilitydata.go | 37 ++++++++ domain/consensus/model/utxodiff.go | 48 +++++++--- .../blockbuilder/test_block_builder.go | 13 +-- .../blockprocessor/validateandinsertblock.go | 17 +--- .../block_body_in_isolation_test.go | 15 +--- .../block_header_in_context_test.go | 5 +- .../add_block_to_virtual.go | 5 +- .../calculate_past_utxo.go | 2 +- .../resolve_block_status.go | 5 +- .../set_pruning_utxo_set.go | 11 +-- .../consensusstatemanager/update_virtual.go | 5 +- .../consensusstatemanager/utxo_diffs.go | 11 ++- .../utxoalgebra/collection_helpers.go | 10 --- .../utxoalgebra/diff_algebra.go | 2 +- .../utxoalgebra/diff_algebra_test.go | 6 +- .../utxoalgebra/diff_helpers.go | 9 -- .../dagtopologymanager/dagtopologymanager.go | 15 +--- .../processes/ghostdagmanager/ghostdag.go | 5 +- .../headertipsmanager/headertipsmanager.go | 5 +- .../reachabilitymanager/reachability_test.go | 3 +- .../processes/reachabilitymanager/stage.go | 10 ++- domain/consensus/utils/multiset/multiset.go | 5 +- 55 files changed, 392 insertions(+), 357 deletions(-) diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index b74cec547..f4e060c81 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -25,14 +25,8 @@ func New() model.AcceptanceDataStore { } // Stage stages the given acceptanceData for the given blockHash -func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error { - clone, err := ads.cloneAcceptanceData(acceptanceData) - if err != nil { - return err - } - - ads.staging[*blockHash] = clone - return nil +func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) { + ads.staging[*blockHash] = acceptanceData.Clone() } func (ads *acceptanceDataStore) IsStaged() bool { @@ -107,12 +101,3 @@ func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes [] func (ads *acceptanceDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } - -func (ads *acceptanceDataStore) cloneAcceptanceData(acceptanceData model.AcceptanceData) (model.AcceptanceData, error) { - serialized, err := ads.serializeAcceptanceData(acceptanceData) - if err != nil { - return nil, err - } - - return ads.deserializeAcceptanceData(serialized) -} diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index 27e08451c..b68734433 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -54,14 +54,8 @@ func (bhs *blockHeaderStore) initializeCount(dbContext model.DBReader) error { } // Stage stages the given block header for the given blockHash -func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error { - clone, err := bhs.cloneHeader(blockHeader) - if err != nil { - return err - } - - bhs.staging[*blockHash] = clone - return nil +func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) { + bhs.staging[*blockHash] = blockHeader.Clone() } func (bhs *blockHeaderStore) IsStaged() bool { @@ -169,15 +163,6 @@ func (bhs *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi return serialization.DbBlockHeaderToDomainBlockHeader(dbBlockHeader) } -func (bhs *blockHeaderStore) cloneHeader(header *externalapi.DomainBlockHeader) (*externalapi.DomainBlockHeader, error) { - serialized, err := bhs.serializeHeader(header) - if err != nil { - return nil, err - } - - return bhs.deserializeHeader(serialized) -} - func (bhs *blockHeaderStore) Count() uint64 { return bhs.count + uint64(len(bhs.staging)) - uint64(len(bhs.toDelete)) } diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index 284b32162..8389628fd 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -22,14 +22,8 @@ func New() model.BlockRelationStore { } } -func (brs *blockRelationStore) StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *model.BlockRelations) error { - clone, err := brs.clone(blockRelations) - if err != nil { - return err - } - - brs.staging[*blockHash] = clone - return nil +func (brs *blockRelationStore) StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *model.BlockRelations) { + brs.staging[*blockHash] = blockRelations.Clone() } func (brs *blockRelationStore) IsStaged() bool { @@ -94,12 +88,3 @@ func (brs *blockRelationStore) deserializeBlockRelations(blockRelationsBytes []b } return serialization.DbBlockRelationsToDomainBlockRelations(dbBlockRelations) } - -func (brs *blockRelationStore) clone(blockRelations *model.BlockRelations) (*model.BlockRelations, error) { - serialized, err := brs.serializeBlockRelations(blockRelations) - if err != nil { - return nil, err - } - - return brs.deserializeBlockRelations(serialized) -} diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index 4b62be445..4a9438129 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -24,7 +24,7 @@ func New() model.BlockStatusStore { // Stage stages the given blockStatus for the given blockHash func (bss *blockStatusStore) Stage(blockHash *externalapi.DomainHash, blockStatus externalapi.BlockStatus) { - bss.staging[*blockHash] = blockStatus + bss.staging[*blockHash] = blockStatus.Clone() } func (bss *blockStatusStore) IsStaged() bool { diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index 6824e11d8..b87660677 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -54,14 +54,8 @@ func (bs *blockStore) initializeCount(dbContext model.DBReader) error { } // Stage stages the given block for the given blockHash -func (bs *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error { - clone, err := bs.clone(block) - if err != nil { - return err - } - - bs.staging[*blockHash] = clone - return nil +func (bs *blockStore) Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) { + bs.staging[*blockHash] = block.Clone() } func (bs *blockStore) IsStaged() bool { @@ -169,15 +163,6 @@ func (bs *blockStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } -func (bs *blockStore) clone(block *externalapi.DomainBlock) (*externalapi.DomainBlock, error) { - serialized, err := bs.serializeBlock(block) - if err != nil { - return nil, err - } - - return bs.deserializeBlock(serialized) -} - func (bs *blockStore) Count() uint64 { return bs.count + uint64(len(bs.staging)) - uint64(len(bs.toDelete)) } diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go index 60fab19e3..11d4cdebb 100644 --- a/domain/consensus/datastructures/consensusstatestore/tips.go +++ b/domain/consensus/datastructures/consensusstatestore/tips.go @@ -23,14 +23,8 @@ func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.Dom return c.deserializeTips(tipsBytes) } -func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) error { - clone, err := c.cloneTips(tipHashes) - if err != nil { - return err - } - - c.stagedTips = clone - return nil +func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) { + c.stagedTips = externalapi.CloneHashes(tipHashes) } func (c *consensusStateStore) commitTips(dbTx model.DBTransaction) error { @@ -67,14 +61,3 @@ func (c *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi. return serialization.DBTipsToTips(dbTips) } - -func (c *consensusStateStore) cloneTips(tips []*externalapi.DomainHash, -) ([]*externalapi.DomainHash, error) { - - serialized, err := c.serializeTips(tips) - if err != nil { - return nil, err - } - - return c.deserializeTips(serialized) -} diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index f51dc6b9d..a6d6fd8a8 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -23,7 +23,7 @@ func (c *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODi return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged") } - c.stagedVirtualUTXODiff = c.cloneUTXODiff(virtualUTXODiff) + c.stagedVirtualUTXODiff = virtualUTXODiff.Clone() return nil } @@ -227,35 +227,3 @@ func (c *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.R return nil } - -func (c *consensusStateStore) cloneUTXODiff(diff *model.UTXODiff) *model.UTXODiff { - utxoDiffCopy := &model.UTXODiff{ - ToAdd: make(model.UTXOCollection, len(diff.ToAdd)), - ToRemove: make(model.UTXOCollection, len(diff.ToRemove)), - } - - for outpoint, entry := range diff.ToAdd { - scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey)) - copy(scriptPublicKeyCopy, entry.ScriptPublicKey) - utxoDiffCopy.ToAdd[outpoint] = cloneUTXOEntry(entry) - } - - for outpoint, entry := range diff.ToRemove { - scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey)) - copy(scriptPublicKeyCopy, entry.ScriptPublicKey) - utxoDiffCopy.ToRemove[outpoint] = cloneUTXOEntry(entry) - } - - return diff -} - -func cloneUTXOEntry(entry *externalapi.UTXOEntry) *externalapi.UTXOEntry { - scriptPublicKeyCopy := make([]byte, len(entry.ScriptPublicKey)) - copy(scriptPublicKeyCopy, entry.ScriptPublicKey) - return &externalapi.UTXOEntry{ - Amount: entry.Amount, - ScriptPublicKey: scriptPublicKeyCopy, - BlockBlueScore: entry.BlockBlueScore, - IsCoinbase: entry.IsCoinbase, - } -} diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go index 006353479..eca0b09c0 100644 --- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go +++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go @@ -23,14 +23,8 @@ func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*e return c.deserializeVirtualDiffParents(virtualDiffParentsBytes) } -func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) error { - clone, err := c.cloneVirtualDiffParents(tipHashes) - if err != nil { - return err - } - - c.stagedVirtualDiffParents = clone - return nil +func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) { + c.stagedVirtualDiffParents = externalapi.CloneHashes(tipHashes) } func (c *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { @@ -67,14 +61,3 @@ func (c *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBy return serialization.DBVirtualDiffParentsToVirtualDiffParents(dbVirtualDiffParents) } - -func (c *consensusStateStore) cloneVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash, -) ([]*externalapi.DomainHash, error) { - - serialized, err := c.serializeVirtualDiffParents(virtualDiffParents) - if err != nil { - return nil, err - } - - return c.deserializeVirtualDiffParents(serialized) -} diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index b84f213c7..16f88c4a6 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -23,14 +23,8 @@ func New() model.GHOSTDAGDataStore { } // Stage stages the given blockGHOSTDAGData for the given blockHash -func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) error { - clone, err := gds.clone(blockGHOSTDAGData) - if err != nil { - return err - } - - gds.staging[*blockHash] = clone - return nil +func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { + gds.staging[*blockHash] = blockGHOSTDAGData.Clone() } func (gds *ghostdagDataStore) IsStaged() bool { @@ -89,12 +83,3 @@ func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataByte return serialization.DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData) } - -func (gds *ghostdagDataStore) clone(blockGHOSTDAGData *model.BlockGHOSTDAGData) (*model.BlockGHOSTDAGData, error) { - serialized, err := gds.serializeBlockGHOSTDAGData(blockGHOSTDAGData) - if err != nil { - return nil, err - } - - return gds.deserializeBlockGHOSTDAGData(serialized) -} diff --git a/domain/consensus/datastructures/headertipsstore/headertipsstore.go b/domain/consensus/datastructures/headertipsstore/headertipsstore.go index c404a4318..73da742c9 100644 --- a/domain/consensus/datastructures/headertipsstore/headertipsstore.go +++ b/domain/consensus/datastructures/headertipsstore/headertipsstore.go @@ -45,14 +45,8 @@ func (h *headerTipsStore) Commit(dbTx model.DBTransaction) error { return nil } -func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) error { - clone, err := h.clone(tips) - if err != nil { - return err - } - - h.staging = clone - return nil +func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) { + h.staging = externalapi.CloneHashes(tips) } func (h *headerTipsStore) IsStaged() bool { @@ -87,17 +81,6 @@ func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.Doma return serialization.DBHeaderTipsToHeaderTips(dbTips) } -func (h *headerTipsStore) clone(tips []*externalapi.DomainHash, -) ([]*externalapi.DomainHash, error) { - - serialized, err := h.serializeTips(tips) - if err != nil { - return nil, err - } - - return h.deserializeTips(serialized) -} - // New instantiates a new HeaderTipsStore func New() model.HeaderTipsStore { return &headerTipsStore{} diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go index 176a1bfef..7b00e8e0f 100644 --- a/domain/consensus/datastructures/multisetstore/multisetstore.go +++ b/domain/consensus/datastructures/multisetstore/multisetstore.go @@ -26,7 +26,7 @@ func New() model.MultisetStore { // Stage stages the given multiset for the given blockHash func (ms *multisetStore) Stage(blockHash *externalapi.DomainHash, multiset model.Multiset) { - ms.staging[*blockHash] = multiset + ms.staging[*blockHash] = multiset.Clone() } func (ms *multisetStore) IsStaged() bool { @@ -65,7 +65,7 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error { // Get gets the multiset associated with the given blockHash func (ms *multisetStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.Multiset, error) { if multiset, ok := ms.staging[*blockHash]; ok { - return multiset.Clone() + return multiset.Clone(), nil } multisetBytes, err := dbContext.Get(ms.hashAsKey(blockHash)) diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index e72f531af..0554df00a 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -27,7 +27,7 @@ func New() model.PruningStore { // Stage stages the pruning state func (ps *pruningStore) Stage(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) { - ps.pruningPointStaging = &(*pruningPointBlockHash) + ps.pruningPointStaging = pruningPointBlockHash.Clone() ps.serializedUTXOSetStaging = pruningPointUTXOSetBytes } diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index e7f996cf8..5a8ff74d8 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -27,14 +27,8 @@ func New() model.ReachabilityDataStore { // StageReachabilityData stages the given reachabilityData for the given blockHash func (rds *reachabilityDataStore) StageReachabilityData(blockHash *externalapi.DomainHash, - reachabilityData *model.ReachabilityData) error { - clone, err := rds.cloneReachabilityData(reachabilityData) - if err != nil { - return err - } - - rds.reachabilityDataStaging[*blockHash] = clone - return nil + reachabilityData *model.ReachabilityData) { + rds.reachabilityDataStaging[*blockHash] = reachabilityData.Clone() } // StageReachabilityReindexRoot stages the given reachabilityReindexRoot @@ -151,12 +145,3 @@ func (rds *reachabilityDataStore) deserializeReachabilityReindexRoot(reachabilit return serialization.DbHashToDomainHash(dbHash) } - -func (rds *reachabilityDataStore) cloneReachabilityData(reachabilityData *model.ReachabilityData) (*model.ReachabilityData, error) { - serialized, err := rds.serializeReachabilityData(reachabilityData) - if err != nil { - return nil, err - } - - return rds.deserializeReachabilityData(serialized) -} diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index 584424009..ce70ecce2 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -29,18 +29,12 @@ func New() model.UTXODiffStore { } // Stage stages the given utxoDiff for the given blockHash -func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { - utxoDiffClone, err := uds.cloneUTXODiff(utxoDiff) - if err != nil { - return err - } - uds.utxoDiffStaging[*blockHash] = utxoDiffClone +func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) { + uds.utxoDiffStaging[*blockHash] = utxoDiff.Clone() if utxoDiffChild != nil { - utxoDiffChildClone := uds.cloneUTXODiffChild(utxoDiffChild) - uds.utxoDiffChildStaging[*blockHash] = utxoDiffChildClone + uds.utxoDiffChildStaging[*blockHash] = utxoDiffChild.Clone() } - return nil } func (uds *utxoDiffStore) IsStaged() bool { @@ -203,16 +197,3 @@ func (uds *utxoDiffStore) deserializeUTXODiffChild(utxoDiffChildBytes []byte) (* return serialization.DbHashToDomainHash(dbHash) } - -func (uds *utxoDiffStore) cloneUTXODiff(diff *model.UTXODiff) (*model.UTXODiff, error) { - serialized, err := uds.serializeUTXODiff(diff) - if err != nil { - return nil, err - } - - return uds.deserializeUTXODiff(serialized) -} - -func (uds *utxoDiffStore) cloneUTXODiffChild(diffChild *externalapi.DomainHash) *externalapi.DomainHash { - return diffChild.Clone() -} diff --git a/domain/consensus/model/acceptancedata.go b/domain/consensus/model/acceptancedata.go index 923e715ce..27f79c329 100644 --- a/domain/consensus/model/acceptancedata.go +++ b/domain/consensus/model/acceptancedata.go @@ -6,12 +6,39 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // It's ordered in the same way as the block merge set blues. type AcceptanceData []*BlockAcceptanceData +// Clone clones the AcceptanceData +func (ad AcceptanceData) Clone() AcceptanceData { + if ad == nil { + return nil + } + clone := make(AcceptanceData, len(ad)) + for i, blockAcceptanceData := range ad { + clone[i] = blockAcceptanceData.Clone() + } + + return clone +} + // BlockAcceptanceData stores all transactions in a block with an indication // if they were accepted or not by some other block type BlockAcceptanceData struct { TransactionAcceptanceData []*TransactionAcceptanceData } +// Clone returns a clone of BlockAcceptanceData +func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData { + if bad == nil { + return nil + } + + clone := &BlockAcceptanceData{TransactionAcceptanceData: make([]*TransactionAcceptanceData, len(bad.TransactionAcceptanceData))} + for i, acceptanceData := range bad.TransactionAcceptanceData { + clone.TransactionAcceptanceData[i] = acceptanceData.Clone() + } + + return clone +} + // TransactionAcceptanceData stores a transaction together with an indication // if it was accepted or not by some block type TransactionAcceptanceData struct { @@ -19,3 +46,16 @@ type TransactionAcceptanceData struct { Fee uint64 IsAccepted bool } + +// Clone returns a clone of TransactionAcceptanceData +func (tad *TransactionAcceptanceData) Clone() *TransactionAcceptanceData { + if tad == nil { + return nil + } + + return &TransactionAcceptanceData{ + Transaction: tad.Transaction.Clone(), + Fee: tad.Fee, + IsAccepted: tad.IsAccepted, + } +} diff --git a/domain/consensus/model/blockrelations.go b/domain/consensus/model/blockrelations.go index 5f326ef82..2ed402d46 100644 --- a/domain/consensus/model/blockrelations.go +++ b/domain/consensus/model/blockrelations.go @@ -7,3 +7,15 @@ type BlockRelations struct { Parents []*externalapi.DomainHash Children []*externalapi.DomainHash } + +// Clone returns a clone of BlockRelations +func (br *BlockRelations) Clone() *BlockRelations { + if br == nil { + return nil + } + + return &BlockRelations{ + Parents: externalapi.CloneHashes(br.Parents), + Children: externalapi.CloneHashes(br.Children), + } +} diff --git a/domain/consensus/model/externalapi/block.go b/domain/consensus/model/externalapi/block.go index 522465c47..da4990620 100644 --- a/domain/consensus/model/externalapi/block.go +++ b/domain/consensus/model/externalapi/block.go @@ -6,6 +6,23 @@ type DomainBlock struct { Transactions []*DomainTransaction } +// Clone returns a clone of DomainBlock +func (block *DomainBlock) Clone() *DomainBlock { + if block == nil { + return nil + } + + transactionClone := make([]*DomainTransaction, len(block.Transactions)) + for i, tx := range block.Transactions { + transactionClone[i] = tx.Clone() + } + + return &DomainBlock{ + Header: block.Header.Clone(), + Transactions: transactionClone, + } +} + // DomainBlockHeader represents the header part of a Kaspa block type DomainBlockHeader struct { Version int32 @@ -17,3 +34,21 @@ type DomainBlockHeader struct { Bits uint32 Nonce uint64 } + +// Clone returns a clone of DomainBlockHeader +func (header *DomainBlockHeader) Clone() *DomainBlockHeader { + if header == nil { + return nil + } + + return &DomainBlockHeader{ + Version: header.Version, + ParentHashes: CloneHashes(header.ParentHashes), + HashMerkleRoot: *header.HashMerkleRoot.Clone(), + AcceptedIDMerkleRoot: *header.AcceptedIDMerkleRoot.Clone(), + UTXOCommitment: *header.UTXOCommitment.Clone(), + TimeInMilliseconds: header.TimeInMilliseconds, + Bits: header.Bits, + Nonce: header.Nonce, + } +} diff --git a/domain/consensus/model/externalapi/blockstatus.go b/domain/consensus/model/externalapi/blockstatus.go index 50a9b848b..8fc15cf3f 100644 --- a/domain/consensus/model/externalapi/blockstatus.go +++ b/domain/consensus/model/externalapi/blockstatus.go @@ -3,6 +3,11 @@ package externalapi // BlockStatus represents the validation state of the block. type BlockStatus byte +// Clone returns a clone of BlockStatus +func (bs BlockStatus) Clone() BlockStatus { + return bs +} + const ( // StatusInvalid indicates that the block is invalid. StatusInvalid BlockStatus = iota diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index eb19869b6..40446d6d1 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -22,7 +22,18 @@ func (hash *DomainHash) Clone() *DomainHash { if hash == nil { return nil } - return &*hash + + hashClone := *hash + return &hashClone +} + +// CloneHashes returns a clone of the given hashes slice +func CloneHashes(hashes []*DomainHash) []*DomainHash { + clone := make([]*DomainHash, len(hashes)) + for i, hash := range hashes { + clone[i] = hash.Clone() + } + return clone } // DomainHashesToStrings returns a slice of strings representing the hashes in the given slice of hashes diff --git a/domain/consensus/model/externalapi/subnetworkid.go b/domain/consensus/model/externalapi/subnetworkid.go index 51f580841..8a948dff0 100644 --- a/domain/consensus/model/externalapi/subnetworkid.go +++ b/domain/consensus/model/externalapi/subnetworkid.go @@ -15,3 +15,13 @@ func (id DomainSubnetworkID) String() string { } return hex.EncodeToString(id[:]) } + +// Clone returns a clone of DomainSubnetworkID +func (id *DomainSubnetworkID) Clone() *DomainSubnetworkID { + if id == nil { + return nil + } + + idClone := *id + return &idClone +} diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 63e4a10c3..32959ec6d 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -19,6 +19,39 @@ type DomainTransaction struct { Mass uint64 } +// Clone returns a clone of DomainTransaction +func (tx *DomainTransaction) Clone() *DomainTransaction { + if tx == nil { + return nil + } + + payloadClone := make([]byte, len(tx.Payload)) + copy(payloadClone, tx.Payload) + + inputsClone := make([]*DomainTransactionInput, len(tx.Inputs)) + for i, input := range tx.Inputs { + inputsClone[i] = input.Clone() + } + + outputsClone := make([]*DomainTransactionOutput, len(tx.Outputs)) + for i, output := range tx.Outputs { + outputsClone[i] = output.Clone() + } + + return &DomainTransaction{ + Version: tx.Version, + Inputs: inputsClone, + Outputs: outputsClone, + LockTime: tx.LockTime, + SubnetworkID: *tx.SubnetworkID.Clone(), + Gas: tx.Gas, + PayloadHash: *tx.PayloadHash.Clone(), + Payload: payloadClone, + Fee: tx.Fee, + Mass: tx.Mass, + } +} + // DomainTransactionInput represents a Kaspa transaction input type DomainTransactionInput struct { PreviousOutpoint DomainOutpoint @@ -28,12 +61,41 @@ type DomainTransactionInput struct { UTXOEntry *UTXOEntry } +// Clone returns a clone of DomainTransactionInput +func (input *DomainTransactionInput) Clone() *DomainTransactionInput { + if input == nil { + return nil + } + + signatureScriptClone := make([]byte, len(input.SignatureScript)) + copy(signatureScriptClone, input.SignatureScript) + + return &DomainTransactionInput{ + PreviousOutpoint: *input.PreviousOutpoint.Clone(), + SignatureScript: signatureScriptClone, + Sequence: input.Sequence, + UTXOEntry: input.UTXOEntry.Clone(), + } +} + // DomainOutpoint represents a Kaspa transaction outpoint type DomainOutpoint struct { TransactionID DomainTransactionID Index uint32 } +// Clone returns a clone of DomainOutpoint +func (op *DomainOutpoint) Clone() *DomainOutpoint { + if op == nil { + return nil + } + + return &DomainOutpoint{ + TransactionID: *op.TransactionID.Clone(), + Index: op.Index, + } +} + // String stringifies an outpoint. func (op DomainOutpoint) String() string { return fmt.Sprintf("(%s: %d)", op.TransactionID, op.Index) @@ -53,6 +115,21 @@ type DomainTransactionOutput struct { ScriptPublicKey []byte } +// Clone returns a clone of DomainTransactionOutput +func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput { + if output == nil { + return nil + } + + scriptPublicKeyClone := make([]byte, len(output.ScriptPublicKey)) + copy(scriptPublicKeyClone, output.ScriptPublicKey) + + return &DomainTransactionOutput{ + Value: output.Value, + ScriptPublicKey: scriptPublicKeyClone, + } +} + // DomainTransactionID represents the ID of a Kaspa transaction type DomainTransactionID DomainHash @@ -60,3 +137,13 @@ type DomainTransactionID DomainHash func (id DomainTransactionID) String() string { return DomainHash(id).String() } + +// Clone returns a clone of DomainTransactionID +func (id *DomainTransactionID) Clone() *DomainTransactionID { + if id == nil { + return nil + } + + idClone := *id + return &idClone +} diff --git a/domain/consensus/model/externalapi/utxoentry.go b/domain/consensus/model/externalapi/utxoentry.go index 9aa98c310..69f5a4756 100644 --- a/domain/consensus/model/externalapi/utxoentry.go +++ b/domain/consensus/model/externalapi/utxoentry.go @@ -11,6 +11,23 @@ type UTXOEntry struct { IsCoinbase bool } +// Clone returns a clone of UTXOEntry +func (entry *UTXOEntry) Clone() *UTXOEntry { + if entry == nil { + return nil + } + + scriptPublicKeyClone := make([]byte, len(entry.ScriptPublicKey)) + copy(scriptPublicKeyClone, entry.ScriptPublicKey) + + return &UTXOEntry{ + Amount: entry.Amount, + ScriptPublicKey: scriptPublicKeyClone, + BlockBlueScore: entry.BlockBlueScore, + IsCoinbase: entry.IsCoinbase, + } +} + // NewUTXOEntry creates a new utxoEntry representing the given txOut func NewUTXOEntry(amount uint64, scriptPubKey []byte, isCoinbase bool, blockBlueScore uint64) *UTXOEntry { return &UTXOEntry{ diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go index 335d634af..d649c34aa 100644 --- a/domain/consensus/model/ghostdag.go +++ b/domain/consensus/model/ghostdag.go @@ -11,5 +11,25 @@ type BlockGHOSTDAGData struct { BluesAnticoneSizes map[externalapi.DomainHash]KType } +// Clone returns a clone of BlockGHOSTDAGData +func (bgd *BlockGHOSTDAGData) Clone() *BlockGHOSTDAGData { + if bgd == nil { + return nil + } + + bluesAnticoneSizesClone := make(map[externalapi.DomainHash]KType, len(bgd.BluesAnticoneSizes)) + for hash, size := range bgd.BluesAnticoneSizes { + bluesAnticoneSizesClone[hash] = size + } + + return &BlockGHOSTDAGData{ + BlueScore: bgd.BlueScore, + SelectedParent: bgd.SelectedParent.Clone(), + MergeSetBlues: externalapi.CloneHashes(bgd.MergeSetBlues), + MergeSetReds: externalapi.CloneHashes(bgd.MergeSetReds), + BluesAnticoneSizes: bluesAnticoneSizesClone, + } +} + // KType defines the size of GHOSTDAG consensus algorithm K parameter. type KType byte diff --git a/domain/consensus/model/interface_datastructures_acceptancedatastore.go b/domain/consensus/model/interface_datastructures_acceptancedatastore.go index db656cd49..4d75e1225 100644 --- a/domain/consensus/model/interface_datastructures_acceptancedatastore.go +++ b/domain/consensus/model/interface_datastructures_acceptancedatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // AcceptanceDataStore represents a store of AcceptanceData type AcceptanceDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData) error + Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData) IsStaged() bool Get(dbContext DBReader, blockHash *externalapi.DomainHash) (AcceptanceData, error) Delete(blockHash *externalapi.DomainHash) diff --git a/domain/consensus/model/interface_datastructures_blockheaderstore.go b/domain/consensus/model/interface_datastructures_blockheaderstore.go index e6d5be9b0..20edf9c08 100644 --- a/domain/consensus/model/interface_datastructures_blockheaderstore.go +++ b/domain/consensus/model/interface_datastructures_blockheaderstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockHeaderStore represents a store of block headers type BlockHeaderStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) error + Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) IsStaged() bool BlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) HasBlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_blockrelationstore.go b/domain/consensus/model/interface_datastructures_blockrelationstore.go index e34cca75a..b4274c68e 100644 --- a/domain/consensus/model/interface_datastructures_blockrelationstore.go +++ b/domain/consensus/model/interface_datastructures_blockrelationstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockRelationStore represents a store of BlockRelations type BlockRelationStore interface { Store - StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations) error + StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations) IsStaged() bool BlockRelation(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockRelations, error) Has(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_blockstore.go b/domain/consensus/model/interface_datastructures_blockstore.go index 0ebc8dc69..f2aadb566 100644 --- a/domain/consensus/model/interface_datastructures_blockstore.go +++ b/domain/consensus/model/interface_datastructures_blockstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockStore represents a store of blocks type BlockStore interface { Store - Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) error + Stage(blockHash *externalapi.DomainHash, block *externalapi.DomainBlock) IsStaged() bool Block(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) HasBlock(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_consensusstatestore.go b/domain/consensus/model/interface_datastructures_consensusstatestore.go index 9be748079..022f8c547 100644 --- a/domain/consensus/model/interface_datastructures_consensusstatestore.go +++ b/domain/consensus/model/interface_datastructures_consensusstatestore.go @@ -13,9 +13,9 @@ type ConsensusStateStore interface { HasUTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) VirtualUTXOSetIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error) - StageVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash) error + StageVirtualDiffParents(virtualDiffParents []*externalapi.DomainHash) VirtualDiffParents(dbContext DBReader) ([]*externalapi.DomainHash, error) - StageTips(tipHashes []*externalapi.DomainHash) error + StageTips(tipHashes []*externalapi.DomainHash) Tips(dbContext DBReader) ([]*externalapi.DomainHash, error) } diff --git a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go index 7d8f4c041..13522feb1 100644 --- a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go +++ b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // GHOSTDAGDataStore represents a store of BlockGHOSTDAGData type GHOSTDAGDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) error + Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) IsStaged() bool Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error) } diff --git a/domain/consensus/model/interface_datastructures_headertipsstore.go b/domain/consensus/model/interface_datastructures_headertipsstore.go index b285599b6..df3bc6dca 100644 --- a/domain/consensus/model/interface_datastructures_headertipsstore.go +++ b/domain/consensus/model/interface_datastructures_headertipsstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // HeaderTipsStore represents a store of the header tips type HeaderTipsStore interface { Store - Stage(tips []*externalapi.DomainHash) error + Stage(tips []*externalapi.DomainHash) IsStaged() bool Tips(dbContext DBReader) ([]*externalapi.DomainHash, error) HasTips(dbContext DBReader) (bool, error) diff --git a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go index 5d82c1384..e1225b19e 100644 --- a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go +++ b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // ReachabilityDataStore represents a store of ReachabilityData type ReachabilityDataStore interface { Store - StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData) error + StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData) StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) IsAnythingStaged() bool ReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (*ReachabilityData, error) diff --git a/domain/consensus/model/interface_datastructures_utxodiffstore.go b/domain/consensus/model/interface_datastructures_utxodiffstore.go index 4388d4b32..4d7ab3101 100644 --- a/domain/consensus/model/interface_datastructures_utxodiffstore.go +++ b/domain/consensus/model/interface_datastructures_utxodiffstore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // UTXODiffStore represents a store of UTXODiffs type UTXODiffStore interface { Store - Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash) error + Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash) IsStaged() bool UTXODiff(dbContext DBReader, blockHash *externalapi.DomainHash) (*UTXODiff, error) UTXODiffChild(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) diff --git a/domain/consensus/model/multiset.go b/domain/consensus/model/multiset.go index bf176d0b4..086c42e0e 100644 --- a/domain/consensus/model/multiset.go +++ b/domain/consensus/model/multiset.go @@ -8,5 +8,5 @@ type Multiset interface { Remove(data []byte) Hash() *externalapi.DomainHash Serialize() []byte - Clone() (Multiset, error) + Clone() Multiset } diff --git a/domain/consensus/model/reachabilitydata.go b/domain/consensus/model/reachabilitydata.go index 0efb7b62a..93ffd3b20 100644 --- a/domain/consensus/model/reachabilitydata.go +++ b/domain/consensus/model/reachabilitydata.go @@ -12,6 +12,18 @@ type ReachabilityData struct { FutureCoveringSet FutureCoveringTreeNodeSet } +// Clone returns a clone of ReachabilityData +func (rd *ReachabilityData) Clone() *ReachabilityData { + if rd == nil { + return nil + } + + return &ReachabilityData{ + TreeNode: rd.TreeNode.Clone(), + FutureCoveringSet: externalapi.CloneHashes(rd.FutureCoveringSet), + } +} + // ReachabilityTreeNode represents a node in the reachability tree // of some DAG block. It mainly provides the ability to query *tree* // reachability with O(1) query time. It does so by managing an @@ -36,6 +48,19 @@ type ReachabilityTreeNode struct { Interval *ReachabilityInterval } +// Clone returns a clone of ReachabilityTreeNode +func (rtn *ReachabilityTreeNode) Clone() *ReachabilityTreeNode { + if rtn == nil { + return nil + } + + return &ReachabilityTreeNode{ + Children: externalapi.CloneHashes(rtn.Children), + Parent: rtn.Parent.Clone(), + Interval: rtn.Interval.Clone(), + } +} + // ReachabilityInterval represents an interval to be used within the // tree reachability algorithm. See ReachabilityTreeNode for further // details. @@ -44,6 +69,18 @@ type ReachabilityInterval struct { End uint64 } +// Clone returns a clone of ReachabilityInterval +func (ri *ReachabilityInterval) Clone() *ReachabilityInterval { + if ri == nil { + return nil + } + + return &ReachabilityInterval{ + Start: ri.Start, + End: ri.End, + } +} + func (ri *ReachabilityInterval) String() string { return fmt.Sprintf("[%d,%d]", ri.Start, ri.End) } diff --git a/domain/consensus/model/utxodiff.go b/domain/consensus/model/utxodiff.go index 00f619783..7448f1c0f 100644 --- a/domain/consensus/model/utxodiff.go +++ b/domain/consensus/model/utxodiff.go @@ -11,18 +11,18 @@ import ( // UTXOCollection represents a set of UTXOs indexed by their outpoints type UTXOCollection map[externalapi.DomainOutpoint]*externalapi.UTXOEntry -// UTXODiff represents a diff between two UTXO Sets. -type UTXODiff struct { - ToAdd UTXOCollection - ToRemove UTXOCollection -} - -// NewUTXODiff instantiates an empty UTXODiff -func NewUTXODiff() *UTXODiff { - return &UTXODiff{ - ToAdd: UTXOCollection{}, - ToRemove: UTXOCollection{}, +// Clone returns a clone of UTXOCollection +func (uc UTXOCollection) Clone() UTXOCollection { + if uc == nil { + return nil } + + clone := make(UTXOCollection, len(uc)) + for outpoint, entry := range uc { + clone[outpoint] = entry.Clone() + } + + return clone } func (uc UTXOCollection) String() string { @@ -41,6 +41,32 @@ func (uc UTXOCollection) String() string { return fmt.Sprintf("[ %s ]", strings.Join(utxoStrings, ", ")) } +// UTXODiff represents a diff between two UTXO Sets. +type UTXODiff struct { + ToAdd UTXOCollection + ToRemove UTXOCollection +} + +// Clone returns a clone of UTXODiff +func (d *UTXODiff) Clone() *UTXODiff { + if d == nil { + return nil + } + + return &UTXODiff{ + ToAdd: d.ToAdd.Clone(), + ToRemove: d.ToRemove.Clone(), + } +} + func (d UTXODiff) String() string { return fmt.Sprintf("ToAdd: %s; ToRemove: %s", d.ToAdd, d.ToRemove) } + +// NewUTXODiff instantiates an empty UTXODiff +func NewUTXODiff() *UTXODiff { + return &UTXODiff{ + ToAdd: UTXOCollection{}, + ToRemove: UTXOCollection{}, + } +} diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 1521a1079..667dd23e9 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -83,12 +83,9 @@ func (bb *testBlockBuilder) buildBlockWithParents( } } - err := bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) - if err != nil { - return nil, err - } + bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) - err = bb.ghostdagManager.GHOSTDAG(tempBlockHash) + err := bb.ghostdagManager.GHOSTDAG(tempBlockHash) if err != nil { return nil, err } @@ -111,10 +108,8 @@ func (bb *testBlockBuilder) buildBlockWithParents( if err != nil { return nil, err } - err = bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData) - if err != nil { - return nil, err - } + + bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData) coinbase, err := bb.coinbaseManager.ExpectedCoinbaseTransaction(tempBlockHash, coinbaseData) if err != nil { diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index d7c4c5c00..911a06e01 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -129,10 +129,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) if err != nil { return err } - err = bp.headerTipsStore.Stage(tips) - if err != nil { - return err - } + bp.headerTipsStore.Stage(tips) } if syncInfo.State != externalapi.SyncStateMissingGenesis { @@ -216,10 +213,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex } if !hasHeader { - err = bp.blockHeaderStore.Stage(blockHash, block.Header) - if err != nil { - return err - } + bp.blockHeaderStore.Stage(blockHash, block.Header) } // If any validation until (included) proof-of-work fails, simply @@ -276,12 +270,9 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock blockHash := consensusserialization.BlockHash(block) if mode.State != externalapi.SyncStateHeadersFirst { - err := bp.blockStore.Stage(blockHash, block) - if err != nil { - return err - } + bp.blockStore.Stage(blockHash, block) - err = bp.blockValidator.ValidateBodyInIsolation(blockHash) + err := bp.blockValidator.ValidateBodyInIsolation(blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 29f2588a7..3fe1177a1 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -91,10 +91,7 @@ func TestCheckBlockSanity(t *testing.T) { t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions)) } - err = consensus.BlockStore().Stage(blockHash, &exampleValidBlock) - if err != nil { - t.Fatalf("Failed storing block: %v", err) - } + consensus.BlockStore().Stage(blockHash, &exampleValidBlock) err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) if err != nil { @@ -103,10 +100,7 @@ func TestCheckBlockSanity(t *testing.T) { // Test with block with wrong transactions sorting order blockHash = consensusserialization.BlockHash(&blockWithWrongTxOrder) - err = consensus.BlockStore().Stage(blockHash, &blockWithWrongTxOrder) - if err != nil { - t.Fatalf("Failed storing block: %v", err) - } + consensus.BlockStore().Stage(blockHash, &blockWithWrongTxOrder) err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) { t.Errorf("CheckBlockSanity: Expected ErrTransactionsNotSorted error, instead got %v", err) @@ -115,10 +109,7 @@ func TestCheckBlockSanity(t *testing.T) { // Test a block with invalid parents order // We no longer require blocks to have ordered parents blockHash = consensusserialization.BlockHash(&unOrderedParentsBlock) - err = consensus.BlockStore().Stage(blockHash, &unOrderedParentsBlock) - if err != nil { - t.Fatalf("Failed storing block: %v", err) - } + consensus.BlockStore().Stage(blockHash, &unOrderedParentsBlock) err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) if err != nil { t.Errorf("CheckBlockSanity: Expected block to be be body in isolation valid, got error instead: %v", err) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index 781a15e26..fab862ba2 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -38,13 +38,10 @@ func TestValidateMedianTime(t *testing.T) { pastMedianTime := func(parents ...*externalapi.DomainHash) int64 { var tempHash externalapi.DomainHash - err := tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{ + tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{ Parents: parents, Children: nil, }) - if err != nil { - t.Fatalf("StageBlockRelation: %+v", err) - } defer tc.BlockRelationStore().Discard() err = tc.GHOSTDAGManager().GHOSTDAG(&tempHash) diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 6eca25669..1f60fed01 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -101,10 +101,7 @@ func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (ne } log.Tracef("The new tips are: %s", newTips) - err = csm.consensusStateStore.StageTips(newTips) - if err != nil { - return nil, err - } + csm.consensusStateStore.StageTips(newTips) log.Tracef("Staged the new tips %s", newTips) return newTips, nil diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index c2e2ffdba..1b33df786 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -127,7 +127,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime) multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks)) - accumulatedUTXODiff := utxoalgebra.DiffClone(selectedParentPastUTXODiff) + accumulatedUTXODiff := selectedParentPastUTXODiff.Clone() accumulatedMass := uint64(0) for i, blueBlock := range blueBlocks { diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 57c45e4e7..eb6998f22 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -132,10 +132,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap } log.Tracef("Staging the calculated acceptance data of block %s", blockHash) - err = csm.acceptanceDataStore.Stage(blockHash, acceptanceData) - if err != nil { - return 0, err - } + csm.acceptanceDataStore.Stage(blockHash, acceptanceData) block, err := csm.blockStore.Block(csm.databaseContext, blockHash) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 9f8f58913..83e37e6f4 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -67,10 +67,7 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt log.Tracef("Header tip pruning point multiset validation passed") log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips") - err = csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes) - if err != nil { - return err - } + csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.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) @@ -159,12 +156,10 @@ func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainH 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) - err = csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{ + csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{ Parents: headerTips, }) - if err != nil { - return nil, err - } + defer csm.blockRelationStore.Discard() err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 3a5a36382..001b675c8 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -35,10 +35,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain } log.Tracef("Staging new acceptance data for the virtual block") - err = csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) - if err != nil { - return err - } + csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) log.Tracef("Staging new multiset for the virtual block") csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go index 385f577ab..1f55fb333 100644 --- a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go +++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go @@ -13,10 +13,7 @@ func (csm *consensusStateManager) stageDiff(blockHash *externalapi.DomainHash, defer log.Tracef("stageDiff end for block %s", blockHash) log.Tracef("Staging block %s as the diff child of %s", utxoDiffChild, blockHash) - err := csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild) - if err != nil { - return err - } + csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild) if utxoDiffChild == nil { log.Tracef("Adding block %s to the virtual diff parents", blockHash) @@ -55,7 +52,8 @@ func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi newVirtualDiffParents := append([]*externalapi.DomainHash{blockHash}, oldVirtualDiffParents...) log.Tracef("Staging virtual diff parents after adding %s to it", blockHash) - return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) + csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) + return nil } func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *externalapi.DomainHash) error { @@ -80,5 +78,6 @@ func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *extern } log.Tracef("Staging virtual diff parents after removing %s from it", blockHash) - return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) + csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) + return nil } diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go index 78624d3bc..148ea9269 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go +++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go @@ -48,13 +48,3 @@ func collectionContainsWithBlueScore(collection model.UTXOCollection, outpoint * entry, ok := CollectionGet(collection, outpoint) return ok && entry.BlockBlueScore == blueScore } - -// clone returns a clone of this collection -func collectionClone(collection model.UTXOCollection) model.UTXOCollection { - clone := make(model.UTXOCollection, len(collection)) - for outpoint, entry := range collection { - collectionAdd(clone, &outpoint, entry) - } - - return clone -} diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go index 58bb13f81..9bcaf3f01 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go +++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go @@ -242,7 +242,7 @@ func WithDiffInPlace(this *model.UTXODiff, diff *model.UTXODiff) error { // WithDiff applies provided diff to this diff, creating a new utxoDiff, that would be the result if // first d, and than diff were applied to some base func WithDiff(this *model.UTXODiff, diff *model.UTXODiff) (*model.UTXODiff, error) { - clone := DiffClone(this) + clone := this.Clone() err := WithDiffInPlace(clone, diff) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go index 43c1a954f..e42e9514e 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go +++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go @@ -58,7 +58,7 @@ func TestUTXOCollection(t *testing.T) { } // Test model.UTXOCollection cloning - collectionClone := collectionClone(test.collection) + collectionClone := test.collection.Clone() if reflect.ValueOf(collectionClone).Pointer() == reflect.ValueOf(test.collection).Pointer() { t.Errorf("collection is reference-equal to its clone in test \"%s\". ", test.name) } @@ -95,7 +95,7 @@ func TestUTXODiff(t *testing.T) { } // Test utxoDiff cloning - clonedDiff := DiffClone(diff) + clonedDiff := diff.Clone() if clonedDiff == diff { t.Errorf("cloned diff is reference-equal to the original") } @@ -576,7 +576,7 @@ func TestUTXODiffRules(t *testing.T) { } // Repeat WithDiff check test.this time using withDiffInPlace - thisClone := DiffClone(test.this) + thisClone := test.this.Clone() err = WithDiffInPlace(thisClone, test.other) // Test whether withDiffInPlace returned an error diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go index fc7b5bd05..2eb45829d 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go +++ b/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go @@ -12,15 +12,6 @@ import ( "github.com/pkg/errors" ) -// DiffClone returns a new UTXODiff which is identical to the given diff -func DiffClone(diff *model.UTXODiff) *model.UTXODiff { - clone := &model.UTXODiff{ - ToAdd: collectionClone(diff.ToAdd), - ToRemove: collectionClone(diff.ToRemove), - } - return clone -} - // DiffAddTransaction modifies the provided utxoDiff with provided transaction. func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.DomainTransaction, blockBlueScore uint64) error { for _, input := range transaction.Inputs { diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index cc1a30519..1c430c8af 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -127,10 +127,7 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par for i, parentChild := range parentRelations.Children { if *parentChild == *blockHash { parentRelations.Children = append(parentRelations.Children[:i], parentRelations.Children[i+1:]...) - err = dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations) - if err != nil { - return err - } + dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations) break } @@ -153,21 +150,15 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par } if !isBlockAlreadyInChildren { parentRelations.Children = append(parentRelations.Children, blockHash) - err = dtm.blockRelationStore.StageBlockRelation(parent, parentRelations) - if err != nil { - return err - } + dtm.blockRelationStore.StageBlockRelation(parent, parentRelations) } } // Finally - create the relations for the block itself - err = dtm.blockRelationStore.StageBlockRelation(blockHash, &model.BlockRelations{ + dtm.blockRelationStore.StageBlockRelation(blockHash, &model.BlockRelations{ Parents: parentHashes, Children: []*externalapi.DomainHash{}, }) - if err != nil { - return err - } return nil } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index 230377761..c510959a5 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -82,10 +82,7 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { newBlockData.BlueScore = 0 } - err = gm.ghostdagDataStore.Stage(blockHash, newBlockData) - if err != nil { - return err - } + gm.ghostdagDataStore.Stage(blockHash, newBlockData) return nil } diff --git a/domain/consensus/processes/headertipsmanager/headertipsmanager.go b/domain/consensus/processes/headertipsmanager/headertipsmanager.go index 96ba6544d..5ad81bdbf 100644 --- a/domain/consensus/processes/headertipsmanager/headertipsmanager.go +++ b/domain/consensus/processes/headertipsmanager/headertipsmanager.go @@ -53,10 +53,7 @@ func (h headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error { } newTips = append(newTips, hash) - err = h.headerTipsStore.Stage(newTips) - if err != nil { - return err - } + h.headerTipsStore.Stage(newTips) return nil } diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go index 6b473d101..448ebb031 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go @@ -23,10 +23,9 @@ func (r *reachabilityDataStoreMock) Commit(_ model.DBTransaction) error { panic("implement me") } -func (r *reachabilityDataStoreMock) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) error { +func (r *reachabilityDataStoreMock) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) { r.reachabilityDataStaging[*blockHash] = reachabilityData r.recorder[*blockHash] = struct{}{} - return nil } func (r *reachabilityDataStoreMock) StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) { diff --git a/domain/consensus/processes/reachabilitymanager/stage.go b/domain/consensus/processes/reachabilitymanager/stage.go index 563b42c57..0c38d61d8 100644 --- a/domain/consensus/processes/reachabilitymanager/stage.go +++ b/domain/consensus/processes/reachabilitymanager/stage.go @@ -5,8 +5,8 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) error { - return rt.reachabilityDataStore.StageReachabilityData(blockHash, data) +func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) { + rt.reachabilityDataStore.StageReachabilityData(blockHash, data) } func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.DomainHash, set model.FutureCoveringTreeNodeSet) error { @@ -16,7 +16,8 @@ func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.Dom } data.FutureCoveringSet = set - return rt.reachabilityDataStore.StageReachabilityData(blockHash, data) + rt.reachabilityDataStore.StageReachabilityData(blockHash, data) + return nil } func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash, node *model.ReachabilityTreeNode) error { @@ -26,7 +27,8 @@ func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash, } data.TreeNode = node - return rt.reachabilityDataStore.StageReachabilityData(blockHash, data) + rt.reachabilityDataStore.StageReachabilityData(blockHash, data) + return nil } func (rt *reachabilityManager) stageReindexRoot(blockHash *externalapi.DomainHash) { diff --git a/domain/consensus/utils/multiset/multiset.go b/domain/consensus/utils/multiset/multiset.go index cea53eee0..efda18f91 100644 --- a/domain/consensus/utils/multiset/multiset.go +++ b/domain/consensus/utils/multiset/multiset.go @@ -34,8 +34,9 @@ func (m multiset) Serialize() []byte { return m.ms.Serialize()[:] } -func (m multiset) Clone() (model.Multiset, error) { - return FromBytes(m.Serialize()) +func (m multiset) Clone() model.Multiset { + msClone := *m.ms + return &multiset{ms: &msClone} } // FromBytes deserializes the given bytes slice and returns a multiset. From 3bad9ec1ebd19de244b9da0e8ad912e1b02d0aa4 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 25 Nov 2020 01:30:07 -0800 Subject: [PATCH 088/351] [NOD-1569] Stop using ReceiveFromChanWhenDone (#1151) --- app/protocol/flows/handshake/handshake.go | 22 +++++++++++-------- .../64_incoming_connections_test.go | 14 +++++++++--- testing/integration/ibd_test.go | 4 +--- util/locks/receive_from_chan_when_done.go | 11 ---------- 4 files changed, 25 insertions(+), 26 deletions(-) delete mode 100644 util/locks/receive_from_chan_when_done.go diff --git a/app/protocol/flows/handshake/handshake.go b/app/protocol/flows/handshake/handshake.go index 515ff5b56..8f305d859 100644 --- a/app/protocol/flows/handshake/handshake.go +++ b/app/protocol/flows/handshake/handshake.go @@ -1,7 +1,6 @@ package handshake import ( - "sync" "sync/atomic" "github.com/kaspanet/kaspad/domain" @@ -16,7 +15,6 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" - "github.com/kaspanet/kaspad/util/locks" "github.com/pkg/errors" ) @@ -38,10 +36,12 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N ) (*peerpkg.Peer, error) { // For HandleHandshake to finish, we need to get from the other node - // a version and verack messages, so we increase the wait group by 2 - // and block HandleHandshake with wg.Wait(). - wg := sync.WaitGroup{} - wg.Add(2) + // a version and verack messages, so we set doneCount to 2, decrease it + // when sending and receiving the version, and close the doneChan when + // it's 0. Then we wait for on select for a tick from doneChan or from + // errChan. + doneCount := int32(2) + doneChan := make(chan struct{}) isStopping := uint32(0) errChan := make(chan error) @@ -56,7 +56,9 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N return } peerAddress = address - wg.Done() + if atomic.AddInt32(&doneCount, -1) == 0 { + close(doneChan) + } }) spawn("HandleHandshake-SendVersion", func() { @@ -65,7 +67,9 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N handleError(err, "SendVersion", &isStopping, errChan) return } - wg.Done() + if atomic.AddInt32(&doneCount, -1) == 0 { + close(doneChan) + } }) select { @@ -74,7 +78,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N return nil, err } return nil, nil - case <-locks.ReceiveFromChanWhenDone(func() { wg.Wait() }): + case <-doneChan: } err := context.AddToPeers(peer) diff --git a/testing/integration/64_incoming_connections_test.go b/testing/integration/64_incoming_connections_test.go index edc3055ca..3ac4a8699 100644 --- a/testing/integration/64_incoming_connections_test.go +++ b/testing/integration/64_incoming_connections_test.go @@ -6,8 +6,6 @@ import ( "testing" "time" - "github.com/kaspanet/kaspad/util/locks" - "github.com/kaspanet/kaspad/app/appmessage" ) @@ -56,6 +54,16 @@ func Test64IncomingConnections(t *testing.T) { select { case <-time.After(defaultTimeout): t.Fatalf("Timeout waiting for block added notification from the bullies") - case <-locks.ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }): + case <-ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }): } } + +// ReceiveFromChanWhenDone takes a blocking function and returns a channel that sends an empty struct when the function is done. +func ReceiveFromChanWhenDone(callback func()) <-chan struct{} { + ch := make(chan struct{}) + spawn("ReceiveFromChanWhenDone", func() { + callback() + close(ch) + }) + return ch +} diff --git a/testing/integration/ibd_test.go b/testing/integration/ibd_test.go index 1fb26ca67..78b39fc8a 100644 --- a/testing/integration/ibd_test.go +++ b/testing/integration/ibd_test.go @@ -5,8 +5,6 @@ import ( "testing" "time" - "github.com/kaspanet/kaspad/util/locks" - "github.com/kaspanet/kaspad/app/appmessage" ) @@ -33,7 +31,7 @@ func TestIBD(t *testing.T) { select { case <-time.After(defaultTimeout): t.Fatalf("Timeout waiting for IBD to finish. Received %d blocks out of %d", receivedBlocks, numBlocks) - case <-locks.ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }): + case <-ReceiveFromChanWhenDone(func() { blockAddedWG.Wait() }): } tip1Hash, err := syncer.rpcClient.GetSelectedTipHash() diff --git a/util/locks/receive_from_chan_when_done.go b/util/locks/receive_from_chan_when_done.go deleted file mode 100644 index 759b6c657..000000000 --- a/util/locks/receive_from_chan_when_done.go +++ /dev/null @@ -1,11 +0,0 @@ -package locks - -// ReceiveFromChanWhenDone takes a blocking function and returns a channel that sends an empty struct when the function is done. -func ReceiveFromChanWhenDone(callback func()) <-chan struct{} { - ch := make(chan struct{}) - spawn("ReceiveFromChanWhenDone", func() { - callback() - close(ch) - }) - return ch -} From 5b2fae04570a102340a42f494486321c5066e5a9 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 25 Nov 2020 01:43:51 -0800 Subject: [PATCH 089/351] [NOD-1568] Add staticcheck checks (#1150) --- app/protocol/flowcontext/blocks.go | 2 +- docker/Dockerfile | 2 +- domain/consensus/database/transaction.go | 2 +- .../consensusstatemanager/verify_and_build_utxo.go | 4 ++-- domain/miningmanager/mempool/mempool.go | 4 +++- domain/miningmanager/miningmanager.go | 6 +++--- domain/miningmanager/model/interface_mempool.go | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index ca92e2db5..b5361a26f 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -26,7 +26,7 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { for _, newBlock := range newBlocks { blocklogger.LogBlock(block) - f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) + _ = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) if f.onBlockAddedToDAGHandler != nil { err := f.onBlockAddedToDAGHandler(newBlock) diff --git a/docker/Dockerfile b/docker/Dockerfile index 7ef305f88..11a1098c0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -26,7 +26,7 @@ RUN golint -set_exit_status ./... # RUN aligncheck ./... # RUN structcheck -e ./... # RUN varcheck -e ./... -RUN staticcheck -checks SA4006 ./... +RUN staticcheck -checks "SA4006,SA4008,SA4009,SA4010,SA5003,SA1004,SA1014,SA1021,SA1023,SA1024,SA1025,SA1026,SA1027,SA1028,SA2000,SA2001,SA2003,SA4000,SA4001,SA4003,SA4004,SA4011,SA4012,SA4013,SA4014,SA4015,SA4016,SA4017,SA4018,SA4019,SA4020,SA4021,SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002,SA9003,SA9004,SA9005,SA9006,ST1019" ./... RUN GOOS=linux go build -a -installsuffix cgo -o kaspad . # Remove the line below and uncomment the line after it for testing with coverage diff --git a/domain/consensus/database/transaction.go b/domain/consensus/database/transaction.go index 807150bbe..9f17bc544 100644 --- a/domain/consensus/database/transaction.go +++ b/domain/consensus/database/transaction.go @@ -26,7 +26,7 @@ func (d *dbTransaction) Commit() error { } func (d *dbTransaction) RollbackUnlessClosed() error { - return d.RollbackUnlessClosed() + return d.transaction.RollbackUnlessClosed() } func newDBTransaction(transaction database.Transaction) model.DBTransaction { diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 0b6966209..c38c32cee 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -48,7 +48,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) + err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff) if err != nil { return err } @@ -58,7 +58,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo } func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock, - blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff, err error) error { + blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash) defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash) diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 99ebf0e1d..908ffb5f4 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -858,7 +858,7 @@ func (mp *mempool) Transactions() []*consensusexternalapi.DomainTransaction { // from the mempool and the orphan pool, and it also removes // from the mempool transactions that double spend a // transaction that is already in the DAG -func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) { +func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction { // Protect concurrent access. mp.mtx.Lock() defer mp.mtx.Unlock() @@ -886,6 +886,8 @@ func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.Domain acceptedTxs = append(acceptedTxs, acceptedOrphan.DomainTransaction) } } + + return acceptedTxs } func (mp *mempool) RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) { diff --git a/domain/miningmanager/miningmanager.go b/domain/miningmanager/miningmanager.go index a9e166bff..82b66a1ef 100644 --- a/domain/miningmanager/miningmanager.go +++ b/domain/miningmanager/miningmanager.go @@ -10,7 +10,7 @@ import ( type MiningManager interface { GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) - HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) + HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error } @@ -25,8 +25,8 @@ func (mm *miningManager) GetBlockTemplate(coinbaseData *consensusexternalapi.Dom } // HandleNewBlock handles the transactions for a new block that was just added to the DAG -func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) { - mm.mempool.HandleNewBlockTransactions(txs) +func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction { + return mm.mempool.HandleNewBlockTransactions(txs) } // ValidateAndInsertTransaction validates the given transaction, and diff --git a/domain/miningmanager/model/interface_mempool.go b/domain/miningmanager/model/interface_mempool.go index ee010a3cc..20bb8ff37 100644 --- a/domain/miningmanager/model/interface_mempool.go +++ b/domain/miningmanager/model/interface_mempool.go @@ -7,7 +7,7 @@ import ( // Mempool maintains a set of known transactions that // are intended to be mined into new blocks type Mempool interface { - HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) + HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction Transactions() []*consensusexternalapi.DomainTransaction ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) From 0fa13357c3f91e8d7cf75fc527f596e8c93eee74 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 25 Nov 2020 13:41:13 +0200 Subject: [PATCH 090/351] [NOD-1566] Add caching to all stores (#1152) * [NOD-1566] Add a dependency to golang-lru. * [NOD-1566] Add caching to blockstore.go. * [NOD-1566] Add LRUCache to all store objects and initialize them. * [NOD-1566] Add caching to acceptanceDataStore. * [NOD-1566] Add caching to blockHeaderStore. * [NOD-1566] Implement a simpler LRU cache. * [NOD-1566] Use the simpler cache implementation everywhere. * [NOD-1566] Remove dependency in golang-lru. * [NOD-1566] Fix object reuse issues in store Get functions. * [NOD-1566] Add caching to blockRelationStore. * [NOD-1566] Add caching to blockStatusStore. * [NOD-1566] Add caching to ghostdagDataStore. * [NOD-1566] Add caching to multisetStore. * [NOD-1566] Add caching to reachabilityDataStore. * [NOD-1566] Add caching to utxoDiffStore. * [NOD-1566] Add caching to reachabilityReindexRoot. * [NOD-1566] Add caching to pruningStore. * [NOD-1566] Add caching to headerTipsStore. * [NOD-1566] Add caching to consensusStateStore. * [NOD-1566] Add comments explaining why we don't discard staging at the normal location in consensusStateStore. * [NOD-1566] Make go vet happy. * [NOD-1566] Fix merge errors. * [NOD-1566] Add a missing break statement. * [NOD-1566] Run go mod tidy. * [NOD-1566] Remove serializedUTXOSetCache. --- .../acceptancedatastore.go | 20 ++++- .../blockheaderstore/blockheaderstore.go | 24 +++++- .../blockrelationstore/blockrelationstore.go | 23 +++++- .../blockstatusstore/blockstatusstore.go | 21 ++++- .../datastructures/blockstore/blockstore.go | 24 +++++- .../consensusstatestore.go | 41 +++++----- .../consensusstatestore/tips.go | 35 ++++++--- .../consensusstatestore/utxo.go | 76 ++++++++++--------- .../virtual_diff_parents.go | 35 ++++++--- .../ghostdagdatastore/ghostdagdatastore.go | 20 ++++- .../headertipsstore/headertipsstore.go | 64 ++++++++++------ .../multisetstore/multisetstore.go | 19 ++++- .../pruningstore/pruningstore.go | 29 ++++--- .../reachabilitydatastore.go | 36 +++++++-- .../utxodiffstore/utxodiffstore.go | 38 ++++++++-- domain/consensus/factory.go | 19 ++--- domain/consensus/utils/lrucache/lrucache.go | 59 ++++++++++++++ go.sum | 2 - 18 files changed, 427 insertions(+), 158 deletions(-) create mode 100644 domain/consensus/utils/lrucache/lrucache.go diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index f4e060c81..f19a4402a 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -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/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" "google.golang.org/protobuf/proto" ) @@ -14,13 +15,15 @@ var bucket = dbkeys.MakeBucket([]byte("acceptance-data")) type acceptanceDataStore struct { staging map[externalapi.DomainHash]model.AcceptanceData toDelete map[externalapi.DomainHash]struct{} + cache *lrucache.LRUCache } // New instantiates a new AcceptanceDataStore -func New() model.AcceptanceDataStore { +func New(cacheSize int) model.AcceptanceDataStore { return &acceptanceDataStore{ staging: make(map[externalapi.DomainHash]model.AcceptanceData), toDelete: make(map[externalapi.DomainHash]struct{}), + cache: lrucache.New(cacheSize), } } @@ -48,6 +51,7 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + ads.cache.Add(&hash, acceptanceData) } for hash := range ads.toDelete { @@ -55,6 +59,7 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + ads.cache.Remove(&hash) } ads.Discard() @@ -64,7 +69,11 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error { // Get gets the acceptanceData associated with the given blockHash func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.AcceptanceData, error) { if acceptanceData, ok := ads.staging[*blockHash]; ok { - return acceptanceData, nil + return acceptanceData.Clone(), nil + } + + if acceptanceData, ok := ads.cache.Get(blockHash); ok { + return acceptanceData.(model.AcceptanceData).Clone(), nil } acceptanceDataBytes, err := dbContext.Get(ads.hashAsKey(blockHash)) @@ -72,7 +81,12 @@ func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externa return nil, err } - return ads.deserializeAcceptanceData(acceptanceDataBytes) + acceptanceData, err := ads.deserializeAcceptanceData(acceptanceDataBytes) + if err != nil { + return nil, err + } + ads.cache.Add(blockHash, acceptanceData) + return acceptanceData.Clone(), nil } // Delete deletes the acceptanceData associated with the given blockHash diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index b68734433..81934893b 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var bucket = dbkeys.MakeBucket([]byte("block-headers")) @@ -15,14 +16,16 @@ var countKey = dbkeys.MakeBucket().Key([]byte("block-headers-count")) type blockHeaderStore struct { staging map[externalapi.DomainHash]*externalapi.DomainBlockHeader toDelete map[externalapi.DomainHash]struct{} + cache *lrucache.LRUCache count uint64 } // New instantiates a new BlockHeaderStore -func New(dbContext model.DBReader) (model.BlockHeaderStore, error) { +func New(dbContext model.DBReader, cacheSize int) (model.BlockHeaderStore, error) { blockHeaderStore := &blockHeaderStore{ staging: make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader), toDelete: make(map[externalapi.DomainHash]struct{}), + cache: lrucache.New(cacheSize), } err := blockHeaderStore.initializeCount(dbContext) @@ -77,6 +80,7 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + bhs.cache.Add(&hash, header) } for hash := range bhs.toDelete { @@ -84,6 +88,7 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + bhs.cache.Remove(&hash) } err := bhs.commitCount(dbTx) @@ -98,7 +103,11 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error { // BlockHeader gets the block header associated with the given blockHash func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { if header, ok := bhs.staging[*blockHash]; ok { - return header, nil + return header.Clone(), nil + } + + if header, ok := bhs.cache.Get(blockHash); ok { + return header.(*externalapi.DomainBlockHeader).Clone(), nil } headerBytes, err := dbContext.Get(bhs.hashAsKey(blockHash)) @@ -106,7 +115,12 @@ func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *ex return nil, err } - return bhs.deserializeHeader(headerBytes) + header, err := bhs.deserializeHeader(headerBytes) + if err != nil { + return nil, err + } + bhs.cache.Add(blockHash, header) + return header.Clone(), nil } // HasBlock returns whether a block header with a given hash exists in the store. @@ -115,6 +129,10 @@ func (bhs *blockHeaderStore) HasBlockHeader(dbContext model.DBReader, blockHash return true, nil } + if bhs.cache.Has(blockHash) { + return true, nil + } + exists, err := dbContext.Has(bhs.hashAsKey(blockHash)) if err != nil { return false, err diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index 8389628fd..64b69e5cf 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var bucket = dbkeys.MakeBucket([]byte("block-relations")) @@ -13,12 +14,14 @@ var bucket = dbkeys.MakeBucket([]byte("block-relations")) // blockRelationStore represents a store of BlockRelations type blockRelationStore struct { staging map[externalapi.DomainHash]*model.BlockRelations + cache *lrucache.LRUCache } // New instantiates a new BlockRelationStore -func New() model.BlockRelationStore { +func New(cacheSize int) model.BlockRelationStore { return &blockRelationStore{ staging: make(map[externalapi.DomainHash]*model.BlockRelations), + cache: lrucache.New(cacheSize), } } @@ -44,6 +47,7 @@ func (brs *blockRelationStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + brs.cache.Add(&hash, blockRelations) } brs.Discard() @@ -52,7 +56,11 @@ func (brs *blockRelationStore) Commit(dbTx model.DBTransaction) error { func (brs *blockRelationStore) BlockRelation(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockRelations, error) { if blockRelations, ok := brs.staging[*blockHash]; ok { - return blockRelations, nil + return blockRelations.Clone(), nil + } + + if blockRelations, ok := brs.cache.Get(blockHash); ok { + return blockRelations.(*model.BlockRelations).Clone(), nil } blockRelationsBytes, err := dbContext.Get(brs.hashAsKey(blockHash)) @@ -60,7 +68,12 @@ func (brs *blockRelationStore) BlockRelation(dbContext model.DBReader, blockHash return nil, err } - return brs.deserializeBlockRelations(blockRelationsBytes) + blockRelations, err := brs.deserializeBlockRelations(blockRelationsBytes) + if err != nil { + return nil, err + } + brs.cache.Add(blockHash, blockRelations) + return blockRelations.Clone(), nil } func (brs *blockRelationStore) Has(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { @@ -68,6 +81,10 @@ func (brs *blockRelationStore) Has(dbContext model.DBReader, blockHash *external return true, nil } + if brs.cache.Has(blockHash) { + return true, nil + } + return dbContext.Has(brs.hashAsKey(blockHash)) } diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index 4a9438129..943d3ad5c 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var bucket = dbkeys.MakeBucket([]byte("block-statuses")) @@ -13,12 +14,14 @@ var bucket = dbkeys.MakeBucket([]byte("block-statuses")) // blockStatusStore represents a store of BlockStatuses type blockStatusStore struct { staging map[externalapi.DomainHash]externalapi.BlockStatus + cache *lrucache.LRUCache } // New instantiates a new BlockStatusStore -func New() model.BlockStatusStore { +func New(cacheSize int) model.BlockStatusStore { return &blockStatusStore{ staging: make(map[externalapi.DomainHash]externalapi.BlockStatus), + cache: lrucache.New(cacheSize), } } @@ -45,6 +48,7 @@ func (bss *blockStatusStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + bss.cache.Add(&hash, status) } bss.Discard() @@ -57,12 +61,21 @@ func (bss *blockStatusStore) Get(dbContext model.DBReader, blockHash *externalap return status, nil } + if status, ok := bss.cache.Get(blockHash); ok { + return status.(externalapi.BlockStatus), nil + } + statusBytes, err := dbContext.Get(bss.hashAsKey(blockHash)) if err != nil { return 0, err } - return bss.deserializeBlockStatus(statusBytes) + status, err := bss.deserializeBlockStatus(statusBytes) + if err != nil { + return 0, err + } + bss.cache.Add(blockHash, status) + return status, nil } // Exists returns true if the blockStatus for the given blockHash exists @@ -71,6 +84,10 @@ func (bss *blockStatusStore) Exists(dbContext model.DBReader, blockHash *externa return true, nil } + if bss.cache.Has(blockHash) { + return true, nil + } + exists, err := dbContext.Has(bss.hashAsKey(blockHash)) if err != nil { return false, err diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index b87660677..20c51efb1 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var bucket = dbkeys.MakeBucket([]byte("blocks")) @@ -15,14 +16,16 @@ var countKey = dbkeys.MakeBucket().Key([]byte("blocks-count")) type blockStore struct { staging map[externalapi.DomainHash]*externalapi.DomainBlock toDelete map[externalapi.DomainHash]struct{} + cache *lrucache.LRUCache count uint64 } // New instantiates a new BlockStore -func New(dbContext model.DBReader) (model.BlockStore, error) { +func New(dbContext model.DBReader, cacheSize int) (model.BlockStore, error) { blockStore := &blockStore{ staging: make(map[externalapi.DomainHash]*externalapi.DomainBlock), toDelete: make(map[externalapi.DomainHash]struct{}), + cache: lrucache.New(cacheSize), } err := blockStore.initializeCount(dbContext) @@ -77,6 +80,7 @@ func (bs *blockStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + bs.cache.Add(&hash, block) } for hash := range bs.toDelete { @@ -84,6 +88,7 @@ func (bs *blockStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + bs.cache.Remove(&hash) } err := bs.commitCount(dbTx) @@ -98,7 +103,11 @@ func (bs *blockStore) Commit(dbTx model.DBTransaction) error { // Block gets the block associated with the given blockHash func (bs *blockStore) Block(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { if block, ok := bs.staging[*blockHash]; ok { - return block, nil + return block.Clone(), nil + } + + if block, ok := bs.cache.Get(blockHash); ok { + return block.(*externalapi.DomainBlock).Clone(), nil } blockBytes, err := dbContext.Get(bs.hashAsKey(blockHash)) @@ -106,7 +115,12 @@ func (bs *blockStore) Block(dbContext model.DBReader, blockHash *externalapi.Dom return nil, err } - return bs.deserializeBlock(blockBytes) + block, err := bs.deserializeBlock(blockBytes) + if err != nil { + return nil, err + } + bs.cache.Add(blockHash, block) + return block.Clone(), nil } // HasBlock returns whether a block with a given hash exists in the store. @@ -115,6 +129,10 @@ func (bs *blockStore) HasBlock(dbContext model.DBReader, blockHash *externalapi. return true, nil } + if bs.cache.Has(blockHash) { + return true, nil + } + exists, err := dbContext.Has(bs.hashAsKey(blockHash)) if err != nil { return false, err diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go index c2cf22ef1..c0ea148e4 100644 --- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go +++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go @@ -7,10 +7,13 @@ import ( // consensusStateStore represents a store for the current consensus state type consensusStateStore struct { - stagedTips []*externalapi.DomainHash - stagedVirtualDiffParents []*externalapi.DomainHash - stagedVirtualUTXODiff *model.UTXODiff - stagedVirtualUTXOSet model.UTXOCollection + tipsStaging []*externalapi.DomainHash + virtualDiffParentsStaging []*externalapi.DomainHash + virtualUTXODiffStaging *model.UTXODiff + virtualUTXOSetStaging model.UTXOCollection + + tipsCache []*externalapi.DomainHash + virtualDiffParentsCache []*externalapi.DomainHash } // New instantiates a new ConsensusStateStore @@ -18,40 +21,40 @@ func New() model.ConsensusStateStore { return &consensusStateStore{} } -func (c *consensusStateStore) Discard() { - c.stagedTips = nil - c.stagedVirtualUTXODiff = nil - c.stagedVirtualDiffParents = nil - c.stagedVirtualUTXOSet = nil +func (css *consensusStateStore) Discard() { + css.tipsStaging = nil + css.virtualUTXODiffStaging = nil + css.virtualDiffParentsStaging = nil + css.virtualUTXOSetStaging = nil } -func (c *consensusStateStore) Commit(dbTx model.DBTransaction) error { - err := c.commitTips(dbTx) +func (css *consensusStateStore) Commit(dbTx model.DBTransaction) error { + err := css.commitTips(dbTx) if err != nil { return err } - err = c.commitVirtualDiffParents(dbTx) + err = css.commitVirtualDiffParents(dbTx) if err != nil { return err } - err = c.commitVirtualUTXODiff(dbTx) + err = css.commitVirtualUTXODiff(dbTx) if err != nil { return err } - err = c.commitVirtualUTXOSet(dbTx) + err = css.commitVirtualUTXOSet(dbTx) if err != nil { return err } - c.Discard() + css.Discard() return nil } -func (c *consensusStateStore) IsStaged() bool { - return c.stagedTips != nil || - c.stagedVirtualDiffParents != nil || - c.stagedVirtualUTXODiff != nil +func (css *consensusStateStore) IsStaged() bool { + return css.tipsStaging != nil || + css.virtualDiffParentsStaging != nil || + css.virtualUTXODiffStaging != nil } diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go index 11d4cdebb..c9cb4400c 100644 --- a/domain/consensus/datastructures/consensusstatestore/tips.go +++ b/domain/consensus/datastructures/consensusstatestore/tips.go @@ -10,9 +10,13 @@ import ( var tipsKey = dbkeys.MakeBucket().Key([]byte("tips")) -func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { - if c.stagedTips != nil { - return c.stagedTips, nil +func (css *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { + if css.tipsStaging != nil { + return externalapi.CloneHashes(css.tipsStaging), nil + } + + if css.tipsCache != nil { + return externalapi.CloneHashes(css.tipsCache), nil } tipsBytes, err := dbContext.Get(tipsKey) @@ -20,37 +24,44 @@ func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.Dom return nil, err } - return c.deserializeTips(tipsBytes) + tips, err := css.deserializeTips(tipsBytes) + if err != nil { + return nil, err + } + css.tipsCache = tips + return externalapi.CloneHashes(tips), nil } -func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) { - c.stagedTips = externalapi.CloneHashes(tipHashes) +func (css *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) { + css.tipsStaging = externalapi.CloneHashes(tipHashes) } -func (c *consensusStateStore) commitTips(dbTx model.DBTransaction) error { - if c.stagedTips == nil { +func (css *consensusStateStore) commitTips(dbTx model.DBTransaction) error { + if css.tipsStaging == nil { return nil } - tipsBytes, err := c.serializeTips(c.stagedTips) + tipsBytes, err := css.serializeTips(css.tipsStaging) if err != nil { return err } - err = dbTx.Put(tipsKey, tipsBytes) if err != nil { return err } + css.tipsCache = css.tipsStaging + // Note: we don't discard the staging here since that's + // being done at the end of Commit() return nil } -func (c *consensusStateStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { +func (css *consensusStateStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { dbTips := serialization.TipsToDBTips(tips) return proto.Marshal(dbTips) } -func (c *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, +func (css *consensusStateStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) { dbTips := &serialization.DbTips{} diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index a6d6fd8a8..fe510a714 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -18,21 +18,21 @@ func utxoKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) { return utxoSetBucket.Key(serializedOutpoint), nil } -func (c *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error { - if c.stagedVirtualUTXOSet != nil { +func (css *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error { + if css.virtualUTXOSetStaging != nil { return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged") } - c.stagedVirtualUTXODiff = virtualUTXODiff.Clone() + css.virtualUTXODiffStaging = virtualUTXODiff.Clone() return nil } -func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error { - if c.stagedVirtualUTXODiff == nil { +func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error { + if css.virtualUTXODiffStaging == nil { return nil } - for toRemoveOutpoint := range c.stagedVirtualUTXODiff.ToRemove { + for toRemoveOutpoint := range css.virtualUTXODiffStaging.ToRemove { dbKey, err := utxoKey(&toRemoveOutpoint) if err != nil { return err @@ -43,7 +43,7 @@ func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) er } } - for toAddOutpoint, toAddEntry := range c.stagedVirtualUTXODiff.ToAdd { + for toAddOutpoint, toAddEntry := range css.virtualUTXODiffStaging.ToAdd { dbKey, err := utxoKey(&toAddOutpoint) if err != nil { return err @@ -58,15 +58,17 @@ func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) er } } + // Note: we don't discard the staging here since that's + // being done at the end of Commit() return nil } -func (c *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error { - if c.stagedVirtualUTXOSet == nil { +func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error { + if css.virtualUTXOSetStaging == nil { return nil } - for outpoint, utxoEntry := range c.stagedVirtualUTXOSet { + for outpoint, utxoEntry := range css.virtualUTXOSetStaging { dbKey, err := utxoKey(&outpoint) if err != nil { return err @@ -81,28 +83,30 @@ func (c *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) err } } + // Note: we don't discard the staging here since that's + // being done at the end of Commit() return nil } -func (c *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( +func (css *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( *externalapi.UTXOEntry, error) { - if c.stagedVirtualUTXOSet != nil { - return c.utxoByOutpointFromStagedVirtualUTXOSet(outpoint) + if css.virtualUTXOSetStaging != nil { + return css.utxoByOutpointFromStagedVirtualUTXOSet(outpoint) } - return c.utxoByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) + return css.utxoByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) } -func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, +func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( *externalapi.UTXOEntry, error) { - if c.stagedVirtualUTXODiff != nil { - if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok { + if css.virtualUTXODiffStaging != nil { + if _, ok := css.virtualUTXODiffStaging.ToRemove[*outpoint]; ok { return nil, errors.Errorf("outpoint was not found") } - if utxoEntry, ok := c.stagedVirtualUTXODiff.ToAdd[*outpoint]; ok { + if utxoEntry, ok := css.virtualUTXODiffStaging.ToAdd[*outpoint]; ok { return utxoEntry, nil } } @@ -120,31 +124,31 @@ func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext return deserializeUTXOEntry(serializedUTXOEntry) } -func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( +func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( *externalapi.UTXOEntry, error) { - if utxoEntry, ok := c.stagedVirtualUTXOSet[*outpoint]; ok { + if utxoEntry, ok := css.virtualUTXOSetStaging[*outpoint]; ok { return utxoEntry, nil } return nil, errors.Errorf("outpoint was not found") } -func (c *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { - if c.stagedVirtualUTXOSet != nil { - return c.hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint), nil +func (css *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { + if css.virtualUTXOSetStaging != nil { + return css.hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint), nil } - return c.hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) + return css.hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) } -func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, +func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { - if c.stagedVirtualUTXODiff != nil { - if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok { + if css.virtualUTXODiffStaging != nil { + if _, ok := css.virtualUTXODiffStaging.ToRemove[*outpoint]; ok { return false, nil } - if _, ok := c.stagedVirtualUTXODiff.ToAdd[*outpoint]; ok { + if _, ok := css.virtualUTXODiffStaging.ToAdd[*outpoint]; ok { return true, nil } } @@ -157,12 +161,12 @@ func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbConte return dbContext.Has(key) } -func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool { - _, ok := c.stagedVirtualUTXOSet[*outpoint] +func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool { + _, ok := css.virtualUTXOSetStaging[*outpoint] return ok } -func (c *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { +func (css *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { cursor, err := dbContext.Cursor(utxoSetBucket) if err != nil { return nil, err @@ -207,22 +211,22 @@ func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry return outpoint, utxoEntry, nil } -func (c *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error { - if c.stagedVirtualUTXODiff != nil { +func (css *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error { + if css.virtualUTXODiffStaging != nil { return errors.New("cannot stage virtual UTXO set while virtual UTXO diff is staged") } - c.stagedVirtualUTXOSet = make(model.UTXOCollection) + css.virtualUTXOSetStaging = make(model.UTXOCollection) for virtualUTXOSetIterator.Next() { outpoint, entry, err := virtualUTXOSetIterator.Get() if err != nil { return err } - if _, exists := c.stagedVirtualUTXOSet[*outpoint]; exists { + if _, exists := css.virtualUTXOSetStaging[*outpoint]; exists { return errors.Errorf("outpoint %s is found more than once in the given iterator", outpoint) } - c.stagedVirtualUTXOSet[*outpoint] = entry + css.virtualUTXOSetStaging[*outpoint] = entry } return nil diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go index eca0b09c0..c834a191f 100644 --- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go +++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go @@ -10,9 +10,13 @@ import ( var virtualDiffParentsKey = dbkeys.MakeBucket().Key([]byte("virtual-diff-parents")) -func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { - if c.stagedVirtualDiffParents != nil { - return c.stagedVirtualDiffParents, nil +func (css *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { + if css.virtualDiffParentsStaging != nil { + return externalapi.CloneHashes(css.virtualDiffParentsStaging), nil + } + + if css.virtualDiffParentsCache != nil { + return externalapi.CloneHashes(css.virtualDiffParentsCache), nil } virtualDiffParentsBytes, err := dbContext.Get(virtualDiffParentsKey) @@ -20,37 +24,44 @@ func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*e return nil, err } - return c.deserializeVirtualDiffParents(virtualDiffParentsBytes) + virtualDiffParents, err := css.deserializeVirtualDiffParents(virtualDiffParentsBytes) + if err != nil { + return nil, err + } + css.virtualDiffParentsCache = virtualDiffParents + return externalapi.CloneHashes(virtualDiffParents), nil } -func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) { - c.stagedVirtualDiffParents = externalapi.CloneHashes(tipHashes) +func (css *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) { + css.virtualDiffParentsStaging = externalapi.CloneHashes(tipHashes) } -func (c *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { - if c.stagedVirtualDiffParents == nil { +func (css *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { + if css.virtualDiffParentsStaging == nil { return nil } - virtualDiffParentsBytes, err := c.serializeVirtualDiffParents(c.stagedVirtualDiffParents) + virtualDiffParentsBytes, err := css.serializeVirtualDiffParents(css.virtualDiffParentsStaging) if err != nil { return err } - err = dbTx.Put(virtualDiffParentsKey, virtualDiffParentsBytes) if err != nil { return err } + css.virtualDiffParentsCache = css.virtualDiffParentsStaging + // Note: we don't discard the staging here since that's + // being done at the end of Commit() return nil } -func (c *consensusStateStore) serializeVirtualDiffParents(virtualDiffParentsBytes []*externalapi.DomainHash) ([]byte, error) { +func (css *consensusStateStore) serializeVirtualDiffParents(virtualDiffParentsBytes []*externalapi.DomainHash) ([]byte, error) { virtualDiffParents := serialization.VirtualDiffParentsToDBHeaderVirtualDiffParents(virtualDiffParentsBytes) return proto.Marshal(virtualDiffParents) } -func (c *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBytes []byte) ([]*externalapi.DomainHash, +func (css *consensusStateStore) deserializeVirtualDiffParents(virtualDiffParentsBytes []byte) ([]*externalapi.DomainHash, error) { dbVirtualDiffParents := &serialization.DbVirtualDiffParents{} diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index 16f88c4a6..aaa096a16 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data")) @@ -13,12 +14,14 @@ var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data")) // ghostdagDataStore represents a store of BlockGHOSTDAGData type ghostdagDataStore struct { staging map[externalapi.DomainHash]*model.BlockGHOSTDAGData + cache *lrucache.LRUCache } // New instantiates a new GHOSTDAGDataStore -func New() model.GHOSTDAGDataStore { +func New(cacheSize int) model.GHOSTDAGDataStore { return &ghostdagDataStore{ staging: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), + cache: lrucache.New(cacheSize), } } @@ -41,11 +44,11 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } - err = dbTx.Put(gds.hashAsKey(&hash), blockGhostdagDataBytes) if err != nil { return err } + gds.cache.Add(&hash, blockGHOSTDAGData) } gds.Discard() @@ -55,7 +58,11 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { // Get gets the blockGHOSTDAGData associated with the given blockHash func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { if blockGHOSTDAGData, ok := gds.staging[*blockHash]; ok { - return blockGHOSTDAGData, nil + return blockGHOSTDAGData.Clone(), nil + } + + if blockGHOSTDAGData, ok := gds.cache.Get(blockHash); ok { + return blockGHOSTDAGData.(*model.BlockGHOSTDAGData).Clone(), nil } blockGHOSTDAGDataBytes, err := dbContext.Get(gds.hashAsKey(blockHash)) @@ -63,7 +70,12 @@ func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externala return nil, err } - return gds.deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes) + blockGHOSTDAGData, err := gds.deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes) + if err != nil { + return nil, err + } + gds.cache.Add(blockHash, blockGHOSTDAGData) + return blockGHOSTDAGData.Clone(), nil } func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { diff --git a/domain/consensus/datastructures/headertipsstore/headertipsstore.go b/domain/consensus/datastructures/headertipsstore/headertipsstore.go index 73da742c9..cb36b6ee1 100644 --- a/domain/consensus/datastructures/headertipsstore/headertipsstore.go +++ b/domain/consensus/datastructures/headertipsstore/headertipsstore.go @@ -12,50 +12,64 @@ var headerTipsKey = dbkeys.MakeBucket().Key([]byte("header-tips")) type headerTipsStore struct { staging []*externalapi.DomainHash + cache []*externalapi.DomainHash } -func (h *headerTipsStore) HasTips(dbContext model.DBReader) (bool, error) { - if h.staging != nil { - return len(h.staging) > 0, nil +// 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 (h *headerTipsStore) Discard() { - h.staging = nil +func (hts *headerTipsStore) Discard() { + hts.staging = nil } -func (h *headerTipsStore) Commit(dbTx model.DBTransaction) error { - if h.staging == nil { +func (hts *headerTipsStore) Commit(dbTx model.DBTransaction) error { + if hts.staging == nil { return nil } - tipsBytes, err := h.serializeTips(h.staging) + 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 - h.Discard() + hts.Discard() return nil } -func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) { - h.staging = externalapi.CloneHashes(tips) +func (hts *headerTipsStore) Stage(tips []*externalapi.DomainHash) { + hts.staging = externalapi.CloneHashes(tips) } -func (h *headerTipsStore) IsStaged() bool { - return h.staging != nil +func (hts *headerTipsStore) IsStaged() bool { + return hts.staging != nil } -func (h *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { - if h.staging != nil { - return h.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) @@ -63,15 +77,20 @@ func (h *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainH return nil, err } - return h.deserializeTips(tipsBytes) + tips, err := hts.deserializeTips(tipsBytes) + if err != nil { + return nil, err + } + hts.cache = tips + return externalapi.CloneHashes(tips), nil } -func (h *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { +func (hts *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { dbTips := serialization.HeaderTipsToDBHeaderTips(tips) return proto.Marshal(dbTips) } -func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) { +func (hts *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) { dbTips := &serialization.DbHeaderTips{} err := proto.Unmarshal(tipsBytes, dbTips) if err != nil { @@ -80,8 +99,3 @@ func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.Doma return serialization.DBHeaderTipsToHeaderTips(dbTips) } - -// New instantiates a new HeaderTipsStore -func New() model.HeaderTipsStore { - return &headerTipsStore{} -} diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go index 7b00e8e0f..17aa680c5 100644 --- a/domain/consensus/datastructures/multisetstore/multisetstore.go +++ b/domain/consensus/datastructures/multisetstore/multisetstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var bucket = dbkeys.MakeBucket([]byte("multisets")) @@ -14,13 +15,15 @@ var bucket = dbkeys.MakeBucket([]byte("multisets")) type multisetStore struct { staging map[externalapi.DomainHash]model.Multiset toDelete map[externalapi.DomainHash]struct{} + cache *lrucache.LRUCache } // New instantiates a new MultisetStore -func New() model.MultisetStore { +func New(cacheSize int) model.MultisetStore { return &multisetStore{ staging: make(map[externalapi.DomainHash]model.Multiset), toDelete: make(map[externalapi.DomainHash]struct{}), + cache: lrucache.New(cacheSize), } } @@ -44,11 +47,11 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } - err = dbTx.Put(ms.hashAsKey(&hash), multisetBytes) if err != nil { return err } + ms.cache.Add(&hash, multiset) } for hash := range ms.toDelete { @@ -56,6 +59,7 @@ func (ms *multisetStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + ms.cache.Remove(&hash) } ms.Discard() @@ -68,12 +72,21 @@ func (ms *multisetStore) Get(dbContext model.DBReader, blockHash *externalapi.Do return multiset.Clone(), nil } + if multiset, ok := ms.cache.Get(blockHash); ok { + return multiset.(model.Multiset).Clone(), nil + } + multisetBytes, err := dbContext.Get(ms.hashAsKey(blockHash)) if err != nil { return nil, err } - return ms.deserializeMultiset(multisetBytes) + multiset, err := ms.deserializeMultiset(multisetBytes) + if err != nil { + return nil, err + } + ms.cache.Add(blockHash, multiset) + return multiset.Clone(), nil } // Delete deletes the multiset associated with the given blockHash diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index 0554df00a..646f6bbac 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -15,14 +15,12 @@ var pruningSerializedUTXOSetkey = dbkeys.MakeBucket().Key([]byte("pruning-utxo-s type pruningStore struct { pruningPointStaging *externalapi.DomainHash serializedUTXOSetStaging []byte + pruningPointCache *externalapi.DomainHash } // New instantiates a new PruningStore func New() model.PruningStore { - return &pruningStore{ - pruningPointStaging: nil, - serializedUTXOSetStaging: nil, - } + return &pruningStore{} } // Stage stages the pruning state @@ -50,6 +48,7 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + ps.pruningPointCache = ps.pruningPointStaging } if ps.serializedUTXOSetStaging != nil { @@ -57,7 +56,6 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } - err = dbTx.Put(pruningSerializedUTXOSetkey, utxoSetBytes) if err != nil { return err @@ -74,16 +72,21 @@ func (ps *pruningStore) PruningPoint(dbContext model.DBReader) (*externalapi.Dom return ps.pruningPointStaging, nil } - blockHashBytes, err := dbContext.Get(pruningBlockHashKey) + if ps.pruningPointCache != nil { + return ps.pruningPointCache, nil + } + + pruningPointBytes, err := dbContext.Get(pruningBlockHashKey) if err != nil { return nil, err } - blockHash, err := ps.deserializePruningPoint(blockHashBytes) + pruningPoint, err := ps.deserializePruningPoint(pruningPointBytes) if err != nil { return nil, err } - return blockHash, nil + ps.pruningPointCache = pruningPoint + return pruningPoint, nil } // PruningPointSerializedUTXOSet returns the serialized UTXO set of the current pruning point @@ -97,7 +100,11 @@ func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader) return nil, err } - return ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes) + pruningPointUTXOSet, err := ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes) + if err != nil { + return nil, err + } + return pruningPointUTXOSet, nil } func (ps *pruningStore) serializePruningPoint(pruningPoint *externalapi.DomainHash) ([]byte, error) { @@ -133,5 +140,9 @@ func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader) (bool, error) return true, nil } + if ps.pruningPointCache != nil { + return true, nil + } + return dbContext.Has(pruningBlockHashKey) } diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index 5a8ff74d8..f466e9d9c 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) var reachabilityDataBucket = dbkeys.MakeBucket([]byte("reachability-data")) @@ -15,13 +16,15 @@ var reachabilityReindexRootKey = dbkeys.MakeBucket().Key([]byte("reachability-re type reachabilityDataStore struct { reachabilityDataStaging map[externalapi.DomainHash]*model.ReachabilityData reachabilityReindexRootStaging *externalapi.DomainHash + reachabilityDataCache *lrucache.LRUCache + reachabilityReindexRootCache *externalapi.DomainHash } // New instantiates a new ReachabilityDataStore -func New() model.ReachabilityDataStore { +func New(cacheSize int) model.ReachabilityDataStore { return &reachabilityDataStore{ - reachabilityDataStaging: make(map[externalapi.DomainHash]*model.ReachabilityData), - reachabilityReindexRootStaging: nil, + reachabilityDataStaging: make(map[externalapi.DomainHash]*model.ReachabilityData), + reachabilityDataCache: lrucache.New(cacheSize), } } @@ -51,22 +54,22 @@ func (rds *reachabilityDataStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } - err = dbTx.Put(reachabilityReindexRootKey, reachabilityReindexRootBytes) if err != nil { return err } + rds.reachabilityReindexRootCache = rds.reachabilityReindexRootStaging } for hash, reachabilityData := range rds.reachabilityDataStaging { reachabilityDataBytes, err := rds.serializeReachabilityData(reachabilityData) if err != nil { return err } - err = dbTx.Put(rds.reachabilityDataBlockHashAsKey(&hash), reachabilityDataBytes) if err != nil { return err } + rds.reachabilityDataCache.Add(&hash, reachabilityData) } rds.Discard() @@ -78,7 +81,11 @@ func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) { if reachabilityData, ok := rds.reachabilityDataStaging[*blockHash]; ok { - return reachabilityData, nil + return reachabilityData.Clone(), nil + } + + if reachabilityData, ok := rds.reachabilityDataCache.Get(blockHash); ok { + return reachabilityData.(*model.ReachabilityData).Clone(), nil } reachabilityDataBytes, err := dbContext.Get(rds.reachabilityDataBlockHashAsKey(blockHash)) @@ -86,7 +93,12 @@ func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader, return nil, err } - return rds.deserializeReachabilityData(reachabilityDataBytes) + reachabilityData, err := rds.deserializeReachabilityData(reachabilityDataBytes) + if err != nil { + return nil, err + } + rds.reachabilityDataCache.Add(blockHash, reachabilityData) + return reachabilityData.Clone(), nil } func (rds *reachabilityDataStore) HasReachabilityData(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { @@ -94,6 +106,10 @@ func (rds *reachabilityDataStore) HasReachabilityData(dbContext model.DBReader, return true, nil } + if rds.reachabilityDataCache.Has(blockHash) { + return true, nil + } + return dbContext.Has(rds.reachabilityDataBlockHashAsKey(blockHash)) } @@ -102,6 +118,11 @@ func (rds *reachabilityDataStore) ReachabilityReindexRoot(dbContext model.DBRead if rds.reachabilityReindexRootStaging != nil { return rds.reachabilityReindexRootStaging, nil } + + if rds.reachabilityReindexRootCache != nil { + return rds.reachabilityReindexRootCache, nil + } + reachabilityReindexRootBytes, err := dbContext.Get(reachabilityReindexRootKey) if err != nil { return nil, err @@ -111,6 +132,7 @@ func (rds *reachabilityDataStore) ReachabilityReindexRoot(dbContext model.DBRead if err != nil { return nil, err } + rds.reachabilityReindexRootCache = reachabilityReindexRoot return reachabilityReindexRoot, nil } diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index ce70ecce2..ea0b14dcb 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" "github.com/pkg/errors" ) @@ -17,14 +18,18 @@ type utxoDiffStore struct { utxoDiffStaging map[externalapi.DomainHash]*model.UTXODiff utxoDiffChildStaging map[externalapi.DomainHash]*externalapi.DomainHash toDelete map[externalapi.DomainHash]struct{} + utxoDiffCache *lrucache.LRUCache + utxoDiffChildCache *lrucache.LRUCache } // New instantiates a new UTXODiffStore -func New() model.UTXODiffStore { +func New(cacheSize int) model.UTXODiffStore { return &utxoDiffStore{ utxoDiffStaging: make(map[externalapi.DomainHash]*model.UTXODiff), utxoDiffChildStaging: make(map[externalapi.DomainHash]*externalapi.DomainHash), toDelete: make(map[externalapi.DomainHash]struct{}), + utxoDiffCache: lrucache.New(cacheSize), + utxoDiffChildCache: lrucache.New(cacheSize), } } @@ -61,11 +66,11 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } - err = dbTx.Put(uds.utxoDiffHashAsKey(&hash), utxoDiffBytes) if err != nil { return err } + uds.utxoDiffCache.Add(&hash, utxoDiff) } for hash, utxoDiffChild := range uds.utxoDiffChildStaging { if utxoDiffChild == nil { @@ -80,6 +85,7 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + uds.utxoDiffChildCache.Add(&hash, utxoDiffChild) } for hash := range uds.toDelete { @@ -87,11 +93,13 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { if err != nil { return err } + uds.utxoDiffCache.Remove(&hash) err = dbTx.Delete(uds.utxoDiffChildHashAsKey(&hash)) if err != nil { return err } + uds.utxoDiffChildCache.Remove(&hash) } uds.Discard() @@ -101,7 +109,11 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { // UTXODiff gets the utxoDiff associated with the given blockHash func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.UTXODiff, error) { if utxoDiff, ok := uds.utxoDiffStaging[*blockHash]; ok { - return utxoDiff, nil + return utxoDiff.Clone(), nil + } + + if utxoDiff, ok := uds.utxoDiffCache.Get(blockHash); ok { + return utxoDiff.(*model.UTXODiff).Clone(), nil } utxoDiffBytes, err := dbContext.Get(uds.utxoDiffHashAsKey(blockHash)) @@ -109,13 +121,22 @@ func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *external return nil, err } - return uds.deserializeUTXODiff(utxoDiffBytes) + utxoDiff, err := uds.deserializeUTXODiff(utxoDiffBytes) + if err != nil { + return nil, err + } + uds.utxoDiffCache.Add(blockHash, utxoDiff) + return utxoDiff.Clone(), nil } // UTXODiffChild gets the utxoDiff child associated with the given blockHash func (uds *utxoDiffStore) UTXODiffChild(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { if utxoDiffChild, ok := uds.utxoDiffChildStaging[*blockHash]; ok { - return utxoDiffChild, nil + return utxoDiffChild.Clone(), nil + } + + if utxoDiffChild, ok := uds.utxoDiffChildCache.Get(blockHash); ok { + return utxoDiffChild.(*externalapi.DomainHash).Clone(), nil } utxoDiffChildBytes, err := dbContext.Get(uds.utxoDiffChildHashAsKey(blockHash)) @@ -127,7 +148,8 @@ func (uds *utxoDiffStore) UTXODiffChild(dbContext model.DBReader, blockHash *ext if err != nil { return nil, err } - return utxoDiffChild, nil + uds.utxoDiffChildCache.Add(blockHash, utxoDiffChild) + return utxoDiffChild.Clone(), nil } // HasUTXODiffChild returns true if the given blockHash has a UTXODiffChild @@ -136,6 +158,10 @@ func (uds *utxoDiffStore) HasUTXODiffChild(dbContext model.DBReader, blockHash * return true, nil } + if uds.utxoDiffChildCache.Has(blockHash) { + return true, nil + } + return dbContext.Has(uds.utxoDiffChildHashAsKey(blockHash)) } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 5ea856d72..5d68536de 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -62,23 +62,24 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager := consensusdatabase.New(db) // Data Structures - acceptanceDataStore := acceptancedatastore.New() - blockStore, err := blockstore.New(dbManager) + storeCacheSize := int(dagParams.FinalityDepth()) + acceptanceDataStore := acceptancedatastore.New(storeCacheSize) + blockStore, err := blockstore.New(dbManager, storeCacheSize) if err != nil { return nil, err } - blockHeaderStore, err := blockheaderstore.New(dbManager) + blockHeaderStore, err := blockheaderstore.New(dbManager, storeCacheSize) if err != nil { return nil, err } - blockRelationStore := blockrelationstore.New() - blockStatusStore := blockstatusstore.New() - multisetStore := multisetstore.New() + blockRelationStore := blockrelationstore.New(storeCacheSize) + blockStatusStore := blockstatusstore.New(storeCacheSize) + multisetStore := multisetstore.New(storeCacheSize) pruningStore := pruningstore.New() - reachabilityDataStore := reachabilitydatastore.New() - utxoDiffStore := utxodiffstore.New() + reachabilityDataStore := reachabilitydatastore.New(storeCacheSize) + utxoDiffStore := utxodiffstore.New(storeCacheSize) consensusStateStore := consensusstatestore.New() - ghostdagDataStore := ghostdagdatastore.New() + ghostdagDataStore := ghostdagdatastore.New(storeCacheSize) headerTipsStore := headertipsstore.New() // Processes diff --git a/domain/consensus/utils/lrucache/lrucache.go b/domain/consensus/utils/lrucache/lrucache.go new file mode 100644 index 000000000..94b175a0d --- /dev/null +++ b/domain/consensus/utils/lrucache/lrucache.go @@ -0,0 +1,59 @@ +package lrucache + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// LRUCache is a least-recently-used cache for any type +// that's able to be indexed by DomainHash +type LRUCache struct { + cache map[externalapi.DomainHash]interface{} + capacity int +} + +// New creates a new LRUCache +func New(capacity int) *LRUCache { + return &LRUCache{ + cache: make(map[externalapi.DomainHash]interface{}, capacity+1), + capacity: capacity, + } +} + +// Add adds an entry to the LRUCache +func (c *LRUCache) Add(key *externalapi.DomainHash, value interface{}) { + c.cache[*key] = value + + if len(c.cache) > c.capacity { + c.evictRandom() + } +} + +// Get returns the entry for the given key, or (nil, false) otherwise +func (c *LRUCache) Get(key *externalapi.DomainHash) (interface{}, bool) { + value, ok := c.cache[*key] + if !ok { + return nil, false + } + return value, true +} + +// Has returns whether the LRUCache contains the given key +func (c *LRUCache) Has(key *externalapi.DomainHash) bool { + _, ok := c.cache[*key] + return ok +} + +// Remove removes the entry for the the given key. Does nothing if +// the entry does not exist +func (c *LRUCache) Remove(key *externalapi.DomainHash) { + delete(c.cache, *key) +} + +func (c *LRUCache) evictRandom() { + var keyToEvict externalapi.DomainHash + for key := range c.cache { + keyToEvict = key + break + } + c.Remove(&keyToEvict) +} diff --git a/go.sum b/go.sum index 0598d276a..8bfb2dbe2 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,6 @@ github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= From f9c213734473ecf3ea6b99b60a508ff0f80f50de Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 25 Nov 2020 13:42:55 +0200 Subject: [PATCH 091/351] [RES-65] Add a test for BoundedMergeDepth - new (#1131) * Test bounded merge depth * Fix a bug in GetBlockInfo, where trying to use reachability on an invalid block * Add a test to reproduce and test the GetBlockInfo bug --- domain/consensus/consensus.go | 5 + domain/consensus/consensus_test.go | 75 +++++++++ domain/consensus/finality_test.go | 251 +++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 domain/consensus/consensus_test.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 3a8903ee3..fa07ae484 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -124,6 +124,11 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap } blockInfo.BlockStatus = blockStatus + // If the status is invalid, then we don't have the necessary reachability data to check if it's in PruningPoint.Future. + if blockStatus == externalapi.StatusInvalid { + return blockInfo, nil + } + isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash) if err != nil { return nil, err diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go new file mode 100644 index 000000000..af64f73e9 --- /dev/null +++ b/domain/consensus/consensus_test.go @@ -0,0 +1,75 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" + "testing" +) + +func TestConsensus_GetBlockInfo(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := NewFactory() + consensus, teardown, err := factory.NewTestConsensus(params, "TestConsensus_GetBlockInfo") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + invalidBlock, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + invalidBlock.Header.TimeInMilliseconds = 0 + 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) + } + + info, err := consensus.GetBlockInfo(consensusserialization.BlockHash(invalidBlock)) + if err != nil { + t.Fatalf("Failed to get block info: %v", err) + } + + if !info.Exists { + t.Fatal("The block is missing") + } + 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) + if err != nil { + t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err) + } + + err = consensus.ValidateAndInsertBlock(validBlock) + if err != nil { + t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err) + } + + info, err = consensus.GetBlockInfo(consensusserialization.BlockHash(validBlock)) + if err != nil { + t.Fatalf("Failed to get block info: %v", err) + } + + if !info.Exists { + t.Fatal("The block is missing") + } + 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) + } + + }) +} diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 24af2edb9..5cf6532e6 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -1,11 +1,16 @@ package consensus import ( + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" + "fmt" "testing" ) @@ -167,3 +172,249 @@ func TestFinality(t *testing.T) { } }) } + +func TestBoundedMergeDepth(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // Set finalityInterval to 50 blocks, so that test runs quickly + params.FinalityDuration = 50 * params.TargetTimePerBlock + finalityInterval := int(params.FinalityDepth()) + + if int(params.K) >= finalityInterval { + t.Fatal("K must be smaller than finality duration for this test to run") + } + + checkViolatingMergeDepth := func(consensus testapi.TestConsensus, parents []*externalapi.DomainHash) (*externalapi.DomainBlock, bool) { + block, err := consensus.BuildBlockWithParents(parents, nil, nil) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: BuildBlockWithParents failed: %v", err) + return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns + } + + err = consensus.ValidateAndInsertBlock(block) + if err == nil { + return block, false + } else if errors.Is(err, ruleerrors.ErrViolatingBoundedMergeDepth) { + return block, true + } else { + t.Fatalf("TestBoundedMergeDepth: expected err: %v, found err: %v", ruleerrors.ErrViolatingBoundedMergeDepth, err) + return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns + } + } + + processBlock := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock, name string) { + err := consensus.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: %s got unexpected error from ProcessBlock: %+v", name, err) + + } + } + + buildAndInsertBlock := func(consensus testapi.TestConsensus, parentHashes []*externalapi.DomainHash) *externalapi.DomainBlock { + block, err := consensus.BuildBlockWithParents(parentHashes, nil, nil) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed building block: %v", err) + } + err = consensus.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed Inserting block to consensus: %v", err) + } + return block + } + + getStatus := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock) externalapi.BlockStatus { + blockInfo, err := consensus.GetBlockInfo(consensusserialization.BlockHash(block)) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed to get block info: %v", err) + } else if !blockInfo.Exists { + t.Fatalf("TestBoundedMergeDepth: Failed to get block info, block doesn't exists") + } + return blockInfo.BlockStatus + } + + factory := NewFactory() + consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, "BoundedMergeTestBuild") + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) + } + + consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, "BoundedMergeTestReal") + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) + } + defer teardownFunc2() + + // Create a block on top on genesis + block1 := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{params.GenesisHash}) + + // Create a chain + selectedChain := make([]*externalapi.DomainBlock, 0, finalityInterval+1) + parent := consensusserialization.BlockHash(block1) + // Make sure this is always bigger than `blocksChain2` so it will stay the selected chain + for i := 0; i < finalityInterval+2; i++ { + block := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{parent}) + selectedChain = append(selectedChain, block) + parent = consensusserialization.BlockHash(block) + } + + // Create another chain + blocksChain2 := make([]*externalapi.DomainBlock, 0, finalityInterval+1) + parent = consensusserialization.BlockHash(block1) + for i := 0; i < finalityInterval+1; i++ { + block := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{parent}) + blocksChain2 = append(blocksChain2, block) + parent = consensusserialization.BlockHash(block) + } + + // Teardown and assign nil to make sure we use the right DAG from here on. + teardownFunc1() + consensusBuild = nil + + // Now test against the real DAG + // submit block1 + processBlock(consensusReal, block1, "block1") + + // submit chain1 + for i, block := range selectedChain { + processBlock(consensusReal, block, fmt.Sprintf("selectedChain block No %d", i)) + } + + // submit chain2 + for i, block := range blocksChain2 { + processBlock(consensusReal, block, fmt.Sprintf("blocksChain2 block No %d", i)) + } + + // submit a block pointing at tip(chain1) and on first block in chain2 directly + mergeDepthViolatingBlockBottom, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[0]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])}) + if !isViolatingMergeDepth { + t.Fatalf("TestBoundedMergeDepth: Expected mergeDepthViolatingBlockBottom to violate merge depth") + } + + // submit a block pointing at tip(chain1) and tip(chain2) should also obviously violate merge depth (this points at first block in chain2 indirectly) + mergeDepthViolatingTop, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[len(blocksChain2)-1]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])}) + if !isViolatingMergeDepth { + t.Fatalf("TestBoundedMergeDepth: Expected mergeDepthViolatingTop to violate merge depth") + } + + // the location of the parents in the slices need to be both `-X` so the `selectedChain` one will have higher blueScore (it's a chain longer by 1) + kosherizingBlock, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[len(blocksChain2)-3]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-3])}) + kosherizingBlockHash := consensusserialization.BlockHash(kosherizingBlock) + if isViolatingMergeDepth { + t.Fatalf("TestBoundedMergeDepth: Expected blueKosherizingBlock to not violate merge depth") + } + + virtualGhotDagData, err := consensusReal.GHOSTDAGDataStore().Get(consensusReal.DatabaseContext(), model.VirtualBlockHash) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed getting the ghostdag data of the virtual: %v", err) + } + // Make sure it's actually blue + found := false + for _, blue := range virtualGhotDagData.MergeSetBlues { + if *blue == *kosherizingBlockHash { + found = true + break + } + } + if !found { + t.Fatalf("TestBoundedMergeDepth: Expected kosherizingBlock to be blue by the virtual") + } + + pointAtBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{kosherizingBlockHash, consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])}) + if isViolatingMergeDepth { + + t.Fatalf("TestBoundedMergeDepth: Expected selectedTip to not violate merge depth") + } + + virtualSelectedParent, err := consensusReal.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) + } + + if *consensusserialization.BlockHash(virtualSelectedParent) != *consensusserialization.BlockHash(pointAtBlueKosherizing) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensusserialization.BlockHash(pointAtBlueKosherizing), consensusserialization.BlockHash(virtualSelectedParent)) + } + + // Now let's make the kosherizing block red and try to merge again + tip := consensusserialization.BlockHash(selectedChain[len(selectedChain)-1]) + // we use k-1 because `kosherizingBlock` points at tip-2, so 2+k-1 = k+1 anticone. + for i := 0; i < int(params.K)-1; i++ { + block := buildAndInsertBlock(consensusReal, []*externalapi.DomainHash{tip}) + tip = consensusserialization.BlockHash(block) + } + + virtualSelectedParent, err = consensusReal.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) + } + + if *consensusserialization.BlockHash(virtualSelectedParent) != *tip { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, consensusserialization.BlockHash(virtualSelectedParent)) + } + + virtualGhotDagData, err = consensusReal.GHOSTDAGDataStore().Get(consensusReal.DatabaseContext(), model.VirtualBlockHash) + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed getting the ghostdag data of the virtual: %v", err) + } + // Make sure it's actually blue + found = false + for _, blue := range virtualGhotDagData.MergeSetBlues { + if *blue == *kosherizingBlockHash { + found = true + break + } + } + if found { + t.Fatalf("expected kosherizingBlock to be red by the virtual") + } + + pointAtRedKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{kosherizingBlockHash, tip}) + if !isViolatingMergeDepth { + t.Fatalf("TestBoundedMergeDepth: Expected selectedTipRedKosherize to violate merge depth") + } + + // Now `pointAtBlueKosherizing` itself is actually still blue, so we can still point at that even though we can't point at kosherizing directly anymore + transitiveBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(pointAtBlueKosherizing), tip}) + if isViolatingMergeDepth { + t.Fatalf("TestBoundedMergeDepth: Expected transitiveBlueKosherizing to not violate merge depth") + } + + virtualSelectedParent, err = consensusReal.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) + } + + if *consensusserialization.BlockHash(virtualSelectedParent) != *consensusserialization.BlockHash(transitiveBlueKosherizing) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensusserialization.BlockHash(transitiveBlueKosherizing), consensusserialization.BlockHash(virtualSelectedParent)) + } + + // Lets validate the status of all the interesting blocks + if getStatus(consensusReal, pointAtBlueKosherizing) != externalapi.StatusValid { + t.Fatalf("TestBoundedMergeDepth: pointAtBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, pointAtBlueKosherizing)) + } + if getStatus(consensusReal, pointAtRedKosherizing) != externalapi.StatusInvalid { + t.Fatalf("TestBoundedMergeDepth: pointAtRedKosherizing expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, pointAtRedKosherizing)) + } + if getStatus(consensusReal, transitiveBlueKosherizing) != externalapi.StatusValid { + t.Fatalf("TestBoundedMergeDepth: transitiveBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, transitiveBlueKosherizing)) + } + if getStatus(consensusReal, mergeDepthViolatingBlockBottom) != externalapi.StatusInvalid { + t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingBlockBottom expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingBlockBottom)) + } + if getStatus(consensusReal, mergeDepthViolatingTop) != externalapi.StatusInvalid { + t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingTop expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingTop)) + } + if getStatus(consensusReal, kosherizingBlock) != externalapi.StatusUTXOPendingVerification { + t.Fatalf("kosherizingBlock expected status '%s' but got '%s'", externalapi.StatusUTXOPendingVerification, getStatus(consensusReal, kosherizingBlock)) + } + + for i, b := range blocksChain2 { + if getStatus(consensusReal, b) != externalapi.StatusUTXOPendingVerification { + t.Fatalf("blocksChain2[%d] expected status '%s' but got '%s'", i, externalapi.StatusUTXOPendingVerification, getStatus(consensusReal, b)) + } + } + for i, b := range selectedChain { + if getStatus(consensusReal, b) != externalapi.StatusValid { + t.Fatalf("selectedChain[%d] expected status '%s' but got '%s'", i, externalapi.StatusValid, getStatus(consensusReal, b)) + } + } + }) +} From 546ea8312351edf93bcf9ab16bf1ebdcca9fa0a6 Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 25 Nov 2020 18:28:42 +0200 Subject: [PATCH 092/351] [NOD-1570] Fix the way UTXO iterators work (#1153) * [NOD-1570] Implement utxo.IteratorWithDiff * [NOD-1570] Utilize utxo.ITeratorWithDiff in RestorePastUTXOSetIterator and VirtualUTXOSetIterator * [NOD-1570] Fix comment --- .../consensusstatestore/utxo.go | 10 ++- .../calculate_past_utxo.go | 69 ++++--------------- .../populate_tx_with_utxo_entries.go | 2 +- .../resolve_block_status.go | 2 +- .../consensusstatemanager/update_virtual.go | 2 +- domain/consensus/utils/utxo/utxo_iterator.go | 40 +++++++++++ .../utils/utxo/utxo_iterator_with_diff.go | 56 +++++++++++++++ .../utxo}/utxoalgebra/collection_helpers.go | 4 +- .../utxo}/utxoalgebra/diff_algebra.go | 18 ++--- .../utxo}/utxoalgebra/diff_algebra_test.go | 0 .../utxo}/utxoalgebra/diff_helpers.go | 4 +- 11 files changed, 135 insertions(+), 72 deletions(-) create mode 100644 domain/consensus/utils/utxo/utxo_iterator.go create mode 100644 domain/consensus/utils/utxo/utxo_iterator_with_diff.go rename domain/consensus/{processes/consensusstatemanager => utils/utxo}/utxoalgebra/collection_helpers.go (92%) rename domain/consensus/{processes/consensusstatemanager => utils/utxo}/utxoalgebra/diff_algebra.go (95%) rename domain/consensus/{processes/consensusstatemanager => utils/utxo}/utxoalgebra/diff_algebra_test.go (100%) rename domain/consensus/{processes/consensusstatemanager => utils/utxo}/utxoalgebra/diff_helpers.go (94%) diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index fe510a714..42ad6e029 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/pkg/errors" ) @@ -172,14 +173,19 @@ func (css *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) return nil, err } - return newUTXOSetIterator(cursor), nil + mainIterator := newCursorUTXOSetIterator(cursor) + if css.virtualUTXODiffStaging != nil { + return utxo.IteratorWithDiff(mainIterator, css.virtualUTXODiffStaging) + } + + return mainIterator, nil } type utxoSetIterator struct { cursor model.DBCursor } -func newUTXOSetIterator(cursor model.DBCursor) model.ReadOnlyUTXOSetIterator { +func newCursorUTXOSetIterator(cursor model.DBCursor) model.ReadOnlyUTXOSetIterator { return &utxoSetIterator{cursor: cursor} } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 1b33df786..a988c94e4 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -4,13 +4,14 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" ) func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( @@ -249,14 +250,25 @@ func (csm *consensusStateManager) checkTransactionMass( return true, accumulatedMassAfter } +// RestorePastUTXOSetIterator restores the given block's UTXOSet iterator, and returns it as a model.ReadOnlyUTXOSetIterator func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) ( model.ReadOnlyUTXOSetIterator, error) { + blockStatus, err := csm.resolveBlockStatus(blockHash) + if err != nil { + return nil, err + } + if blockStatus != externalapi.StatusValid { + return nil, errors.Errorf( + "block %s, has status '%s', and therefore can't restore it's UTXO set. Only blocks with status '%s' can be restored.", + blockHash, blockStatus, externalapi.StatusValid) + } + log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash) defer log.Tracef("RestorePastUTXOSetIterator end for block %s", blockHash) log.Tracef("Calculating UTXO diff for block %s", blockHash) - blockDiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) + blockDiff, err := csm.restorePastUTXO(blockHash) if err != nil { return nil, err } @@ -266,56 +278,5 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external return nil, err } - virtualUTXO := model.NewUTXODiff() - for virtualUTXOSetIterator.Next() { - outpoint, utxoEntry, err := virtualUTXOSetIterator.Get() - if err != nil { - return nil, err - } - virtualUTXO.ToAdd[*outpoint] = utxoEntry - } - - blockUTXO, err := utxoalgebra.WithDiff(virtualUTXO, blockDiff) - if err != nil { - return nil, err - } - - if len(blockUTXO.ToRemove) > 0 { - return nil, errors.New("blockUTXO.ToRemove is expected to be empty") - } - - return newUTXOSetIterator(blockUTXO.ToAdd), nil -} - -type utxoOutpointEntryPair struct { - outpoint externalapi.DomainOutpoint - entry *externalapi.UTXOEntry -} - -type utxoSetIterator struct { - index int - pairs []utxoOutpointEntryPair -} - -func newUTXOSetIterator(collection model.UTXOCollection) *utxoSetIterator { - pairs := make([]utxoOutpointEntryPair, len(collection)) - i := 0 - for outpoint, entry := range collection { - pairs[i] = utxoOutpointEntryPair{ - outpoint: outpoint, - entry: entry, - } - i++ - } - return &utxoSetIterator{index: -1, pairs: pairs} -} - -func (u *utxoSetIterator) Next() bool { - u.index++ - return u.index < len(u.pairs) -} - -func (u *utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { - pair := u.pairs[u.index] - return &pair.outpoint, pair.entry, nil + return utxo.IteratorWithDiff(virtualUTXOSetIterator, blockDiff) } diff --git a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go index 08147f004..9e9f4a00c 100644 --- a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go +++ b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go @@ -3,9 +3,9 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" ) // PopulateTransactionWithUTXOEntries populates the transaction UTXO entries with data from the virtual's UTXO set. diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index eb6998f22..bd54054c0 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -3,8 +3,8 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" "github.com/pkg/errors" ) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 001b675c8..f93bbe102 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -3,7 +3,7 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error { diff --git a/domain/consensus/utils/utxo/utxo_iterator.go b/domain/consensus/utils/utxo/utxo_iterator.go new file mode 100644 index 000000000..d75b33c5d --- /dev/null +++ b/domain/consensus/utils/utxo/utxo_iterator.go @@ -0,0 +1,40 @@ +package utxo + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +type utxoOutpointEntryPair struct { + outpoint externalapi.DomainOutpoint + entry *externalapi.UTXOEntry +} + +type utxoCollectionIterator struct { + index int + pairs []utxoOutpointEntryPair +} + +// CollectionIterator creates a utxo iterator from give UTXO collection +func CollectionIterator(collection model.UTXOCollection) model.ReadOnlyUTXOSetIterator { + pairs := make([]utxoOutpointEntryPair, len(collection)) + i := 0 + for outpoint, entry := range collection { + pairs[i] = utxoOutpointEntryPair{ + outpoint: outpoint, + entry: entry, + } + i++ + } + return &utxoCollectionIterator{index: -1, pairs: pairs} +} + +func (u *utxoCollectionIterator) Next() bool { + u.index++ + return u.index < len(u.pairs) +} + +func (u *utxoCollectionIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { + pair := u.pairs[u.index] + return &pair.outpoint, pair.entry, nil +} diff --git a/domain/consensus/utils/utxo/utxo_iterator_with_diff.go b/domain/consensus/utils/utxo/utxo_iterator_with_diff.go new file mode 100644 index 000000000..f8b0da037 --- /dev/null +++ b/domain/consensus/utils/utxo/utxo_iterator_with_diff.go @@ -0,0 +1,56 @@ +package utxo + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" +) + +type readOnlyUTXOIteratorWithDiff struct { + baseIterator model.ReadOnlyUTXOSetIterator + diff *model.UTXODiff + + currentOutpoint *externalapi.DomainOutpoint + currentUTXOEntry *externalapi.UTXOEntry + currentErr error + + toAddIterator model.ReadOnlyUTXOSetIterator +} + +// IteratorWithDiff applies a UTXODiff to given utxo iterator +func IteratorWithDiff(iterator model.ReadOnlyUTXOSetIterator, diff *model.UTXODiff) (model.ReadOnlyUTXOSetIterator, error) { + if iteratorWithDiff, ok := iterator.(*readOnlyUTXOIteratorWithDiff); ok { + combinedDiff, err := utxoalgebra.WithDiff(iteratorWithDiff.diff, diff) + if err != nil { + return nil, err + } + + return IteratorWithDiff(iteratorWithDiff.baseIterator, combinedDiff) + } + + return &readOnlyUTXOIteratorWithDiff{ + baseIterator: iterator, + diff: diff, + toAddIterator: CollectionIterator(diff.ToAdd), + }, nil +} + +func (r *readOnlyUTXOIteratorWithDiff) Next() bool { + for r.baseIterator.Next() { // keep looping until we reach an outpoint/entry pair that is not in r.diff.ToRemove + r.currentOutpoint, r.currentUTXOEntry, r.currentErr = r.baseIterator.Get() + if !utxoalgebra.CollectionContainsWithBlueScore(r.diff.ToRemove, r.currentOutpoint, r.currentUTXOEntry.BlockBlueScore) { + return true + } + } + + if r.toAddIterator.Next() { + r.currentOutpoint, r.currentUTXOEntry, r.currentErr = r.toAddIterator.Get() + return true + } + + return false +} + +func (r *readOnlyUTXOIteratorWithDiff) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { + return r.currentOutpoint, r.currentUTXOEntry, r.currentErr +} diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go b/domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go similarity index 92% rename from domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go rename to domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go index 148ea9269..f0e969cf0 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/collection_helpers.go +++ b/domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go @@ -42,9 +42,9 @@ func CollectionContains(collection model.UTXOCollection, outpoint *externalapi.D return ok } -// containsWithBlueScore returns a boolean value indicating whether a model.UTXOEntry +// CollectionContainsWithBlueScore returns a boolean value indicating whether a model.UTXOEntry // is in the set and its blue score is equal to the given blue score. -func collectionContainsWithBlueScore(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint, blueScore uint64) bool { +func CollectionContainsWithBlueScore(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint, blueScore uint64) bool { entry, ok := CollectionGet(collection, outpoint) return ok && entry.BlockBlueScore == blueScore } diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go b/domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go similarity index 95% rename from domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go rename to domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go index 9bcaf3f01..ad186c74c 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra.go +++ b/domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go @@ -56,7 +56,7 @@ func intersectionWithRemainderHavingBlueScore(collection1, collection2 model.UTX // having same blue score, puts it into result and into remainder from collection1 func intersectionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder model.UTXOCollection) { for outpoint, utxoEntry := range collection1 { - if collectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { + if CollectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { collectionAdd(result, &outpoint, utxoEntry) } else { collectionAdd(remainder, &outpoint, utxoEntry) @@ -77,7 +77,7 @@ func subtractionHavingBlueScore(collection1, collection2 model.UTXOCollection) ( // having same blue score, puts it into result func subtractionHavingBlueScoreInPlace(collection1, collection2, result model.UTXOCollection) { for outpoint, utxoEntry := range collection1 { - if !collectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { + if !CollectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { collectionAdd(result, &outpoint, utxoEntry) } } @@ -97,7 +97,7 @@ func subtractionWithRemainderHavingBlueScore(collection1, collection2 model.UTXO // having same blue score, puts it into result and into remainder from collection1 func subtractionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder model.UTXOCollection) { for outpoint, utxoEntry := range collection1 { - if !collectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { + if !CollectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { collectionAdd(result, &outpoint, utxoEntry) } else { collectionAdd(remainder, &outpoint, utxoEntry) @@ -142,8 +142,8 @@ func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { // check that NOT (entries with unequal blue scores AND utxoEntry is in this.ToAdd and/or other.ToRemove) -> Error isNotAddedOutputRemovedWithBlueScore := func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry *externalapi.UTXOEntry) bool { return !(diffEntry.BlockBlueScore != utxoEntry.BlockBlueScore && - (collectionContainsWithBlueScore(this.ToAdd, outpoint, diffEntry.BlockBlueScore) || - collectionContainsWithBlueScore(other.ToRemove, outpoint, utxoEntry.BlockBlueScore))) + (CollectionContainsWithBlueScore(this.ToAdd, outpoint, diffEntry.BlockBlueScore) || + CollectionContainsWithBlueScore(other.ToRemove, outpoint, utxoEntry.BlockBlueScore))) } if offendingOutpoint, ok := @@ -156,8 +156,8 @@ func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry *externalapi.UTXOEntry) bool { return !(diffEntry.BlockBlueScore != utxoEntry.BlockBlueScore && - (collectionContainsWithBlueScore(this.ToRemove, outpoint, diffEntry.BlockBlueScore) || - collectionContainsWithBlueScore(other.ToAdd, outpoint, utxoEntry.BlockBlueScore))) + (CollectionContainsWithBlueScore(this.ToRemove, outpoint, diffEntry.BlockBlueScore) || + CollectionContainsWithBlueScore(other.ToAdd, outpoint, utxoEntry.BlockBlueScore))) } if offendingOutpoint, ok := @@ -210,7 +210,7 @@ func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { func WithDiffInPlace(this *model.UTXODiff, diff *model.UTXODiff) error { if offendingOutpoint, ok := checkIntersectionWithRule(diff.ToRemove, this.ToRemove, func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry *externalapi.UTXOEntry) bool { - return !collectionContainsWithBlueScore(this.ToAdd, outpoint, entryToAdd.BlockBlueScore) + return !CollectionContainsWithBlueScore(this.ToAdd, outpoint, entryToAdd.BlockBlueScore) }); ok { return errors.Errorf( "withDiffInPlace: outpoint %s both in this.ToRemove and in diff.ToRemove", offendingOutpoint) @@ -218,7 +218,7 @@ func WithDiffInPlace(this *model.UTXODiff, diff *model.UTXODiff) error { if offendingOutpoint, ok := checkIntersectionWithRule(diff.ToAdd, this.ToAdd, func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry *externalapi.UTXOEntry) bool { - return !collectionContainsWithBlueScore(diff.ToRemove, outpoint, existingEntry.BlockBlueScore) + return !CollectionContainsWithBlueScore(diff.ToRemove, outpoint, existingEntry.BlockBlueScore) }); ok { return errors.Errorf( "withDiffInPlace: outpoint %s both in this.ToAdd and in diff.ToAdd", offendingOutpoint) diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go b/domain/consensus/utils/utxo/utxoalgebra/diff_algebra_test.go similarity index 100% rename from domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_algebra_test.go rename to domain/consensus/utils/utxo/utxoalgebra/diff_algebra_test.go diff --git a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go b/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go similarity index 94% rename from domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go rename to domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go index 2eb45829d..98545f791 100644 --- a/domain/consensus/processes/consensusstatemanager/utxoalgebra/diff_helpers.go +++ b/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go @@ -45,7 +45,7 @@ func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.Domai } func diffAddEntry(diff *model.UTXODiff, outpoint *externalapi.DomainOutpoint, entry *externalapi.UTXOEntry) error { - if collectionContainsWithBlueScore(diff.ToRemove, outpoint, entry.BlockBlueScore) { + if CollectionContainsWithBlueScore(diff.ToRemove, outpoint, entry.BlockBlueScore) { collectionRemove(diff.ToRemove, outpoint) } else if _, exists := diff.ToAdd[*outpoint]; exists { return errors.Errorf("AddEntry: Cannot add outpoint %s twice", outpoint) @@ -56,7 +56,7 @@ func diffAddEntry(diff *model.UTXODiff, outpoint *externalapi.DomainOutpoint, en } func diffRemoveEntry(diff *model.UTXODiff, outpoint *externalapi.DomainOutpoint, entry *externalapi.UTXOEntry) error { - if collectionContainsWithBlueScore(diff.ToAdd, outpoint, entry.BlockBlueScore) { + if CollectionContainsWithBlueScore(diff.ToAdd, outpoint, entry.BlockBlueScore) { collectionRemove(diff.ToAdd, outpoint) } else if _, exists := diff.ToRemove[*outpoint]; exists { return errors.Errorf("removeEntry: Cannot remove outpoint %s twice", outpoint) From f7fa823f17c4c539c04be169978a9658c78e9777 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 26 Nov 2020 12:12:01 +0200 Subject: [PATCH 093/351] [NOD-1551] Requirements for performance tests (#1154) * [NOD-1551] Add NewTestConsensusWithDataDir to factory * [NOD-1551] Cache transaction ID * [NOD-1551] Should return err if err != nil * [NOD-1551] BuildBlockWithParents returns the blocks pastUTXOData * [NOD-1551] Set BlockCoinbaseMaturity to 0 in TestDoubleSpends * [NOD-1551] Fix comments * --amend Co-authored-by: Ori Newman --- domain/consensus/consensus_test.go | 5 ++-- domain/consensus/factory.go | 15 ++++++++-- domain/consensus/finality_test.go | 6 ++-- .../model/externalapi/transaction.go | 4 +++ .../model/interface_processes_blockbuilder.go | 5 +++- .../consensus/model/testapi/test_consensus.go | 3 +- .../blockbuilder/test_block_builder.go | 29 ++++++++++--------- .../block_header_in_context_test.go | 5 ++-- .../resolve_block_status_test.go | 2 ++ .../pastmediantimemanager_test.go | 5 ++-- .../transaction_in_context.go | 8 ++--- domain/consensus/test_consensus.go | 5 ++-- .../consensusserialization/transaction.go | 10 ++++++- 13 files changed, 65 insertions(+), 37 deletions(-) diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index af64f73e9..63c1d1527 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -1,13 +1,14 @@ package consensus import ( + "testing" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" - "testing" ) func TestConsensus_GetBlockInfo(t *testing.T) { @@ -20,7 +21,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) { } defer teardown() - invalidBlock, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + invalidBlock, _, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) if err != nil { t.Fatal(err) } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 5d68536de..9f7015617 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -48,6 +48,8 @@ import ( 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) + NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) ( + tc testapi.TestConsensus, teardown func(), err error) } type factory struct{} @@ -312,11 +314,18 @@ 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) { - testDatabaseDir, err := ioutil.TempDir("", testName) + dataDir, err := ioutil.TempDir("", testName) if err != nil { return nil, nil, err } - db, err := ldb.NewLevelDB(testDatabaseDir) + + return f.NewTestConsensusWithDataDir(dagParams, dataDir) +} + +func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) ( + tc testapi.TestConsensus, teardown func(), err error) { + + db, err := ldb.NewLevelDB(dataDir) if err != nil { return nil, nil, err } @@ -338,7 +347,7 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus) teardown = func() { db.Close() - os.RemoveAll(testDatabaseDir) + os.RemoveAll(dataDir) } return tstConsensus, teardown, nil diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 5cf6532e6..f5ba1a48e 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -27,7 +27,7 @@ func TestFinality(t *testing.T) { defer teardown() buildAndInsertBlock := func(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) { - block, err := consensus.BuildBlockWithParents(parentHashes, nil, nil) + block, _, err := consensus.BuildBlockWithParents(parentHashes, nil, nil) if err != nil { return nil, err } @@ -184,7 +184,7 @@ func TestBoundedMergeDepth(t *testing.T) { } checkViolatingMergeDepth := func(consensus testapi.TestConsensus, parents []*externalapi.DomainHash) (*externalapi.DomainBlock, bool) { - block, err := consensus.BuildBlockWithParents(parents, nil, nil) + block, _, err := consensus.BuildBlockWithParents(parents, nil, nil) if err != nil { t.Fatalf("TestBoundedMergeDepth: BuildBlockWithParents failed: %v", err) return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns @@ -210,7 +210,7 @@ func TestBoundedMergeDepth(t *testing.T) { } buildAndInsertBlock := func(consensus testapi.TestConsensus, parentHashes []*externalapi.DomainHash) *externalapi.DomainBlock { - block, err := consensus.BuildBlockWithParents(parentHashes, nil, nil) + block, _, err := consensus.BuildBlockWithParents(parentHashes, nil, nil) if err != nil { t.Fatalf("TestBoundedMergeDepth: Failed building block: %v", err) } diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 32959ec6d..9928ad732 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -17,6 +17,10 @@ type DomainTransaction struct { Fee uint64 Mass uint64 + + // ID is a field that is used to cache the transaction ID. + // Always use consensusserialization.TransactionID instead of accessing this field directly + ID *DomainTransactionID } // Clone returns a clone of DomainTransaction diff --git a/domain/consensus/model/interface_processes_blockbuilder.go b/domain/consensus/model/interface_processes_blockbuilder.go index 469c176ae..59c7bf60a 100644 --- a/domain/consensus/model/interface_processes_blockbuilder.go +++ b/domain/consensus/model/interface_processes_blockbuilder.go @@ -10,6 +10,9 @@ type BlockBuilder interface { // TestBlockBuilder adds to the main BlockBuilder methods required by tests type TestBlockBuilder interface { BlockBuilder + + // BuildBlockWithParents builds a block with provided parents, coinbaseData and transactions, + // and returns the block together with its past UTXO-diff from the virtual. BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *UTXODiff, error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index e898e6e62..f87cb9f37 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -11,8 +11,7 @@ type TestConsensus interface { DatabaseContext() model.DBReader - BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) + BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) // AddBlock builds a block with given information, solves it, and adds to the DAG. // Returns the hash of the added block diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 667dd23e9..08943658c 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -27,8 +27,11 @@ func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus test } } -func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { +// BuildBlockWithParents builds a block with provided parents, coinbaseData and transactions, +// and returns the block together with its past UTXO-diff from the virtual. +func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, + coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) ( + *externalapi.DomainBlock, *model.UTXODiff, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockWithParents") defer onEnd() @@ -69,9 +72,7 @@ func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.D }, nil } -func (bb *testBlockBuilder) buildBlockWithParents( - parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { +func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) { defer bb.testConsensus.DiscardAllStores() @@ -87,43 +88,43 @@ func (bb *testBlockBuilder) buildBlockWithParents( err := bb.ghostdagManager.GHOSTDAG(tempBlockHash) if err != nil { - return nil, err + return nil, nil, err } ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash) if err != nil { - return nil, err + return nil, nil, err } selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) if err != nil { - return nil, err + return nil, nil, err } if selectedParentStatus == externalapi.StatusDisqualifiedFromChain { - return nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain", + return nil, nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain", ghostdagData.SelectedParent) } - _, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) + pastUTXO, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) if err != nil { - return nil, err + return nil, nil, err } bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData) coinbase, err := bb.coinbaseManager.ExpectedCoinbaseTransaction(tempBlockHash, coinbaseData) if err != nil { - return nil, err + return nil, nil, err } transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...) header, err := bb.buildHeaderWithParents(parentHashes, transactionsWithCoinbase, acceptanceData, multiset) if err != nil { - return nil, err + return nil, nil, err } return &externalapi.DomainBlock{ Header: header, Transactions: transactionsWithCoinbase, - }, nil + }, pastUTXO, nil } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index fab862ba2..4f46a8c4f 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -2,6 +2,8 @@ package blockvalidator_test import ( "errors" + "testing" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -9,7 +11,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" - "testing" ) func TestValidateMedianTime(t *testing.T) { @@ -22,7 +23,7 @@ func TestValidateMedianTime(t *testing.T) { defer teardown() addBlock := func(blockTime int64, parents []*externalapi.DomainHash, expectedErr error) (*externalapi.DomainBlock, *externalapi.DomainHash) { - block, err := tc.BuildBlockWithParents(parents, nil, nil) + block, _, err := tc.BuildBlockWithParents(parents, nil, nil) if err != nil { t.Fatalf("BuildBlockWithParents: %+v", err) } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 4bcd70d20..3dae149b0 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -17,6 +17,8 @@ import ( func TestDoubleSpends(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.BlockCoinbaseMaturity = 0 + factory := consensus.NewFactory() consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index aa0184ab0..5cce8cca9 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -1,12 +1,13 @@ package pastmediantimemanager_test import ( + "testing" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" - "testing" ) func TestPastMedianTime(t *testing.T) { @@ -24,7 +25,7 @@ func TestPastMedianTime(t *testing.T) { blockTime := params.GenesisBlock.Header.TimeInMilliseconds for i := uint32(1); i < numBlocks; i++ { blockTime += 1000 - block, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{blockHashes[i-1]}, nil, nil) + block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{blockHashes[i-1]}, nil, nil) if err != nil { t.Fatalf("BuildBlockWithParents: %s", err) } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index 3f7f9a5bb..edf886921 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -18,24 +18,24 @@ func (v *transactionValidator) ValidateTransactionInContextAndPopulateMassAndFee err := v.checkTransactionCoinbaseMaturity(povBlockHash, tx) if err != nil { - return nil + return err } totalSompiIn, err := v.checkTransactionInputAmounts(tx) if err != nil { - return nil + return err } totalSompiOut, err := v.checkTransactionOutputAmounts(tx, totalSompiIn) if err != nil { - return nil + return err } tx.Fee = totalSompiIn - totalSompiOut err = v.checkTransactionSequenceLock(povBlockHash, tx, selectedParentMedianTime) if err != nil { - return nil + return err } err = v.validateTransactionScripts(tx) diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index b01dc58fb..d845b4e6f 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -14,8 +14,7 @@ type testConsensus struct { testConsensusStateManager model.TestConsensusStateManager } -func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { +func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) { // Require write lock because BuildBlockWithParents stages temporary data tc.lock.Lock() @@ -31,7 +30,7 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba tc.lock.Lock() defer tc.lock.Unlock() - block, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) + block, _, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) if err != nil { return nil, err } diff --git a/domain/consensus/utils/consensusserialization/transaction.go b/domain/consensus/utils/consensusserialization/transaction.go index 4a99ce12b..fbb6f0e25 100644 --- a/domain/consensus/utils/consensusserialization/transaction.go +++ b/domain/consensus/utils/consensusserialization/transaction.go @@ -65,6 +65,12 @@ func TransactionHash(tx *externalapi.DomainTransaction) *externalapi.DomainHash // TransactionID generates the Hash for the transaction without the signature script and payload field. func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransactionID { + + // If transaction ID is already cached, return it + if tx.ID != nil { + return tx.ID + } + // Encode the transaction, replace signature script with zeroes, cut off // payload and calculate double sha256 on the result. var encodingFlags txEncoding @@ -80,7 +86,9 @@ func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransac } transactionID := externalapi.DomainTransactionID(*writer.Finalize()) - return &transactionID + tx.ID = &transactionID + + return tx.ID } func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodingFlags txEncoding) error { From 0e91b44fc65f333131b11495644d90f4c09c2179 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 26 Nov 2020 07:11:49 -0800 Subject: [PATCH 094/351] [NOD-1577] Change cache size to 200 (#1156) --- domain/consensus/factory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 9f7015617..17907cac9 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -64,7 +64,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager := consensusdatabase.New(db) // Data Structures - storeCacheSize := int(dagParams.FinalityDepth()) + storeCacheSize := 200 acceptanceDataStore := acceptancedatastore.New(storeCacheSize) blockStore, err := blockstore.New(dbManager, storeCacheSize) if err != nil { From f6dfce81804d172a8624efabdc7597f72859497c Mon Sep 17 00:00:00 2001 From: alexandratran <12214231+alexandratran@users.noreply.github.com> Date: Thu, 26 Nov 2020 21:46:57 -0800 Subject: [PATCH 095/351] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dbd6e811..7b504fce0 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ is used for this project. ## Documentation -The documentation is a work-in-progress. It is located in the [docs](https://github.com/kaspanet/kaspad/tree/master/docs) folder. +The documentation is a work-in-progress. ## License From baa4311a34317f1289ab1310578d36dda66534df Mon Sep 17 00:00:00 2001 From: oudeis Date: Sun, 29 Nov 2020 05:12:30 +0000 Subject: [PATCH 096/351] Update to version 0.8.2 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 612ccc8b3..1424c3221 100644 --- a/version/version.go +++ b/version/version.go @@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 appMinor uint = 8 - appPatch uint = 0 + appPatch uint = 2 ) // appBuild is defined as a variable so it can be overridden during the build From 048caebda37987862204c026856fc26a71fefab5 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 29 Nov 2020 10:18:00 +0200 Subject: [PATCH 097/351] [NOD-1551] Add SigCache to TransactionValidator + Option to manipulate it in TestConsensus (#1159) * [NOD-1551] Add SigCache * [NOD-1551] Add option to edit SigCache in TestConsensus * [NOD-1551] Fix comments and make SetSigCache pointer-receiver --- domain/consensus/factory.go | 3 +++ .../interface_processes_blockvalidator.go | 4 +++- ...nterface_processes_transactionvalidator.go | 14 +++++++++-- .../consensus/model/testapi/test_consensus.go | 2 +- .../test_transaction_validator.go | 23 +++++++++++++++++++ .../transaction_in_context.go | 2 +- .../transactionvalidator.go | 5 ++++ domain/consensus/test_consensus.go | 5 +++- domain/consensus/test_consensus_getters.go | 4 ++-- domain/consensus/utils/txscript/opcode.go | 1 - 10 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 domain/consensus/processes/transactionvalidator/test_transaction_validator.go diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 17907cac9..4e95ca67b 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -338,11 +338,14 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager) + testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator) + tstConsensus := &testConsensus{ consensus: consensusAsImplementation, testConsensusStateManager: testConsensusStateManager, testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation. reachabilityManager), + testTransactionValidator: testTransactionValidator, } tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus) teardown = func() { diff --git a/domain/consensus/model/interface_processes_blockvalidator.go b/domain/consensus/model/interface_processes_blockvalidator.go index 5a89c09c7..0cdc771e7 100644 --- a/domain/consensus/model/interface_processes_blockvalidator.go +++ b/domain/consensus/model/interface_processes_blockvalidator.go @@ -1,6 +1,8 @@ package model -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // BlockValidator exposes a set of validation classes, after which // it's possible to determine whether a block is valid diff --git a/domain/consensus/model/interface_processes_transactionvalidator.go b/domain/consensus/model/interface_processes_transactionvalidator.go index 2d8b09a89..ccf5de817 100644 --- a/domain/consensus/model/interface_processes_transactionvalidator.go +++ b/domain/consensus/model/interface_processes_transactionvalidator.go @@ -1,11 +1,21 @@ package model -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" +) // TransactionValidator exposes a set of validation classes, after which // it's possible to determine whether a transaction is valid type TransactionValidator interface { ValidateTransactionInIsolation(transaction *externalapi.DomainTransaction) error ValidateTransactionInContextAndPopulateMassAndFee(tx *externalapi.DomainTransaction, - povBlockHash *externalapi.DomainHash, selectedParentMedianTime int64) error + povTransactionHash *externalapi.DomainHash, selectedParentMedianTime int64) error +} + +// TestTransactionValidator adds to the main TransactionValidator methods required by tests +type TestTransactionValidator interface { + TransactionValidator + SigCache() *txscript.SigCache + SetSigCache(sigCache *txscript.SigCache) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index f87cb9f37..d1cdc657f 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -48,5 +48,5 @@ type TestConsensus interface { PruningManager() model.PruningManager ReachabilityManager() model.TestReachabilityManager SyncManager() model.SyncManager - TransactionValidator() model.TransactionValidator + TransactionValidator() model.TestTransactionValidator } diff --git a/domain/consensus/processes/transactionvalidator/test_transaction_validator.go b/domain/consensus/processes/transactionvalidator/test_transaction_validator.go new file mode 100644 index 000000000..342b682e2 --- /dev/null +++ b/domain/consensus/processes/transactionvalidator/test_transaction_validator.go @@ -0,0 +1,23 @@ +package transactionvalidator + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" +) + +type testTransactionValidator struct { + *transactionValidator +} + +// NewTestTransactionValidator creates an instance of a TestTransactionValidator +func NewTestTransactionValidator(baseTransactionValidator model.TransactionValidator) model.TestTransactionValidator { + return &testTransactionValidator{transactionValidator: baseTransactionValidator.(*transactionValidator)} +} + +func (tbv *testTransactionValidator) SigCache() *txscript.SigCache { + return tbv.sigCache +} + +func (tbv *testTransactionValidator) SetSigCache(sigCache *txscript.SigCache) { + tbv.sigCache = sigCache +} diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index edf886921..bc8dd7af4 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -189,7 +189,7 @@ func (v *transactionValidator) validateTransactionScripts(tx *externalapi.Domain scriptPubKey := utxoEntry.ScriptPublicKey vm, err := txscript.NewEngine(scriptPubKey, tx, - i, txscript.ScriptNoFlags, nil) + i, txscript.ScriptNoFlags, v.sigCache) if err != nil { return errors.Wrapf(ruleerrors.ErrScriptMalformed, "failed to parse input "+ "%d which references output %s - "+ diff --git a/domain/consensus/processes/transactionvalidator/transactionvalidator.go b/domain/consensus/processes/transactionvalidator/transactionvalidator.go index 41c338b97..9500bb556 100644 --- a/domain/consensus/processes/transactionvalidator/transactionvalidator.go +++ b/domain/consensus/processes/transactionvalidator/transactionvalidator.go @@ -2,8 +2,11 @@ package transactionvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" ) +const sigCacheSize = 10_000 + // transactionValidator exposes a set of validation classes, after which // it's possible to determine whether either a transaction is valid type transactionValidator struct { @@ -12,6 +15,7 @@ type transactionValidator struct { pastMedianTimeManager model.PastMedianTimeManager ghostdagDataStore model.GHOSTDAGDataStore enableNonNativeSubnetworks bool + sigCache *txscript.SigCache } // New instantiates a new TransactionValidator @@ -26,5 +30,6 @@ func New(blockCoinbaseMaturity uint64, databaseContext: databaseContext, pastMedianTimeManager: pastMedianTimeManager, ghostdagDataStore: ghostdagDataStore, + sigCache: txscript.NewSigCache(sigCacheSize), } } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index d845b4e6f..a0dc83936 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -12,9 +12,12 @@ type testConsensus struct { testBlockBuilder model.TestBlockBuilder testReachabilityManager model.TestReachabilityManager testConsensusStateManager model.TestConsensusStateManager + testTransactionValidator model.TestTransactionValidator } -func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) { +func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, + coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) ( + *externalapi.DomainBlock, *model.UTXODiff, error) { // Require write lock because BuildBlockWithParents stages temporary data tc.lock.Lock() diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 0ab7f6ccd..9d9061f3d 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -116,6 +116,6 @@ func (tc *testConsensus) SyncManager() model.SyncManager { return tc.syncManager } -func (tc *testConsensus) TransactionValidator() model.TransactionValidator { - return tc.transactionValidator +func (tc *testConsensus) TransactionValidator() model.TestTransactionValidator { + return tc.testTransactionValidator } diff --git a/domain/consensus/utils/txscript/opcode.go b/domain/consensus/utils/txscript/opcode.go index f87bb87b0..6c83230f7 100644 --- a/domain/consensus/utils/txscript/opcode.go +++ b/domain/consensus/utils/txscript/opcode.go @@ -2249,7 +2249,6 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { secpHash := secp256k1.Hash(*sigHash) var valid bool if vm.sigCache != nil { - valid = vm.sigCache.Exists(secpHash, parsedSig, parsedPubKey) if !valid && parsedPubKey.SchnorrVerify(&secpHash, parsedSig) { vm.sigCache.Add(secpHash, parsedSig, parsedPubKey) From a1af992d1542901e9bbaff03ece3efb25df281ea Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 29 Nov 2020 10:44:50 +0200 Subject: [PATCH 098/351] [NOD-1578] Fix areHeaderTipsSyncedMaxTimeDifference (#1157) * [NOD-1578] Fix areHeaderTipsSyncedMaxTimeDifference. * [NOD-1578] Return errors that occur in the new logClosure. --- .../blockprocessor/validateandinsertblock.go | 24 +++++++++++++++---- .../processes/syncmanager/syncinfo.go | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 911a06e01..5c18947f0 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -1,10 +1,12 @@ package blockprocessor import ( + "fmt" "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/consensusserialization" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" ) @@ -153,11 +155,25 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } log.Debugf("Block %s validated and inserted", hash) - virtualGhostDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash) - if err != nil { - return err + + var logClosureErr error + log.Debugf("%s", logger.NewLogClosure(func() string { + virtualGhostDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash) + if err != nil { + 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) + })) + if logClosureErr != nil { + return logClosureErr } - log.Debugf("New virtual's blue score: %d", virtualGhostDAGData.BlueScore) return nil } diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index ce24f3097..5d502b114 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -9,7 +9,7 @@ import ( // 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_000 // 5 minutes +const areHeaderTipsSyncedMaxTimeDifference = 300 // 5 minutes func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { syncState, err := sm.resolveSyncState() From f407c44a8d8f55b0114cd6f8e2ea9211758c8dcd Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Mon, 30 Nov 2020 09:57:15 +0200 Subject: [PATCH 099/351] [Issue - #1126] - Checking pruning point violation - pruning point in the past. (#1160) * [NOD-1126] 1. Change function name in BlockValidator interface from: "ValidateProofOfWorkAndDifficulty" to "ValidatePruningPointViolationAndProofOfWorkAndDifficulty". 2. Add to the blockValidator struct the pruningManager (also added to the function "New" Respectively). 3. Added new function "checkPruningPointViolation" of blockValidator type. 4. Add new internal check - "checkPruningPointViolation", on the function "ValidateProofOfWorkAndDifficulty".(The third check). 5. Add new error rule - "ErrPruningPointViolation". * [Issue-1126] 1. Remove the function "PruningPoint" from PruningManager interface. 2. Changes in blockValidator struct - remove pruningManager, and adding pruningStore. 3. Reads for "pruningPoint" function from pruningStore instead of pruningManager (because of note 1 above) in the functions: * "checkPruningPointViolation" of type blockValidator. * "FindNextPruningPoint" of type pruningManager. * [Issue-1126] 1. Add missing error handling. * [Issue-1126] Changes in function "checkPruningPointViolation": If header = genesis, stop checking and return nil. * [Issue-1126] In function "checkPruningPointViolation" - change from a for loop to the "IsAncestorOfAny" function. * [#1126] "FindNextPruningPoint" - save the pruning point in case the point is the genesis and change code internal order. * [#1126] "FindNextPruningPoint" - cosmetics change. * [#1126] "FindNextPruningPoint" - remove "return nil" when there is no pruning point on the if expression. Co-authored-by: tal --- domain/consensus/factory.go | 1 + .../interface_processes_blockvalidator.go | 2 +- .../interface_processes_pruningmanager.go | 3 -- .../blockprocessor/validateandinsertblock.go | 2 +- .../blockvalidator/blockvalidator.go | 3 ++ .../processes/blockvalidator/proof_of_work.go | 35 +++++++++++++++- .../pruningmanager/pruningmanager.go | 41 ++++++++----------- domain/consensus/ruleerrors/rule_error.go | 3 ++ 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 4e95ca67b..222fe0016 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -153,6 +153,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTraversalManager, coinbaseManager, mergeDepthManager, + pruningStore, blockStore, ghostdagDataStore, diff --git a/domain/consensus/model/interface_processes_blockvalidator.go b/domain/consensus/model/interface_processes_blockvalidator.go index 0cdc771e7..12dde50d0 100644 --- a/domain/consensus/model/interface_processes_blockvalidator.go +++ b/domain/consensus/model/interface_processes_blockvalidator.go @@ -11,5 +11,5 @@ type BlockValidator interface { ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error ValidateHeaderInContext(blockHash *externalapi.DomainHash) error ValidateBodyInContext(blockHash *externalapi.DomainHash) error - ValidateProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error + ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error } diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index b6e0ea85f..09322ebad 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -1,9 +1,6 @@ package model -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - // PruningManager resolves and manages the current pruning point type PruningManager interface { FindNextPruningPoint() error - PruningPoint() (*externalapi.DomainHash, error) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 5c18947f0..f521c9b52 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -240,7 +240,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex return err } - err = bp.blockValidator.ValidateProofOfWorkAndDifficulty(blockHash) + err = bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 91bdf2bd8..7c3fa4e10 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -28,6 +28,7 @@ type blockValidator struct { dagTraversalManager model.DAGTraversalManager coinbaseManager model.CoinbaseManager mergeDepthManager model.MergeDepthManager + pruningStore model.PruningStore blockStore model.BlockStore ghostdagDataStore model.GHOSTDAGDataStore @@ -52,6 +53,7 @@ func New(powMax *big.Int, dagTraversalManager model.DAGTraversalManager, coinbaseManager model.CoinbaseManager, mergeDepthManager model.MergeDepthManager, + pruningStore model.PruningStore, blockStore model.BlockStore, ghostdagDataStore model.GHOSTDAGDataStore, @@ -75,6 +77,7 @@ func New(powMax *big.Int, dagTraversalManager: dagTraversalManager, coinbaseManager: coinbaseManager, mergeDepthManager: mergeDepthManager, + pruningStore: pruningStore, blockStore: blockStore, ghostdagDataStore: ghostdagDataStore, diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index 6014a0282..e6de47b69 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" ) -func (v *blockValidator) ValidateProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error { +func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error { header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash) if err != nil { return err @@ -25,6 +25,11 @@ func (v *blockValidator) ValidateProofOfWorkAndDifficulty(blockHash *externalapi return err } + err = v.checkPruningPointViolation(header) + if err != nil { + return err + } + err = v.checkProofOfWork(header) if err != nil { return err @@ -119,3 +124,31 @@ func (v *blockValidator) checkParentsExist(header *externalapi.DomainBlockHeader return nil } +func (v *blockValidator) checkPruningPointViolation(header *externalapi.DomainBlockHeader) error { + // check if the pruning point is on past of at least one parent of the header's parents. + + hasPruningPoint, err := v.pruningStore.HasPruningPoint(v.databaseContext) + if err != nil { + return err + } + + //If hasPruningPoint has a false value, it means that it's the genesis - so no violation can exist. + if !hasPruningPoint { + return nil + } + + pruningPoint, err := v.pruningStore.PruningPoint(v.databaseContext) + if err != nil { + return err + } + + isAncestorOfAny, err := v.dagTopologyManager.IsAncestorOfAny(pruningPoint, header.ParentHashes) + if err != nil { + return err + } + if isAncestorOfAny { + return nil + } + return errors.Wrapf(ruleerrors.ErrPruningPointViolation, + "expected pruning point to be in block %d past.", header.Bits) +} diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 36c397dc2..9dda97c9d 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -73,15 +73,28 @@ func New( // FindNextPruningPoint finds the next pruning point from the // given blockHash func (pm *pruningManager) FindNextPruningPoint() error { + hasPruningPoint, err := pm.pruningStore.HasPruningPoint(pm.databaseContext) + if err != nil { + return err + } + + if !hasPruningPoint { + err = pm.savePruningPoint(pm.genesisHash) + if err != nil { + return err + } + } + + currentP, err := pm.pruningStore.PruningPoint(pm.databaseContext) + if err != nil { + return err + } + virtual, err := pm.ghostdagDataStore.Get(pm.databaseContext, model.VirtualBlockHash) if err != nil { return err } - currentP, err := pm.PruningPoint() - if err != nil { - return err - } currentPGhost, err := pm.ghostdagDataStore.Get(pm.databaseContext, currentP) if err != nil { return err @@ -118,26 +131,6 @@ func (pm *pruningManager) FindNextPruningPoint() error { return pm.deletePastBlocks(currentP) } -// PruningPoint returns the hash of the current pruning point -func (pm *pruningManager) PruningPoint() (*externalapi.DomainHash, error) { - hasPruningPoint, err := pm.pruningStore.HasPruningPoint(pm.databaseContext) - if err != nil { - return nil, err - } - if hasPruningPoint { - return pm.pruningStore.PruningPoint(pm.databaseContext) - } - - // If there's no pruning point yet, set genesis as the pruning point. - // This is the genesis because it means `FindNextPruningPoint()` has never been called before, - // if this is part of the first `FindNextPruningPoint()` call, then it might move the pruning point forward. - err = pm.savePruningPoint(pm.genesisHash) - if err != nil { - return nil, err - } - return pm.genesisHash, nil -} - func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) error { // Go over all P.Past and P.AC that's not in V.Past queue := pm.dagTraversalManager.NewDownHeap() diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 8b0367b89..6dab741f2 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -233,6 +233,9 @@ var ( ErrMalformedUTXO = newRuleError("ErrMalformedUTXO") ErrWrongPruningPointHash = newRuleError("ErrWrongPruningPointHash") + + //ErrPruningPointViolation indicates that the pruning point isn't in the block past. + ErrPruningPointViolation = newRuleError("ErrPruningPointViolation") ) // RuleError identifies a rule violation. It is used to indicate that From 3b6eb73e53c93c18cc14e3ed09afba15f2abe4ab Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 30 Nov 2020 11:34:19 +0200 Subject: [PATCH 100/351] [NOD-1551] Remove lock in SigCache (#1161) --- domain/consensus/utils/txscript/sigcache.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/domain/consensus/utils/txscript/sigcache.go b/domain/consensus/utils/txscript/sigcache.go index d64d93167..cb6ef804f 100644 --- a/domain/consensus/utils/txscript/sigcache.go +++ b/domain/consensus/utils/txscript/sigcache.go @@ -6,7 +6,6 @@ package txscript import ( "github.com/kaspanet/go-secp256k1" - "sync" ) // sigCacheEntry represents an entry in the SigCache. Entries within the @@ -31,7 +30,6 @@ type sigCacheEntry struct { // optimization which speeds up the validation of transactions within a block, // if they've already been seen and verified within the mempool. type SigCache struct { - sync.RWMutex validSigs map[secp256k1.Hash]sigCacheEntry maxEntries uint } @@ -54,8 +52,6 @@ func NewSigCache(maxEntries uint) *SigCache { // NOTE: This function is safe for concurrent access. Readers won't be blocked // unless there exists a writer, adding an entry to the SigCache. func (s *SigCache) Exists(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignature, pubKey *secp256k1.SchnorrPublicKey) bool { - s.RLock() - defer s.RUnlock() entry, ok := s.validSigs[sigHash] return ok && entry.pubKey.IsEqual(pubKey) && entry.sig.IsEqual(sig) @@ -69,9 +65,6 @@ func (s *SigCache) Exists(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignatur // NOTE: This function is safe for concurrent access. Writers will block // simultaneous readers until function execution has concluded. func (s *SigCache) Add(sigHash secp256k1.Hash, sig *secp256k1.SchnorrSignature, pubKey *secp256k1.SchnorrPublicKey) { - s.Lock() - defer s.Unlock() - if s.maxEntries == 0 { return } From 80c445c78b46a2734fe656a04cf8ea1725382799 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 30 Nov 2020 13:45:06 +0200 Subject: [PATCH 101/351] [NOD-1551] Optimize binary writes + remove redundant VarInt code (#1163) * [NOD-1551] Optimize binary writes + remove redundant VarInt code * [NOD-1551] Remove varInt tests * [NOD-1551] Fix TestBech32 for Go1.15 --- app/appmessage/common.go | 188 +------ app/appmessage/common_test.go | 462 ------------------ .../utils/consensusserialization/common.go | 23 +- .../consensusserialization/transaction.go | 12 +- .../utils/consensusserialization/utxo_test.go | 37 ++ util/bech32/internal_test.go | 8 +- util/binaryserializer/binaryserializer.go | 37 +- util/coinbasepayload/coinbasepayload.go | 66 --- util/random/random.go | 3 +- 9 files changed, 92 insertions(+), 744 deletions(-) create mode 100644 domain/consensus/utils/consensusserialization/utxo_test.go delete mode 100644 util/coinbasepayload/coinbasepayload.go diff --git a/app/appmessage/common.go b/app/appmessage/common.go index d72ad29f2..66b5ca531 100644 --- a/app/appmessage/common.go +++ b/app/appmessage/common.go @@ -5,10 +5,8 @@ package appmessage import ( - "encoding/binary" "fmt" "io" - "math" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/id" @@ -23,16 +21,6 @@ const MaxVarIntPayload = 9 // MaxInvPerMsg is the maximum number of inventory vectors that can be in any type of kaspa inv message. const MaxInvPerMsg = 1 << 17 -var ( - // littleEndian is a convenience variable since binary.LittleEndian is - // quite long. - littleEndian = binary.LittleEndian - - // bigEndian is a convenience variable since binary.BigEndian is quite - // long. - bigEndian = binary.BigEndian -) - // errNonCanonicalVarInt is the common format string used for non-canonically // encoded variable length integer errors. var errNonCanonicalVarInt = "non-canonical varint %x - discriminant %x must " + @@ -53,7 +41,7 @@ func ReadElement(r io.Reader, element interface{}) error { // type assertions first. switch e := element.(type) { case *int32: - rv, err := binaryserializer.Uint32(r, littleEndian) + rv, err := binaryserializer.Uint32(r) if err != nil { return err } @@ -61,7 +49,7 @@ func ReadElement(r io.Reader, element interface{}) error { return nil case *uint32: - rv, err := binaryserializer.Uint32(r, littleEndian) + rv, err := binaryserializer.Uint32(r) if err != nil { return err } @@ -69,7 +57,7 @@ func ReadElement(r io.Reader, element interface{}) error { return nil case *int64: - rv, err := binaryserializer.Uint64(r, littleEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return err } @@ -77,7 +65,7 @@ func ReadElement(r io.Reader, element interface{}) error { return nil case *uint64: - rv, err := binaryserializer.Uint64(r, littleEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return err } @@ -106,7 +94,7 @@ func ReadElement(r io.Reader, element interface{}) error { // Unix timestamp encoded as an int64. case *int64Time: - rv, err := binaryserializer.Uint64(r, binary.LittleEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return err } @@ -123,7 +111,7 @@ func ReadElement(r io.Reader, element interface{}) error { // Message header command. case *MessageCommand: - rv, err := binaryserializer.Uint32(r, littleEndian) + rv, err := binaryserializer.Uint32(r) if err != nil { return err } @@ -156,7 +144,7 @@ func ReadElement(r io.Reader, element interface{}) error { return nil case *ServiceFlag: - rv, err := binaryserializer.Uint64(r, littleEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return err } @@ -164,7 +152,7 @@ func ReadElement(r io.Reader, element interface{}) error { return nil case *KaspaNet: - rv, err := binaryserializer.Uint32(r, littleEndian) + rv, err := binaryserializer.Uint32(r) if err != nil { return err } @@ -193,28 +181,28 @@ func WriteElement(w io.Writer, element interface{}) error { // type assertions first. switch e := element.(type) { case int32: - err := binaryserializer.PutUint32(w, littleEndian, uint32(e)) + err := binaryserializer.PutUint32(w, uint32(e)) if err != nil { return err } return nil case uint32: - err := binaryserializer.PutUint32(w, littleEndian, e) + err := binaryserializer.PutUint32(w, e) if err != nil { return err } return nil case int64: - err := binaryserializer.PutUint64(w, littleEndian, uint64(e)) + err := binaryserializer.PutUint64(w, uint64(e)) if err != nil { return err } return nil case uint64: - err := binaryserializer.PutUint64(w, littleEndian, e) + err := binaryserializer.PutUint64(w, e) if err != nil { return err } @@ -249,7 +237,7 @@ func WriteElement(w io.Writer, element interface{}) error { // Message header command. case MessageCommand: - err := binaryserializer.PutUint32(w, littleEndian, uint32(e)) + err := binaryserializer.PutUint32(w, uint32(e)) if err != nil { return err } @@ -281,14 +269,14 @@ func WriteElement(w io.Writer, element interface{}) error { return nil case ServiceFlag: - err := binaryserializer.PutUint64(w, littleEndian, uint64(e)) + err := binaryserializer.PutUint64(w, uint64(e)) if err != nil { return err } return nil case KaspaNet: - err := binaryserializer.PutUint32(w, littleEndian, uint32(e)) + err := binaryserializer.PutUint32(w, uint32(e)) if err != nil { return err } @@ -320,7 +308,7 @@ func ReadVarInt(r io.Reader) (uint64, error) { var rv uint64 switch discriminant { case 0xff: - sv, err := binaryserializer.Uint64(r, littleEndian) + sv, err := binaryserializer.Uint64(r) if err != nil { return 0, err } @@ -335,7 +323,7 @@ func ReadVarInt(r io.Reader) (uint64, error) { } case 0xfe: - sv, err := binaryserializer.Uint32(r, littleEndian) + sv, err := binaryserializer.Uint32(r) if err != nil { return 0, err } @@ -350,7 +338,7 @@ func ReadVarInt(r io.Reader) (uint64, error) { } case 0xfd: - sv, err := binaryserializer.Uint16(r, littleEndian) + sv, err := binaryserializer.Uint16(r) if err != nil { return 0, err } @@ -370,143 +358,3 @@ func ReadVarInt(r io.Reader) (uint64, error) { return rv, nil } - -// WriteVarInt serializes val to w using a variable number of bytes depending -// on its value. -func WriteVarInt(w io.Writer, val uint64) error { - if val < 0xfd { - _, err := w.Write([]byte{uint8(val)}) - return errors.WithStack(err) - } - - if val <= math.MaxUint16 { - var buf [3]byte - buf[0] = 0xfd - littleEndian.PutUint16(buf[1:], uint16(val)) - _, err := w.Write(buf[:]) - return errors.WithStack(err) - } - - if val <= math.MaxUint32 { - var buf [5]byte - buf[0] = 0xfe - littleEndian.PutUint32(buf[1:], uint32(val)) - _, err := w.Write(buf[:]) - return errors.WithStack(err) - } - - var buf [9]byte - buf[0] = 0xff - littleEndian.PutUint64(buf[1:], val) - _, err := w.Write(buf[:]) - return errors.WithStack(err) -} - -// VarIntSerializeSize returns the number of bytes it would take to serialize -// val as a variable length integer. -func VarIntSerializeSize(val uint64) int { - // The value is small enough to be represented by itself, so it's - // just 1 byte. - if val < 0xfd { - return 1 - } - - // Discriminant 1 byte plus 2 bytes for the uint16. - if val <= math.MaxUint16 { - return 3 - } - - // Discriminant 1 byte plus 4 bytes for the uint32. - if val <= math.MaxUint32 { - return 5 - } - - // Discriminant 1 byte plus 8 bytes for the uint64. - return 9 -} - -// ReadVarString reads a variable length string from r and returns it as a Go -// string. A variable length string is encoded as a variable length integer -// containing the length of the string followed by the bytes that represent the -// string itself. An error is returned if the length is greater than the -// maximum block payload size since it helps protect against memory exhaustion -// attacks and forced panics through malformed messages. -func ReadVarString(r io.Reader, pver uint32) (string, error) { - count, err := ReadVarInt(r) - if err != nil { - return "", err - } - - // Prevent variable length strings that are larger than the maximum - // message size. It would be possible to cause memory exhaustion and - // panics without a sane upper bound on this count. - if count > MaxMessagePayload { - str := fmt.Sprintf("variable length string is too long "+ - "[count %d, max %d]", count, MaxMessagePayload) - return "", messageError("ReadVarString", str) - } - - buf := make([]byte, count) - _, err = io.ReadFull(r, buf) - if err != nil { - return "", err - } - return string(buf), nil -} - -// WriteVarString serializes str to w as a variable length integer containing -// the length of the string followed by the bytes that represent the string -// itself. -func WriteVarString(w io.Writer, str string) error { - err := WriteVarInt(w, uint64(len(str))) - if err != nil { - return err - } - _, err = w.Write([]byte(str)) - return err -} - -// ReadVarBytes reads a variable length byte array. A byte array is encoded -// as a varInt containing the length of the array followed by the bytes -// themselves. An error is returned if the length is greater than the -// passed maxAllowed parameter which helps protect against memory exhaustion -// attacks and forced panics through malformed messages. The fieldName -// parameter is only used for the error message so it provides more context in -// the error. -func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32, - fieldName string) ([]byte, error) { - - count, err := ReadVarInt(r) - if err != nil { - return nil, err - } - - // Prevent byte array larger than the max message size. It would - // be possible to cause memory exhaustion and panics without a sane - // upper bound on this count. - if count > uint64(maxAllowed) { - str := fmt.Sprintf("%s is larger than the max allowed size "+ - "[count %d, max %d]", fieldName, count, maxAllowed) - return nil, messageError("ReadVarBytes", str) - } - - b := make([]byte, count) - _, err = io.ReadFull(r, b) - if err != nil { - return nil, err - } - return b, nil -} - -// WriteVarBytes serializes a variable length byte array to w as a varInt -// containing the number of bytes, followed by the bytes themselves. -func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) error { - slen := uint64(len(bytes)) - err := WriteVarInt(w, slen) - if err != nil { - return err - } - - _, err = w.Write(bytes) - return err -} diff --git a/app/appmessage/common_test.go b/app/appmessage/common_test.go index 1714d9b49..6644d4fd9 100644 --- a/app/appmessage/common_test.go +++ b/app/appmessage/common_test.go @@ -8,7 +8,6 @@ import ( "bytes" "io" "reflect" - "strings" "testing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -233,464 +232,3 @@ func TestElementEncodingErrors(t *testing.T) { } } } - -// TestVarIntEncoding tests appmessage encode and decode for variable length integers. -func TestVarIntEncoding(t *testing.T) { - tests := []struct { - value uint64 // Value to encode - buf []byte // Encoded value - }{ - // Latest protocol version. - // Single byte - {0, []byte{0x00}}, - // Max single byte - {0xfc, []byte{0xfc}}, - // Min 2-byte - {0xfd, []byte{0xfd, 0x0fd, 0x00}}, - // Max 2-byte - {0xffff, []byte{0xfd, 0xff, 0xff}}, - // Min 4-byte - {0x10000, []byte{0xfe, 0x00, 0x00, 0x01, 0x00}}, - // Max 4-byte - {0xffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff}}, - // Min 8-byte - { - 0x100000000, - []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, - }, - // Max 8-byte - { - 0xffffffffffffffff, - []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - }, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - buf := &bytes.Buffer{} - err := WriteVarInt(buf, test.value) - if err != nil { - t.Errorf("WriteVarInt #%d error %v", i, err) - continue - } - if !bytes.Equal(buf.Bytes(), test.buf) { - t.Errorf("WriteVarInt #%d\n got: %s want: %s", i, - spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) - continue - } - - // Decode from appmessage format. - rbuf := bytes.NewReader(test.buf) - val, err := ReadVarInt(rbuf) - if err != nil { - t.Errorf("ReadVarInt #%d error %v", i, err) - continue - } - if val != test.value { - t.Errorf("ReadVarInt #%d\n got: %x want: %x", i, - val, test.value) - continue - } - } -} - -// TestVarIntEncodingErrors performs negative tests against appmessage encode and decode -// of variable length integers to confirm error paths work correctly. -func TestVarIntEncodingErrors(t *testing.T) { - tests := []struct { - in uint64 // Value to encode - buf []byte // Encoded value - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error - }{ - // Force errors on discriminant. - {0, []byte{0x00}, 0, io.ErrShortWrite, io.EOF}, - // Force errors on 2-byte read/write. - {0xfd, []byte{0xfd}, 0, io.ErrShortWrite, io.EOF}, // error on writing length - {0xfd, []byte{0xfd}, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, // error on writing actual data - // Force errors on 4-byte read/write. - {0x10000, []byte{0xfe}, 0, io.ErrShortWrite, io.EOF}, // error on writing length - {0x10000, []byte{0xfe}, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, // error on writing actual data - // Force errors on 8-byte read/write. - {0x100000000, []byte{0xff}, 0, io.ErrShortWrite, io.EOF}, // error on writing length - {0x100000000, []byte{0xff}, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, // error on writing actual data - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - w := newFixedWriter(test.max) - err := WriteVarInt(w, test.in) - if !errors.Is(err, test.writeErr) { - t.Errorf("WriteVarInt #%d wrong error got: %v, want: %v", - i, err, test.writeErr) - continue - } - - // Decode from appmessage format. - r := newFixedReader(test.max, test.buf) - _, err = ReadVarInt(r) - if !errors.Is(err, test.readErr) { - t.Errorf("ReadVarInt #%d wrong error got: %v, want: %v", - i, err, test.readErr) - continue - } - } -} - -// TestVarIntNonCanonical ensures variable length integers that are not encoded -// canonically return the expected error. -func TestVarIntNonCanonical(t *testing.T) { - pver := ProtocolVersion - - tests := []struct { - name string // Test name for easier identification - in []byte // Value to decode - pver uint32 // Protocol version for appmessage encoding - }{ - { - "0 encoded with 3 bytes", []byte{0xfd, 0x00, 0x00}, - pver, - }, - { - "max single-byte value encoded with 3 bytes", - []byte{0xfd, 0xfc, 0x00}, pver, - }, - { - "0 encoded with 5 bytes", - []byte{0xfe, 0x00, 0x00, 0x00, 0x00}, pver, - }, - { - "max three-byte value encoded with 5 bytes", - []byte{0xfe, 0xff, 0xff, 0x00, 0x00}, pver, - }, - { - "0 encoded with 9 bytes", - []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - pver, - }, - { - "max five-byte value encoded with 9 bytes", - []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - pver, - }, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Decode from appmessage format. - rbuf := bytes.NewReader(test.in) - val, err := ReadVarInt(rbuf) - if msgErr := &(MessageError{}); !errors.As(err, &msgErr) { - t.Errorf("ReadVarInt #%d (%s) unexpected error %v", i, - test.name, err) - continue - } - if val != 0 { - t.Errorf("ReadVarInt #%d (%s)\n got: %d want: 0", i, - test.name, val) - continue - } - } -} - -// TestVarIntEncoding tests the serialize size for variable length integers. -func TestVarIntSerializeSize(t *testing.T) { - tests := []struct { - val uint64 // Value to get the serialized size for - size int // Expected serialized size - }{ - // Single byte - {0, 1}, - // Max single byte - {0xfc, 1}, - // Min 2-byte - {0xfd, 3}, - // Max 2-byte - {0xffff, 3}, - // Min 4-byte - {0x10000, 5}, - // Max 4-byte - {0xffffffff, 5}, - // Min 8-byte - {0x100000000, 9}, - // Max 8-byte - {0xffffffffffffffff, 9}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - serializedSize := VarIntSerializeSize(test.val) - if serializedSize != test.size { - t.Errorf("VarIntSerializeSize #%d got: %d, want: %d", i, - serializedSize, test.size) - continue - } - } -} - -// TestVarStringEncoding tests appmessage encode and decode for variable length strings. -func TestVarStringEncoding(t *testing.T) { - pver := ProtocolVersion - - // str256 is a string that takes a 2-byte varint to encode. - str256 := strings.Repeat("test", 64) - - tests := []struct { - in string // String to encode - out string // String to decoded value - buf []byte // Encoded value - pver uint32 // Protocol version for appmessage encoding - }{ - // Latest protocol version. - // Empty string - {"", "", []byte{0x00}, pver}, - // Single byte varint + string - {"Test", "Test", append([]byte{0x04}, []byte("Test")...), pver}, - // 2-byte varint + string - {str256, str256, append([]byte{0xfd, 0x00, 0x01}, []byte(str256)...), pver}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - var buf bytes.Buffer - err := WriteVarString(&buf, test.in) - if err != nil { - t.Errorf("WriteVarString #%d error %v", i, err) - continue - } - if !bytes.Equal(buf.Bytes(), test.buf) { - t.Errorf("WriteVarString #%d\n got: %s want: %s", i, - spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) - continue - } - - // Decode from appmessage format. - rbuf := bytes.NewReader(test.buf) - val, err := ReadVarString(rbuf, test.pver) - if err != nil { - t.Errorf("ReadVarString #%d error %v", i, err) - continue - } - if val != test.out { - t.Errorf("ReadVarString #%d\n got: %s want: %s", i, - val, test.out) - continue - } - } -} - -// TestVarStringEncodingErrors performs negative tests against appmessage encode and -// decode of variable length strings to confirm error paths work correctly. -func TestVarStringEncodingErrors(t *testing.T) { - pver := ProtocolVersion - - // str256 is a string that takes a 2-byte varint to encode. - str256 := strings.Repeat("test", 64) - - tests := []struct { - in string // Value to encode - buf []byte // Encoded value - pver uint32 // Protocol version for appmessage encoding - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error - }{ - // Latest protocol version with intentional read/write errors. - // Force errors on empty string. - {"", []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF}, - // Force error on single byte varint + string. - {"Test", []byte{0x04}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, - // Force errors on 2-byte varint + string. - {str256, []byte{0xfd}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - w := newFixedWriter(test.max) - err := WriteVarString(w, test.in) - if !errors.Is(err, test.writeErr) { - t.Errorf("WriteVarString #%d wrong error got: %v, want: %v", - i, err, test.writeErr) - continue - } - - // Decode from appmessage format. - r := newFixedReader(test.max, test.buf) - _, err = ReadVarString(r, test.pver) - if !errors.Is(err, test.readErr) { - t.Errorf("ReadVarString #%d wrong error got: %v, want: %v", - i, err, test.readErr) - continue - } - } -} - -// TestVarStringOverflowErrors performs tests to ensure deserializing variable -// length strings intentionally crafted to use large values for the string -// length are handled properly. This could otherwise potentially be used as an -// attack vector. -func TestVarStringOverflowErrors(t *testing.T) { - pver := ProtocolVersion - - tests := []struct { - buf []byte // Encoded value - pver uint32 // Protocol version for appmessage encoding - err error // Expected error - }{ - {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - pver, &MessageError{}}, - {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - pver, &MessageError{}}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Decode from appmessage format. - rbuf := bytes.NewReader(test.buf) - _, err := ReadVarString(rbuf, test.pver) - if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("ReadVarString #%d wrong error got: %v, "+ - "want: %v", i, err, reflect.TypeOf(test.err)) - continue - } - } - -} - -// TestVarBytesEncoding tests appmessage encode and decode for variable length byte array. -func TestVarBytesEncoding(t *testing.T) { - pver := ProtocolVersion - - // bytes256 is a byte array that takes a 2-byte varint to encode. - bytes256 := bytes.Repeat([]byte{0x01}, 256) - - tests := []struct { - in []byte // Byte Array to write - buf []byte // Encoded value - pver uint32 // Protocol version for appmessage encoding - }{ - // Latest protocol version. - // Empty byte array - {[]byte{}, []byte{0x00}, pver}, - // Single byte varint + byte array - {[]byte{0x01}, []byte{0x01, 0x01}, pver}, - // 2-byte varint + byte array - {bytes256, append([]byte{0xfd, 0x00, 0x01}, bytes256...), pver}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - var buf bytes.Buffer - err := WriteVarBytes(&buf, test.pver, test.in) - if err != nil { - t.Errorf("WriteVarBytes #%d error %v", i, err) - continue - } - if !bytes.Equal(buf.Bytes(), test.buf) { - t.Errorf("WriteVarBytes #%d\n got: %s want: %s", i, - spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) - continue - } - - // Decode from appmessage format. - rbuf := bytes.NewReader(test.buf) - val, err := ReadVarBytes(rbuf, test.pver, MaxMessagePayload, - "test payload") - if err != nil { - t.Errorf("ReadVarBytes #%d error %v", i, err) - continue - } - if !bytes.Equal(buf.Bytes(), test.buf) { - t.Errorf("ReadVarBytes #%d\n got: %s want: %s", i, - val, test.buf) - continue - } - } -} - -// TestVarBytesEncodingErrors performs negative tests against appmessage encode and -// decode of variable length byte arrays to confirm error paths work correctly. -func TestVarBytesEncodingErrors(t *testing.T) { - pver := ProtocolVersion - - // bytes256 is a byte array that takes a 2-byte varint to encode. - bytes256 := bytes.Repeat([]byte{0x01}, 256) - - tests := []struct { - in []byte // Byte Array to write - buf []byte // Encoded value - pver uint32 // Protocol version for appmessage encoding - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error - }{ - // Latest protocol version with intentional read/write errors. - // Force errors on empty byte array. - {[]byte{}, []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF}, - // Force error on single byte varint + byte array. - {[]byte{0x01, 0x02, 0x03}, []byte{0x04}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, - // Force errors on 2-byte varint + byte array. - {bytes256, []byte{0xfd}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - w := newFixedWriter(test.max) - err := WriteVarBytes(w, test.pver, test.in) - if !errors.Is(err, test.writeErr) { - t.Errorf("WriteVarBytes #%d wrong error got: %v, want: %v", - i, err, test.writeErr) - continue - } - - // Decode from appmessage format. - r := newFixedReader(test.max, test.buf) - _, err = ReadVarBytes(r, test.pver, MaxMessagePayload, - "test payload") - if !errors.Is(err, test.readErr) { - t.Errorf("ReadVarBytes #%d wrong error got: %v, want: %v", - i, err, test.readErr) - continue - } - } -} - -// TestVarBytesOverflowErrors performs tests to ensure deserializing variable -// length byte arrays intentionally crafted to use large values for the array -// length are handled properly. This could otherwise potentially be used as an -// attack vector. -func TestVarBytesOverflowErrors(t *testing.T) { - pver := ProtocolVersion - - tests := []struct { - buf []byte // Encoded value - pver uint32 // Protocol version for appmessage encoding - err error // Expected error - }{ - {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - pver, &MessageError{}}, - {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - pver, &MessageError{}}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Decode from appmessage format. - rbuf := bytes.NewReader(test.buf) - _, err := ReadVarBytes(rbuf, test.pver, MaxMessagePayload, - "test payload") - if reflect.TypeOf(err) != reflect.TypeOf(test.err) { - t.Errorf("ReadVarBytes #%d wrong error got: %v, "+ - "want: %v", i, err, reflect.TypeOf(test.err)) - continue - } - } - -} diff --git a/domain/consensus/utils/consensusserialization/common.go b/domain/consensus/utils/consensusserialization/common.go index d6d499618..b76446503 100644 --- a/domain/consensus/utils/consensusserialization/common.go +++ b/domain/consensus/utils/consensusserialization/common.go @@ -1,7 +1,6 @@ package consensusserialization import ( - "encoding/binary" "io" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -9,12 +8,6 @@ import ( "github.com/pkg/errors" ) -var ( - // littleEndian is a convenience variable since binary.LittleEndian is - // quite long. - littleEndian = binary.LittleEndian -) - // errNoEncodingForType signifies that there's no encoding for the given type. var errNoEncodingForType = errors.New("there's no encoding for this type") @@ -26,28 +19,28 @@ func WriteElement(w io.Writer, element interface{}) error { // type assertions first. switch e := element.(type) { case int32: - err := binaryserializer.PutUint32(w, littleEndian, uint32(e)) + err := binaryserializer.PutUint32(w, uint32(e)) if err != nil { return err } return nil case uint32: - err := binaryserializer.PutUint32(w, littleEndian, e) + err := binaryserializer.PutUint32(w, e) if err != nil { return err } return nil case int64: - err := binaryserializer.PutUint64(w, littleEndian, uint64(e)) + err := binaryserializer.PutUint64(w, uint64(e)) if err != nil { return err } return nil case uint64: - err := binaryserializer.PutUint64(w, littleEndian, e) + err := binaryserializer.PutUint64(w, e) if err != nil { return err } @@ -123,7 +116,7 @@ func readElement(r io.Reader, element interface{}) error { // type assertions first. switch e := element.(type) { case *int32: - rv, err := binaryserializer.Uint32(r, littleEndian) + rv, err := binaryserializer.Uint32(r) if err != nil { return err } @@ -131,7 +124,7 @@ func readElement(r io.Reader, element interface{}) error { return nil case *uint32: - rv, err := binaryserializer.Uint32(r, littleEndian) + rv, err := binaryserializer.Uint32(r) if err != nil { return err } @@ -139,7 +132,7 @@ func readElement(r io.Reader, element interface{}) error { return nil case *int64: - rv, err := binaryserializer.Uint64(r, littleEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return err } @@ -147,7 +140,7 @@ func readElement(r io.Reader, element interface{}) error { return nil case *uint64: - rv, err := binaryserializer.Uint64(r, littleEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return err } diff --git a/domain/consensus/utils/consensusserialization/transaction.go b/domain/consensus/utils/consensusserialization/transaction.go index fbb6f0e25..e1a8b6fb9 100644 --- a/domain/consensus/utils/consensusserialization/transaction.go +++ b/domain/consensus/utils/consensusserialization/transaction.go @@ -92,7 +92,7 @@ func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransac } func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodingFlags txEncoding) error { - err := binaryserializer.PutUint32(w, littleEndian, uint32(tx.Version)) + err := binaryserializer.PutUint32(w, uint32(tx.Version)) if err != nil { return err } @@ -123,7 +123,7 @@ func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodi } } - err = binaryserializer.PutUint64(w, littleEndian, tx.LockTime) + err = binaryserializer.PutUint64(w, tx.LockTime) if err != nil { return err } @@ -133,7 +133,7 @@ func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodi return err } - err = binaryserializer.PutUint64(w, littleEndian, tx.Gas) + err = binaryserializer.PutUint64(w, tx.Gas) if err != nil { return err } @@ -175,7 +175,7 @@ func writeTransactionInput(w io.Writer, ti *externalapi.DomainTransactionInput, return err } - return binaryserializer.PutUint64(w, littleEndian, ti.Sequence) + return binaryserializer.PutUint64(w, ti.Sequence) } func writeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error { @@ -184,7 +184,7 @@ func writeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error { return err } - return binaryserializer.PutUint32(w, littleEndian, outpoint.Index) + return binaryserializer.PutUint32(w, outpoint.Index) } func writeVarBytes(w io.Writer, data []byte) error { @@ -199,7 +199,7 @@ func writeVarBytes(w io.Writer, data []byte) error { } func writeTxOut(w io.Writer, to *externalapi.DomainTransactionOutput) error { - err := binaryserializer.PutUint64(w, littleEndian, to.Value) + err := binaryserializer.PutUint64(w, to.Value) if err != nil { return err } diff --git a/domain/consensus/utils/consensusserialization/utxo_test.go b/domain/consensus/utils/consensusserialization/utxo_test.go new file mode 100644 index 000000000..2d91a904c --- /dev/null +++ b/domain/consensus/utils/consensusserialization/utxo_test.go @@ -0,0 +1,37 @@ +package consensusserialization + +import ( + "encoding/hex" + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +func Benchmark_serializeUTXO(b *testing.B) { + scriptPublicKey, err := hex.DecodeString("76a914ad06dd6ddee55cbca9a9e3713bd7587509a3056488ac") + if err != nil { + b.Fatalf("Error decoding scriptPublicKey string: %s", err) + } + entry := &externalapi.UTXOEntry{ + Amount: 5000000000, + ScriptPublicKey: scriptPublicKey, // p2pkh + BlockBlueScore: 1432432, + IsCoinbase: false, + } + 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, + } + + for i := 0; i < b.N; i++ { + _, err := SerializeUTXO(entry, outpoint) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/util/bech32/internal_test.go b/util/bech32/internal_test.go index 007b7ac9d..8ee3a003b 100644 --- a/util/bech32/internal_test.go +++ b/util/bech32/internal_test.go @@ -21,10 +21,10 @@ func TestBech32(t *testing.T) { {"::qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq40ku0e3z", true}, {"split:checkupstagehandshakeupstreamerranterredcaperred3za27wc5", true}, {"aaa:bbb", false}, // too short - {"split:checkupstagehandshakeupstreamerranterredCaperred3za27wc5", false}, // mixed uppercase and lowercase - {"split:checkupstagehandshakeupstreamerranterredcaperred3za28wc5", false}, // invalid checksum - {"s lit:checkupstagehandshakeupstreamerranterredcaperred3za27wc5", false}, // invalid character (space) in prefix - {"spl" + string(127) + "t:checkupstagehandshakeupstreamerranterredcaperred3za27wc5", false}, // invalid character (DEL) in prefix + {"split:checkupstagehandshakeupstreamerranterredCaperred3za27wc5", false}, // mixed uppercase and lowercase + {"split:checkupstagehandshakeupstreamerranterredcaperred3za28wc5", false}, // invalid checksum + {"s lit:checkupstagehandshakeupstreamerranterredcaperred3za27wc5", false}, // invalid character (space) in prefix + {"spl" + string(rune(127)) + "t:checkupstagehandshakeupstreamerranterredcaperred3za27wc5", false}, // invalid character (DEL) in prefix {"split:cheosgds2s3c", false}, // invalid character (o) in data part {"split:te5peu7", false}, // too short data part {":checkupstagehandshakeupstreamerranterredcaperred3za27wc5", false}, // empty prefix diff --git a/util/binaryserializer/binaryserializer.go b/util/binaryserializer/binaryserializer.go index 50b88f07e..7f9040f34 100644 --- a/util/binaryserializer/binaryserializer.go +++ b/util/binaryserializer/binaryserializer.go @@ -2,8 +2,9 @@ package binaryserializer import ( "encoding/binary" - "github.com/pkg/errors" "io" + + "github.com/pkg/errors" ) // maxItems is the number of buffers to keep in the free @@ -48,13 +49,13 @@ func Uint8(r io.Reader) (uint8, error) { // Uint16 reads two bytes from the provided reader using a buffer from the // free list, converts it to a number using the provided byte order, and returns // the resulting uint16. -func Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) { +func Uint16(r io.Reader) (uint16, error) { buf := Borrow()[:2] if _, err := io.ReadFull(r, buf); err != nil { Return(buf) return 0, errors.WithStack(err) } - rv := byteOrder.Uint16(buf) + rv := binary.LittleEndian.Uint16(buf) Return(buf) return rv, nil } @@ -62,13 +63,13 @@ func Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) { // Uint32 reads four bytes from the provided reader using a buffer from the // free list, converts it to a number using the provided byte order, and returns // the resulting uint32. -func Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) { +func Uint32(r io.Reader) (uint32, error) { buf := Borrow()[:4] if _, err := io.ReadFull(r, buf); err != nil { Return(buf) return 0, errors.WithStack(err) } - rv := byteOrder.Uint32(buf) + rv := binary.LittleEndian.Uint32(buf) Return(buf) return rv, nil } @@ -76,13 +77,13 @@ func Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) { // Uint64 reads eight bytes from the provided reader using a buffer from the // free list, converts it to a number using the provided byte order, and returns // the resulting uint64. -func Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) { +func Uint64(r io.Reader) (uint64, error) { buf := Borrow()[:8] if _, err := io.ReadFull(r, buf); err != nil { Return(buf) return 0, errors.WithStack(err) } - rv := byteOrder.Uint64(buf) + rv := binary.LittleEndian.Uint64(buf) Return(buf) return rv, nil } @@ -100,9 +101,9 @@ func PutUint8(w io.Writer, val uint8) error { // PutUint16 serializes the provided uint16 using the given byte order into a // buffer from the free list and writes the resulting two bytes to the given // writer. -func PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error { +func PutUint16(w io.Writer, val uint16) error { buf := Borrow()[:2] - byteOrder.PutUint16(buf, val) + binary.LittleEndian.PutUint16(buf, val) _, err := w.Write(buf) Return(buf) return errors.WithStack(err) @@ -111,22 +112,20 @@ func PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error { // PutUint32 serializes the provided uint32 using the given byte order into a // buffer from the free list and writes the resulting four bytes to the given // writer. -func PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error { - buf := Borrow()[:4] - byteOrder.PutUint32(buf, val) - _, err := w.Write(buf) - Return(buf) +func PutUint32(w io.Writer, val uint32) error { + var buf [4]byte + binary.LittleEndian.PutUint32(buf[:], val) + _, err := w.Write(buf[:]) return errors.WithStack(err) } // PutUint64 serializes the provided uint64 using the given byte order into a // buffer from the free list and writes the resulting eight bytes to the given // writer. -func PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error { - buf := Borrow()[:8] - byteOrder.PutUint64(buf, val) - _, err := w.Write(buf) - Return(buf) +func PutUint64(w io.Writer, val uint64) error { + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], val) + _, err := w.Write(buf[:]) return errors.WithStack(err) } diff --git a/util/coinbasepayload/coinbasepayload.go b/util/coinbasepayload/coinbasepayload.go deleted file mode 100644 index db571ac64..000000000 --- a/util/coinbasepayload/coinbasepayload.go +++ /dev/null @@ -1,66 +0,0 @@ -package coinbasepayload - -import ( - "bytes" - "encoding/binary" - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/util/binaryserializer" - "github.com/pkg/errors" -) - -var byteOrder = binary.LittleEndian - -// SerializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data. -func SerializeCoinbasePayload(blueScore uint64, scriptPubKey []byte, extraData []byte) ([]byte, error) { - w := &bytes.Buffer{} - err := binaryserializer.PutUint64(w, byteOrder, blueScore) - if err != nil { - return nil, err - } - err = appmessage.WriteVarInt(w, uint64(len(scriptPubKey))) - if err != nil { - return nil, err - } - _, err = w.Write(scriptPubKey) - if err != nil { - return nil, err - } - _, err = w.Write(extraData) - if err != nil { - return nil, err - } - return w.Bytes(), nil -} - -// ErrIncorrectScriptPubKeyLen indicates that the script pub key length is not as expected. -var ErrIncorrectScriptPubKeyLen = errors.New("incorrect script pub key length") - -// DeserializeCoinbasePayload deserializes the coinbase payload to its component (scriptPubKey and extra data). -func DeserializeCoinbasePayload(tx *appmessage.MsgTx) (blueScore uint64, scriptPubKey []byte, extraData []byte, err error) { - r := bytes.NewReader(tx.Payload) - blueScore, err = binaryserializer.Uint64(r, byteOrder) - if err != nil { - return 0, nil, nil, err - } - scriptPubKeyLen, err := appmessage.ReadVarInt(r) - if err != nil { - return 0, nil, nil, err - } - scriptPubKey = make([]byte, scriptPubKeyLen) - n, err := r.Read(scriptPubKey) - if err != nil { - return 0, nil, nil, err - } - if uint64(n) != scriptPubKeyLen { - return 0, nil, nil, - errors.Wrapf(ErrIncorrectScriptPubKeyLen, "expected %d bytes in script pub key but got %d", scriptPubKeyLen, n) - } - extraData = make([]byte, r.Len()) - if r.Len() != 0 { - _, err = r.Read(extraData) - if err != nil { - return 0, nil, nil, err - } - } - return blueScore, scriptPubKey, extraData, nil -} diff --git a/util/random/random.go b/util/random/random.go index 9d98b7575..cd027d25d 100644 --- a/util/random/random.go +++ b/util/random/random.go @@ -2,7 +2,6 @@ package random import ( "crypto/rand" - "encoding/binary" "io" "github.com/kaspanet/kaspad/util/binaryserializer" @@ -12,7 +11,7 @@ import ( // unexported version takes a reader primarily to ensure the error paths // can be properly tested by passing a fake reader in the tests. func randomUint64(r io.Reader) (uint64, error) { - rv, err := binaryserializer.Uint64(r, binary.BigEndian) + rv, err := binaryserializer.Uint64(r) if err != nil { return 0, err } From f1c6df48c9c67d939622c9f6b7e78b10985e18a3 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 1 Dec 2020 08:48:23 +0200 Subject: [PATCH 102/351] [#1028] Replace oldschnorr with the BIP340 schnorr variant (#1165) * Update go-secp256k1 to v0.0.3 * Update the txscript engine to support only 32 bytes pubkeys * Update the txscript engine tests * Update txscript/sign.go to use the new Schnorr KeyPair API * Update txscript sign_test to use the new schnorr * Update sigcache tests to use new schnorr pubkey * Update integration tests to use the new txscript and new schnorr pubkey --- domain/consensus/utils/txscript/engine.go | 7 +- .../consensus/utils/txscript/engine_test.go | 19 +- .../consensus/utils/txscript/sigcache_test.go | 16 +- domain/consensus/utils/txscript/sign.go | 25 +- domain/consensus/utils/txscript/sign_test.go | 479 +++++------------- go.mod | 2 +- go.sum | 44 +- testing/integration/config_test.go | 6 +- testing/integration/tx_relay_test.go | 13 +- 9 files changed, 180 insertions(+), 431 deletions(-) diff --git a/domain/consensus/utils/txscript/engine.go b/domain/consensus/utils/txscript/engine.go index c22abf9ae..fde7653e8 100644 --- a/domain/consensus/utils/txscript/engine.go +++ b/domain/consensus/utils/txscript/engine.go @@ -364,12 +364,7 @@ func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error { // checkPubKeyEncoding returns whether or not the passed public key adheres to // the strict encoding requirements if enabled. func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error { - if len(pubKey) == 33 && (pubKey[0] == 0x02 || pubKey[0] == 0x03) { - // Compressed - return nil - } - if len(pubKey) == 65 && pubKey[0] == 0x04 { - // Uncompressed + if len(pubKey) == 32 { return nil } diff --git a/domain/consensus/utils/txscript/engine_test.go b/domain/consensus/utils/txscript/engine_test.go index 46f1dafc6..5d0968d28 100644 --- a/domain/consensus/utils/txscript/engine_test.go +++ b/domain/consensus/utils/txscript/engine_test.go @@ -163,33 +163,38 @@ func TestCheckPubKeyEncoding(t *testing.T) { isValid bool }{ { - name: "uncompressed ok", + name: "uncompressed - invalid", key: hexToBytes("0411db93e1dcdb8a016b49840f8c53bc1eb68" + "a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf" + "9744464f82e160bfa9b8b64f9d4c03f999b8643f656b" + "412a3"), - isValid: true, + isValid: false, }, { - name: "compressed ok", + name: "compressed - invalid", key: hexToBytes("02ce0b14fb842b1ba549fdd675c98075f12e9" + "c510f8ef52bd021a9a1f4809d3b4d"), - isValid: true, + isValid: false, }, { - name: "compressed ok", + name: "compressed - invalid", key: hexToBytes("032689c7c2dab13309fb143e0e8fe39634252" + "1887e976690b6b47f5b2a4b7d448e"), - isValid: true, + isValid: false, }, { - name: "hybrid", + name: "hybrid - invalid", key: hexToBytes("0679be667ef9dcbbac55a06295ce870b07029" + "bfcdb2dce28d959f2815b16f81798483ada7726a3c46" + "55da4fbfc0e1108a8fd17b448a68554199c47d08ffb1" + "0d4b8"), isValid: false, }, + { + name: "32 bytes pubkey - Ok", + key: hexToBytes("2689c7c2dab13309fb143e0e8fe396342521887e976690b6b47f5b2a4b7d448e"), + isValid: true, + }, { name: "empty", key: nil, diff --git a/domain/consensus/utils/txscript/sigcache_test.go b/domain/consensus/utils/txscript/sigcache_test.go index 905fc0f7a..fd513d045 100644 --- a/domain/consensus/utils/txscript/sigcache_test.go +++ b/domain/consensus/utils/txscript/sigcache_test.go @@ -53,8 +53,8 @@ func TestSigCacheAddExists(t *testing.T) { // The previously added triplet should now be found within the sigcache. sig1Copy := secp256k1.DeserializeSchnorrSignature(sig1.Serialize()) - key1Serialized, _ := key1.SerializeCompressed() - key1Copy, _ := secp256k1.DeserializeSchnorrPubKey(key1Serialized) + key1Serialized, _ := key1.Serialize() + key1Copy, _ := secp256k1.DeserializeSchnorrPubKey(key1Serialized[:]) if !sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added item not found in signature cache") } @@ -78,8 +78,8 @@ func TestSigCacheAddEvictEntry(t *testing.T) { sigCache.Add(*msg, sig, key) sigCopy := secp256k1.DeserializeSchnorrSignature(sig.Serialize()) - keySerialized, _ := key.SerializeCompressed() - keyCopy, _ := secp256k1.DeserializeSchnorrPubKey(keySerialized) + keySerialized, _ := key.Serialize() + keyCopy, _ := secp256k1.DeserializeSchnorrPubKey(keySerialized[:]) if !sigCache.Exists(*msg, sigCopy, keyCopy) { t.Errorf("previously added item not found in signature" + "cache") @@ -108,8 +108,8 @@ func TestSigCacheAddEvictEntry(t *testing.T) { // The entry added above should be found within the sigcache. sigNewCopy := secp256k1.DeserializeSchnorrSignature(sigNew.Serialize()) - keyNewSerialized, _ := keyNew.SerializeCompressed() - keyNewCopy, _ := secp256k1.DeserializeSchnorrPubKey(keyNewSerialized) + keyNewSerialized, _ := keyNew.Serialize() + keyNewCopy, _ := secp256k1.DeserializeSchnorrPubKey(keyNewSerialized[:]) if !sigCache.Exists(*msgNew, sigNewCopy, keyNewCopy) { t.Fatalf("previously added item not found in signature cache") } @@ -132,8 +132,8 @@ func TestSigCacheAddMaxEntriesZeroOrNegative(t *testing.T) { // The generated triplet should not be found. sig1Copy := secp256k1.DeserializeSchnorrSignature(sig1.Serialize()) - key1Serialized, _ := key1.SerializeCompressed() - key1Copy, _ := secp256k1.DeserializeSchnorrPubKey(key1Serialized) + key1Serialized, _ := key1.Serialize() + key1Copy, _ := secp256k1.DeserializeSchnorrPubKey(key1Serialized[:]) if sigCache.Exists(*msg1, sig1Copy, key1Copy) { t.Errorf("previously added signature found in sigcache, but" + "shouldn't have been") diff --git a/domain/consensus/utils/txscript/sign.go b/domain/consensus/utils/txscript/sign.go index d2783705c..e6a450916 100644 --- a/domain/consensus/utils/txscript/sign.go +++ b/domain/consensus/utils/txscript/sign.go @@ -16,7 +16,7 @@ import ( // RawTxInSignature returns the serialized Schnorr signature for the input idx of // the given transaction, with hashType appended to it. func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, script []byte, - hashType SigHashType, key *secp256k1.PrivateKey) ([]byte, error) { + hashType SigHashType, key *secp256k1.SchnorrKeyPair) ([]byte, error) { hash, err := CalcSignatureHash(script, hashType, tx, idx) if err != nil { @@ -39,7 +39,7 @@ func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, script []byte, // as the idx'th input. privKey is serialized in either a compressed or // uncompressed format based on compress. This format must match the same format // used to generate the payment address, or the script validation will fail. -func SignatureScript(tx *externalapi.DomainTransaction, idx int, script []byte, hashType SigHashType, privKey *secp256k1.PrivateKey, compress bool) ([]byte, error) { +func SignatureScript(tx *externalapi.DomainTransaction, idx int, script []byte, hashType SigHashType, privKey *secp256k1.SchnorrKeyPair) ([]byte, error) { sig, err := RawTxInSignature(tx, idx, script, hashType, privKey) if err != nil { return nil, err @@ -49,17 +49,12 @@ func SignatureScript(tx *externalapi.DomainTransaction, idx int, script []byte, if err != nil { return nil, err } - var pkData []byte - if compress { - pkData, err = pk.SerializeCompressed() - } else { - pkData, err = pk.SerializeUncompressed() - } + pkData, err := pk.Serialize() if err != nil { return nil, err } - return NewScriptBuilder().AddData(sig).AddData(pkData).Script() + return NewScriptBuilder().AddData(sig).AddData(pkData[:]).Script() } func sign(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx int, @@ -75,13 +70,12 @@ func sign(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx in switch class { case PubKeyHashTy: // look up key for address - key, compressed, err := kdb.GetKey(address) + key, err := kdb.GetKey(address) if err != nil { return nil, class, nil, err } - signedScript, err := SignatureScript(tx, idx, script, hashType, - key, compressed) + signedScript, err := SignatureScript(tx, idx, script, hashType, key) if err != nil { return nil, class, nil, err } @@ -162,15 +156,14 @@ func mergeScripts(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction // KeyDB is an interface type provided to SignTxOutput, it encapsulates // any user state required to get the private keys for an address. type KeyDB interface { - GetKey(util.Address) (*secp256k1.PrivateKey, bool, error) + GetKey(util.Address) (*secp256k1.SchnorrKeyPair, error) } // KeyClosure implements KeyDB with a closure. -type KeyClosure func(util.Address) (*secp256k1.PrivateKey, bool, error) +type KeyClosure func(util.Address) (*secp256k1.SchnorrKeyPair, error) // GetKey implements KeyDB by returning the result of calling the closure. -func (kc KeyClosure) GetKey(address util.Address) (*secp256k1.PrivateKey, - bool, error) { +func (kc KeyClosure) GetKey(address util.Address) (*secp256k1.SchnorrKeyPair, error) { return kc(address) } diff --git a/domain/consensus/utils/txscript/sign_test.go b/domain/consensus/utils/txscript/sign_test.go index 32c438320..7a36cab24 100644 --- a/domain/consensus/utils/txscript/sign_test.go +++ b/domain/consensus/utils/txscript/sign_test.go @@ -16,25 +16,18 @@ import ( "github.com/kaspanet/kaspad/util" ) -type addressToKey struct { - key *secp256k1.PrivateKey - compressed bool -} - -func mkGetKey(keys map[string]addressToKey) KeyDB { +func mkGetKey(keys map[string]*secp256k1.SchnorrKeyPair) KeyDB { if keys == nil { - return KeyClosure(func(addr util.Address) (*secp256k1.PrivateKey, - bool, error) { - return nil, false, errors.New("nope") + return KeyClosure(func(addr util.Address) (*secp256k1.SchnorrKeyPair, error) { + return nil, errors.New("nope") }) } - return KeyClosure(func(addr util.Address) (*secp256k1.PrivateKey, - bool, error) { - a2k, ok := keys[addr.EncodeAddress()] + return KeyClosure(func(addr util.Address) (*secp256k1.SchnorrKeyPair, error) { + key, ok := keys[addr.EncodeAddress()] if !ok { - return nil, false, errors.New("nope") + return nil, errors.New("nope") } - return a2k.key, a2k.compressed, nil + return key, nil }) } @@ -139,7 +132,7 @@ func TestSignTxOutput(t *testing.T) { Outputs: outputs, } - // Pay to Pubkey Hash (uncompressed) + // Pay to Pubkey Hash (merging with correct) for _, hashType := range hashTypes { for i := range tx.Inputs { msg := fmt.Sprintf("%d:%d", hashType, i) @@ -157,63 +150,14 @@ func TestSignTxOutput(t *testing.T) { break } - uncompressedPubKey, err := pubKey.SerializeUncompressed() - if err != nil { - t.Errorf("failed to make a pubkey for %s: %s", - key, err) - break - } - - address, err := util.NewAddressPubKeyHash( - util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - break - } - - scriptPubKey, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make scriptPubKey "+ - "for %s: %v", msg, err) - } - - if err := signAndCheck(msg, tx, i, scriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, false}, - }), mkGetScript(nil), nil); err != nil { - t.Error(err) - break - } - } - } - - // Pay to Pubkey Hash (uncompressed) (merging with correct) - for _, hashType := range hashTypes { - for i := range tx.Inputs { - msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := secp256k1.GeneratePrivateKey() - if err != nil { - t.Errorf("failed to make privKey for %s: %s", - msg, err) - break - } - - pubKey, err := key.SchnorrPublicKey() - if err != nil { - t.Errorf("failed to make a publickey for %s: %s", - key, err) - break - } - - uncompressedPubKey, err := pubKey.SerializeUncompressed() + serializedPubKey, err := pubKey.Serialize() if err != nil { t.Errorf("failed to make a pubkey for %s: %s", key, err) break } address, err := util.NewAddressPubKeyHash( - util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) + util.Hash160(serializedPubKey[:]), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -228,8 +172,8 @@ func TestSignTxOutput(t *testing.T) { sigScript, err := SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, false}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, @@ -241,8 +185,8 @@ func TestSignTxOutput(t *testing.T) { // again and merge. sigScript, err = SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, false}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ @@ -278,7 +222,7 @@ func TestSignTxOutput(t *testing.T) { break } - compressedPubKey, err := pubKey.SerializeCompressed() + serializedPubKey, err := pubKey.Serialize() if err != nil { t.Errorf("failed to make a pubkey for %s: %s", key, err) @@ -286,7 +230,7 @@ func TestSignTxOutput(t *testing.T) { } address, err := util.NewAddressPubKeyHash( - util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + util.Hash160(serializedPubKey[:]), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -300,8 +244,8 @@ func TestSignTxOutput(t *testing.T) { } if err := signAndCheck(msg, tx, i, scriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, true}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(nil), nil); err != nil { t.Error(err) break @@ -309,7 +253,7 @@ func TestSignTxOutput(t *testing.T) { } } - // Pay to Pubkey Hash (compressed) with duplicate merge + // Pay to Pubkey Hash with duplicate merge for _, hashType := range hashTypes { for i := range tx.Inputs { msg := fmt.Sprintf("%d:%d", hashType, i) @@ -328,7 +272,7 @@ func TestSignTxOutput(t *testing.T) { break } - compressedPubKey, err := pubKey.SerializeCompressed() + serializedPubKey, err := pubKey.Serialize() if err != nil { t.Errorf("failed to make a pubkey for %s: %s", key, err) @@ -336,7 +280,7 @@ func TestSignTxOutput(t *testing.T) { } address, err := util.NewAddressPubKeyHash( - util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + util.Hash160(serializedPubKey[:]), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -351,8 +295,8 @@ func TestSignTxOutput(t *testing.T) { sigScript, err := SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, true}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(nil), nil) if err != nil { t.Errorf("failed to sign output %s: %v", msg, @@ -364,8 +308,8 @@ func TestSignTxOutput(t *testing.T) { // again and merge. sigScript, err = SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, true}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(nil), sigScript) if err != nil { t.Errorf("failed to sign output %s a "+ @@ -383,168 +327,8 @@ func TestSignTxOutput(t *testing.T) { } // As before, but with p2sh now. - // Pay to Pubkey Hash (uncompressed) - for _, hashType := range hashTypes { - for i := range tx.Inputs { - msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := secp256k1.GeneratePrivateKey() - if err != nil { - t.Errorf("failed to make privKey for %s: %s", - msg, err) - break - } - pubKey, err := key.SchnorrPublicKey() - if err != nil { - t.Errorf("failed to make a publickey for %s: %s", - key, err) - break - } - - uncompressedPubKey, err := pubKey.SerializeUncompressed() - if err != nil { - t.Errorf("failed to make a pubkey for %s: %s", - key, err) - break - } - - address, err := util.NewAddressPubKeyHash( - util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - break - } - - scriptPubKey, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make scriptPubKey "+ - "for %s: %v", msg, err) - break - } - - scriptAddr, err := util.NewAddressScriptHash( - scriptPubKey, util.Bech32PrefixKaspaTest) - if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) - break - } - - scriptScriptPubKey, err := PayToAddrScript( - scriptAddr) - if err != nil { - t.Errorf("failed to make script scriptPubKey for "+ - "%s: %v", msg, err) - break - } - - if err := signAndCheck(msg, tx, i, scriptScriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, false}, - }), mkGetScript(map[string][]byte{ - scriptAddr.EncodeAddress(): scriptPubKey, - }), nil); err != nil { - t.Error(err) - break - } - } - } - - // Pay to Pubkey Hash (uncompressed) with duplicate merge - for _, hashType := range hashTypes { - for i := range tx.Inputs { - msg := fmt.Sprintf("%d:%d", hashType, i) - key, err := secp256k1.GeneratePrivateKey() - if err != nil { - t.Errorf("failed to make privKey for %s: %s", - msg, err) - break - } - - pubKey, err := key.SchnorrPublicKey() - if err != nil { - t.Errorf("failed to make a publickey for %s: %s", - key, err) - break - } - - uncompressedPubKey, err := pubKey.SerializeUncompressed() - if err != nil { - t.Errorf("failed to make a pubkey for %s: %s", - key, err) - break - } - - address, err := util.NewAddressPubKeyHash( - util.Hash160(uncompressedPubKey), util.Bech32PrefixKaspaTest) - if err != nil { - t.Errorf("failed to make address for %s: %v", - msg, err) - break - } - - scriptPubKey, err := PayToAddrScript(address) - if err != nil { - t.Errorf("failed to make scriptPubKey "+ - "for %s: %v", msg, err) - break - } - - scriptAddr, err := util.NewAddressScriptHash( - scriptPubKey, util.Bech32PrefixKaspaTest) - if err != nil { - t.Errorf("failed to make p2sh addr for %s: %v", - msg, err) - break - } - - scriptScriptPubKey, err := PayToAddrScript( - scriptAddr) - if err != nil { - t.Errorf("failed to make script scriptPubKey for "+ - "%s: %v", msg, err) - break - } - - _, err = SignTxOutput(&dagconfig.TestnetParams, - tx, i, scriptScriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, false}, - }), mkGetScript(map[string][]byte{ - scriptAddr.EncodeAddress(): scriptPubKey, - }), nil) - if err != nil { - t.Errorf("failed to sign output %s: %v", msg, - err) - break - } - - // by the above loop, this should be valid, now sign - // again and merge. - sigScript, err := SignTxOutput(&dagconfig.TestnetParams, - tx, i, scriptScriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, false}, - }), mkGetScript(map[string][]byte{ - scriptAddr.EncodeAddress(): scriptPubKey, - }), nil) - if err != nil { - t.Errorf("failed to sign output %s a "+ - "second time: %v", msg, err) - break - } - - err = checkScripts(msg, tx, i, sigScript, scriptScriptPubKey) - if err != nil { - t.Errorf("twice signed script invalid for "+ - "%s: %v", msg, err) - break - } - } - } - - // Pay to Pubkey Hash (compressed) + // Pay to Pubkey Hash for _, hashType := range hashTypes { for i := range tx.Inputs { msg := fmt.Sprintf("%d:%d", hashType, i) @@ -563,7 +347,7 @@ func TestSignTxOutput(t *testing.T) { break } - compressedPubKey, err := pubKey.SerializeCompressed() + serializedPubKey, err := pubKey.Serialize() if err != nil { t.Errorf("failed to make a pubkey for %s: %s", key, err) @@ -571,7 +355,7 @@ func TestSignTxOutput(t *testing.T) { } address, err := util.NewAddressPubKeyHash( - util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + util.Hash160(serializedPubKey[:]), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -601,8 +385,8 @@ func TestSignTxOutput(t *testing.T) { } if err := signAndCheck(msg, tx, i, scriptScriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, true}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): scriptPubKey, }), nil); err != nil { @@ -631,7 +415,7 @@ func TestSignTxOutput(t *testing.T) { break } - compressedPubKey, err := pubKey.SerializeCompressed() + serializedPubKey, err := pubKey.Serialize() if err != nil { t.Errorf("failed to make a pubkey for %s: %s", key, err) @@ -639,7 +423,7 @@ func TestSignTxOutput(t *testing.T) { } address, err := util.NewAddressPubKeyHash( - util.Hash160(compressedPubKey), util.Bech32PrefixKaspaTest) + util.Hash160(serializedPubKey[:]), util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make address for %s: %v", msg, err) @@ -670,8 +454,8 @@ func TestSignTxOutput(t *testing.T) { _, err = SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptScriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, true}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): scriptPubKey, }), nil) @@ -685,8 +469,8 @@ func TestSignTxOutput(t *testing.T) { // again and merge. sigScript, err := SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptScriptPubKey, hashType, - mkGetKey(map[string]addressToKey{ - address.EncodeAddress(): {key, true}, + mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ + address.EncodeAddress(): key, }), mkGetScript(map[string][]byte{ scriptAddr.EncodeAddress(): scriptPubKey, }), nil) @@ -717,7 +501,6 @@ type tstSigScript struct { name string inputs []tstInput hashType SigHashType - compress bool scriptAtWrongIndex bool } @@ -732,12 +515,15 @@ var ( 0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65, 0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, 0xd6, 0x0e, 0x06, 0x92} - uncompressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + oldUncompressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, 0x53, 0x90, 0x0e, 0x0a, 0x86, 0xc9, 0xfa, 0x88, 0xac} - compressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, + oldCompressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, 0x61, 0x7e, 0x7c, 0x7a, 0x1c, 0x1f, 0xb2, 0x75, 0x79, 0x10, 0x43, 0x65, 0x68, 0x27, 0x9d, 0x86, 0x88, 0xac} + p2pkhScriptPubKey = []byte{0x76, 0xa9, 0x14, 0x7e, 0x01, 0x76, 0xb6, + 0x72, 0x08, 0xc0, 0x08, 0x98, 0x85, 0x97, 0x00, 0x4e, 0x1a, 0x8d, + 0x60, 0x89, 0xfe, 0x42, 0x6f, 0x88, 0xac} shortScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, 0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac} @@ -749,12 +535,94 @@ const fee = 5000000 var sigScriptTests = []tstSigScript{ { - name: "one input uncompressed", + name: "one input old uncompressed", inputs: []tstInput{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: oldUncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + scriptAtWrongIndex: false, + }, + { + name: "two inputs old uncompressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: oldUncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal + fee, + ScriptPublicKey: oldUncompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + scriptAtWrongIndex: false, + }, + { + name: "one input old compressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: oldCompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + scriptAtWrongIndex: false, + }, + { + name: "two inputs old compressed", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: oldCompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal + fee, + ScriptPublicKey: oldCompressedScriptPubKey, + }, + sigscriptGenerates: true, + inputValidates: false, + indexOutOfRange: false, + }, + }, + hashType: SigHashAll, + scriptAtWrongIndex: false, + }, + { + name: "one input 32byte pubkey", + inputs: []tstInput{ + { + txout: &externalapi.DomainTransactionOutput{ + Value: coinbaseVal, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -762,16 +630,15 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAll, - compress: false, scriptAtWrongIndex: false, }, { - name: "two inputs uncompressed", + name: "two inputs 32byte pubkey", inputs: []tstInput{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -780,7 +647,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal + fee, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -788,50 +655,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAll, - compress: false, - scriptAtWrongIndex: false, - }, - { - name: "one input compressed", - inputs: []tstInput{ - { - txout: &externalapi.DomainTransactionOutput{ - Value: coinbaseVal, - ScriptPublicKey: compressedScriptPubKey, - }, - sigscriptGenerates: true, - inputValidates: true, - indexOutOfRange: false, - }, - }, - hashType: SigHashAll, - compress: true, - scriptAtWrongIndex: false, - }, - { - name: "two inputs compressed", - inputs: []tstInput{ - { - txout: &externalapi.DomainTransactionOutput{ - Value: coinbaseVal, - ScriptPublicKey: compressedScriptPubKey, - }, - sigscriptGenerates: true, - inputValidates: true, - indexOutOfRange: false, - }, - { - txout: &externalapi.DomainTransactionOutput{ - Value: coinbaseVal + fee, - ScriptPublicKey: compressedScriptPubKey, - }, - sigscriptGenerates: true, - inputValidates: true, - indexOutOfRange: false, - }, - }, - hashType: SigHashAll, - compress: true, scriptAtWrongIndex: false, }, { @@ -840,7 +663,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -848,7 +671,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashNone, - compress: false, scriptAtWrongIndex: false, }, { @@ -857,7 +679,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -865,7 +687,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashSingle, - compress: false, scriptAtWrongIndex: false, }, { @@ -874,7 +695,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -882,7 +703,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAll | SigHashAnyOneCanPay, - compress: false, scriptAtWrongIndex: false, }, { @@ -891,7 +711,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: false, @@ -899,7 +719,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAnyOneCanPay, - compress: false, scriptAtWrongIndex: false, }, { @@ -908,7 +727,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: false, @@ -916,24 +735,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: 0x04, - compress: false, - scriptAtWrongIndex: false, - }, - { - name: "invalid compression", - inputs: []tstInput{ - { - txout: &externalapi.DomainTransactionOutput{ - Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, - }, - sigscriptGenerates: true, - inputValidates: false, - indexOutOfRange: false, - }, - }, - hashType: SigHashAll, - compress: true, scriptAtWrongIndex: false, }, { @@ -949,7 +750,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAll, - compress: false, scriptAtWrongIndex: false, }, { @@ -958,7 +758,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -967,7 +767,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal + fee, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -975,7 +775,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAll, - compress: false, scriptAtWrongIndex: true, }, { @@ -984,7 +783,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -993,7 +792,7 @@ var sigScriptTests = []tstSigScript{ { txout: &externalapi.DomainTransactionOutput{ Value: coinbaseVal + fee, - ScriptPublicKey: uncompressedScriptPubKey, + ScriptPublicKey: p2pkhScriptPubKey, }, sigscriptGenerates: true, inputValidates: true, @@ -1001,7 +800,6 @@ var sigScriptTests = []tstSigScript{ }, }, hashType: SigHashAll, - compress: false, scriptAtWrongIndex: true, }, } @@ -1046,8 +844,7 @@ nexttest: } script, err = SignatureScript(tx, idx, sigScriptTests[i].inputs[j].txout.ScriptPublicKey, - sigScriptTests[i].hashType, privKey, - sigScriptTests[i].compress) + sigScriptTests[i].hashType, privKey) if (err == nil) != sigScriptTests[i].inputs[j].sigscriptGenerates { if err == nil { diff --git a/go.mod b/go.mod index 57a1ac0a6..50ef525b8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/golang/protobuf v1.4.2 github.com/jessevdk/go-flags v1.4.0 github.com/jrick/logrotate v1.0.0 - github.com/kaspanet/go-secp256k1 v0.0.2 + github.com/kaspanet/go-secp256k1 v0.0.3 github.com/pkg/errors v0.9.1 github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 diff --git a/go.sum b/go.sum index 8bfb2dbe2..ef0ff054b 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,21 @@ -cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -35,7 +23,6 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= @@ -45,55 +32,40 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/kaspanet/go-secp256k1 v0.0.2 h1:KZGXddYHxzS02rx6EPPQYYe2tZ/rREj4P6XxgQQwQIw= -github.com/kaspanet/go-secp256k1 v0.0.2/go.mod h1:W9OcWBKzH8P/PN2WAUn9k2YmZG/Uc660WAL1NTS3G3M= -github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= +github.com/kaspanet/go-secp256k1 v0.0.3 h1:zvrKddgUm/sZ0capLUZVcn2tKoAvQaXytZYrOzLZWx4= +github.com/kaspanet/go-secp256k1 v0.0.3/go.mod h1:cFbxhxKkxqHX5eIwUGKARkph19PehipDPJejWB+H0jM= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -106,13 +78,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20200228224639-71482053b885 h1:y09Juz/HD0YjGlyEd4bLUWG0s8Yx6iPniPqUGzUxNrU= -golang.org/x/tools v0.0.0-20200228224639-71482053b885/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -134,14 +101,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/testing/integration/config_test.go b/testing/integration/config_test.go index 4089d6cf3..dd5253073 100644 --- a/testing/integration/config_test.go +++ b/testing/integration/config_test.go @@ -18,13 +18,13 @@ const ( rpcAddress2 = "127.0.0.1:12346" rpcAddress3 = "127.0.0.1:12347" - miningAddress1 = "kaspasim:qzmdkk8ay8sgvp8cnwts8gtdylz9j7572slwdh85qv" + miningAddress1 = "kaspasim:qzpj2cfa9m40w9m2cmr8pvfuqpp32mzzwsuw6ukhfd" miningAddress1PrivateKey = "be9e9884f03e687166479e22d21b064db7903d69b5a46878aae66521c01a6094" - miningAddress2 = "kaspasim:qze20hwkc4lzq37jt0hrym5emlsxxs8j3qyf3y4ghs" + miningAddress2 = "kaspasim:qr7w7nqsdnc3zddm6u8s9fex4ysk95hm3v30q353ym" miningAddress2PrivateKey = "98bd8d8e1f7078abefd017839f83edd0e3c8226ed4989e4d7a8bceb5935de193" - miningAddress3 = "kaspasim:qretklduvhg5h2aj7jd8w4heq7pvtkpv9q6w4sqfen" + miningAddress3 = "kaspasim:qz7n8gfak3j2wt9vywy5ljhs3v3xu7lgmutfjqaay5" miningAddress3PrivateKey = "eb0af684f2cdbb4ed2d85fbfe0b7f40654a7777fb2c47f142ffb5543b594d1e4" defaultTimeout = 10 * time.Second diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 42cbb5d52..1975a5700 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -6,15 +6,12 @@ import ( "testing" "time" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" - - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/util" ) @@ -116,7 +113,7 @@ func generateTx(t *testing.T, firstBlockCoinbase *externalapi.DomainTransaction, } signatureScript, err := txscript.SignatureScript(appmessage.MsgTxToDomainTransaction(tx), 0, - fromScript, txscript.SigHashAll, privateKey, true) + fromScript, txscript.SigHashAll, privateKey) if err != nil { t.Fatalf("Error signing transaction: %+v", err) } From 21fc2d421961a9c8caf09ad56bd3e4a5de744c1b Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 1 Dec 2020 16:54:13 +0200 Subject: [PATCH 103/351] [NOD-1433] Write specified unit tests for GHOSTDAG (#1010) commit 3830df34b2a53c361c8a6ca450f7f4a683fe1ae1 Merge: 46dc2e977 17e7819c2 Author: Elichai Turkel Date: Tue Dec 1 16:29:51 2020 +0200 Merge pull request #1170 from kaspanet/tal-ghost-fix Fix GhostDAG tests and jsons commit 17e7819c27153b8527f18d638a3173a6cc4975eb Author: Elichai Turkel Date: Tue Dec 1 16:24:01 2020 +0200 Remove non-json ghostdag tests commit 4bebb1d96a8740c5359351c0aea7aca20067d65b Author: Elichai Turkel Date: Tue Dec 1 13:26:06 2020 +0200 Add a coment above tal's ghostdag2 impl commit faf21a042e0f40f3842bbe2b4a6aeef48a9bf0fd Author: Elichai Turkel Date: Tue Dec 1 13:20:08 2020 +0200 fix the interfaces after merge commit a8b7a25b2e85a47ef2acffa426db25ce0d8c753c Merge: af91b69b2 f1c6df48c Author: Elichai Turkel Date: Tue Dec 1 13:19:08 2020 +0200 Merge branch 'v0.8.2-dev' into tal-ghost-fix commit af91b69b207cf3c3e9eaedf031810153b8a576d3 Author: Elichai Turkel Date: Tue Dec 1 13:18:41 2020 +0200 Fix the non-json tests commit c56f34b73b16f0b28f02f4dc5ae4607b420afb36 Author: Elichai Turkel Date: Tue Dec 1 13:18:17 2020 +0200 Fix the jsons commit 46dc2e97736e304fa5398289566c0d281d02cf8e Author: tal Date: Mon Nov 30 17:15:20 2020 +0200 [NOD - 1143] Cosmetics changes. commit b28e5ce816c8f9ea69720b0c8d2e8fb63fc1d6c3 Author: tal Date: Mon Nov 30 15:48:08 2020 +0200 [#1126] Place selectedParent to be first on blueMergeSet. commit 4b56ed2da94638736d02c038acaa4ab4d8b625ac Author: tal Date: Mon Nov 30 14:51:50 2020 +0200 [#1126] Change pacement between blockRight and blockLeft . commit b09f31be9301cf51a8f3866166cf38a174c368c9 Merge: e17a98b7b 0db39833f Author: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Mon Nov 30 14:30:22 2020 +0200 Merge pull request #1162 from kaspanet/new-jsons Update the dag json tests commit e17a98b7ba4beba77699fb68081a0d23f4feb714 Author: tal Date: Mon Nov 30 14:08:25 2020 +0200 [#1126] Use WALK function in tests & cosmetic changes. commit 0db39833f3afeea8f79a67795d2e532c111b0eda Author: Elichai Turkel Date: Mon Nov 30 12:20:13 2020 +0200 Update the dag json tests commit 5a3da43dd4c492120debabca643293ed5269a842 Author: tal Date: Sun Nov 29 12:03:37 2020 +0200 [NOD-1433] Remove unneccessry code. commit a6cde558ac8ff788b548da7ec695460cd680bb32 Author: tal Date: Mon Nov 23 17:05:56 2020 +0200 [NOD-1433] Change "Stage" sig function according to the new interface - added error as a return type. commit 07859b6218f503f13079640d1ab9139f9b63a51b Author: tal Date: Mon Nov 23 17:03:26 2020 +0200 [NOD-1433] Print formats changed & Cosmetics code changes. commit e1a851664ea69185a93cd189bb328f4cded07a8e Author: tal Date: Sun Nov 15 17:34:59 2020 +0200 [NOD-1433] Travers the tests dir and run each test. commit 4c7474edc16ce4553532f893c81f0c795a649b1c Author: tal Date: Mon Nov 9 12:44:53 2020 +0200 [NOD-1433] Travers the tests dir and run each test. commit 89dd1e61d36af077493f38d90d925e3057eb962a Author: tal Date: Mon Nov 9 11:48:36 2020 +0200 [NOD-1433] Change implementation to adjust genesis's score 0. Also, keep changing the test file to fit the new implementation. commit 6acdcd17def0bb29aca1f65c713d89d1e9960416 Author: tal Date: Sun Nov 8 17:07:22 2020 +0200 [NOD-1433] New test was added(Test 6). commit bf238893170e5b5ebc509d40937b410b22d8a9ff Author: tal Date: Sun Nov 8 14:59:36 2020 +0200 Fix golint errors commit 79ff990b5f04a5a80ccccd95ec3c6fb745e2ca41 Author: tal Date: Sun Nov 8 14:47:12 2020 +0200 added "Optimize imports". commit 73d0128f639517b27a01d016a14d67d7f1a42570 Author: tal Date: Sun Nov 8 13:03:22 2020 +0200 Added an implementation factory. commit 61ca8b2e7e20f0dbced5424028e6b52ea511d25c Author: tal Date: Thu Nov 5 16:03:18 2020 +0200 1. impl - choose the highest hash. 2. test - changed the test accordingly. commit ef0943ca29ad8699b2c50978cf94d28561bb3e10 Author: tal Date: Thu Oct 29 18:00:45 2020 +0200 Update Tests commit 6e5936abff9be604a0bd62329ec2d09be13c1d33 Author: tal Date: Tue Oct 27 10:22:45 2020 +0200 Change to the new API commit 5a70dc48b376994634586e0053a56f775b93f6b9 Author: tal Date: Mon Oct 26 18:35:31 2020 +0200 1. Added tests for ori commit 2b9f78353f671d2243fee36394618a59f3eb8d4c Author: tal Date: Mon Oct 26 13:04:37 2020 +0200 1. Added structure "isolatedTest" {k, test} 2. Added for loop on the tests. 3. New test - Test 5. commit c026d7b7a26348d0f2999a73cb9caefd3ada0ab1 Author: tal Date: Thu Oct 22 17:35:56 2020 +0300 Fix bugs in the GHOSTDAG : counters, conntains and isAncestorOf. Added more tests. commit 74493b27d21ed09195eaab164c0f3399312090b5 Author: tal Date: Thu Oct 22 16:49:27 2020 +0300 added compare between Hashes commit f689253463cb46cb5787067aade9c7c6545878bc Author: tal Date: Thu Oct 22 11:49:01 2020 +0300 added compare between Hashes commit 66be07f6168c8cde92ac68ebbafa45c7ab3484d9 Author: tal Date: Mon Oct 19 18:42:40 2020 +0300 First test - pass. commit 327f34f2dcb5567ef983a7d63e857688e5b8a395 Author: tal Date: Mon Oct 19 15:20:27 2020 +0300 Add alternative implementation for ghostdag. change all function's signatures (add error type) commit fd2ea3d84a4f21bed0f1e2a4c6eba549287bef46 Author: tal Date: Mon Oct 19 11:57:05 2020 +0300 add alternative implementation for ghostdag --- .../processes/ghostdag2/ghostdagimpl.go | 381 +++++++++++++++ .../ghostdagmanager/ghostdag_test.go | 273 +++++++++++ domain/consensus/testdata/dags/dag0.json | 252 ++++++++++ domain/consensus/testdata/dags/dag1.json | 436 ++++++++++++++++++ domain/consensus/testdata/dags/dag2.json | 126 +++++ 5 files changed, 1468 insertions(+) create mode 100644 domain/consensus/processes/ghostdag2/ghostdagimpl.go create mode 100644 domain/consensus/processes/ghostdagmanager/ghostdag_test.go create mode 100644 domain/consensus/testdata/dags/dag0.json create mode 100644 domain/consensus/testdata/dags/dag1.json create mode 100644 domain/consensus/testdata/dags/dag2.json diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go new file mode 100644 index 000000000..867f52a8e --- /dev/null +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -0,0 +1,381 @@ +package ghostdag2 + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "sort" +) + +type ghostdagHelper struct { + k model.KType + dataStore model.GHOSTDAGDataStore + dbAccess model.DBReader + dagTopologyManager model.DAGTopologyManager +} + +// New creates a new instance of this alternative ghostdag impl +func New( + databaseContext model.DBReader, + dagTopologyManager model.DAGTopologyManager, + ghostdagDataStore model.GHOSTDAGDataStore, + k model.KType) model.GHOSTDAGManager { + + return &ghostdagHelper{ + dbAccess: databaseContext, + dagTopologyManager: dagTopologyManager, + dataStore: ghostdagDataStore, + k: k, + } +} + +/* --------------------------------------------- */ + +func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error { + var maxNum uint64 = 0 + var myScore uint64 = 0 + /* find the selectedParent */ + blockParents, err := gh.dagTopologyManager.Parents(blockCandidate) + if err != nil { + return err + } + var selectedParent = blockParents[0] + for _, parent := range blockParents { + blockData, err := gh.dataStore.Get(gh.dbAccess, parent) + if err != nil { + return err + } + blockScore := blockData.BlueScore + if blockScore > maxNum { + selectedParent = parent + maxNum = blockScore + } + if blockScore == maxNum && ismoreHash(parent, selectedParent) { + selectedParent = parent + } + } + myScore = maxNum + + /* Goal: iterate blockCandidate's mergeSet and divide it to : blue, blues, reds. */ + var mergeSetBlues = make([]*externalapi.DomainHash, 0) + var mergeSetReds = make([]*externalapi.DomainHash, 0) + var blueSet = make([]*externalapi.DomainHash, 0) + + mergeSetBlues = append(mergeSetBlues, selectedParent) + + mergeSetArr, err := gh.findMergeSet(blockParents, selectedParent) + if err != nil { + return err + } + + err = gh.sortByBlueScore(mergeSetArr) + if err != nil { + return err + } + err = gh.findBlueSet(&blueSet, selectedParent) + if err != nil { + return err + } + + for _, mergeSetBlock := range mergeSetArr { + if *mergeSetBlock == *selectedParent { + if !contains(selectedParent, mergeSetBlues) { + mergeSetBlues = append(mergeSetBlues, selectedParent) + blueSet = append(blueSet, selectedParent) + } + continue + } + err := gh.divideBlueRed(selectedParent, mergeSetBlock, &mergeSetBlues, &mergeSetReds, &blueSet) + if err != nil { + return err + } + } + myScore += uint64(len(mergeSetBlues)) + + e := model.BlockGHOSTDAGData{ + BlueScore: myScore, + SelectedParent: selectedParent, + MergeSetBlues: mergeSetBlues, + MergeSetReds: mergeSetReds, + } + gh.dataStore.Stage(blockCandidate, &e) + return nil +} + +/* --------isMoreHash(w, selectedParent)----------------*/ +func ismoreHash(parent *externalapi.DomainHash, selectedParent *externalapi.DomainHash) bool { + //Check if parentHash is more then selectedParentHash + for i := len(parent) - 1; i >= 0; i-- { + switch { + case parent[i] < selectedParent[i]: + return false + case parent[i] > selectedParent[i]: + return true + } + } + return false +} + +/* 1. blue = selectedParent.blue + blues + 2. not connected to at most K blocks (from the blue group) + 3. for each block at blue , check if not destroy +*/ + +/* ---------------divideBluesReds--------------------- */ +func (gh *ghostdagHelper) divideBlueRed(selectedParent *externalapi.DomainHash, desiredBlock *externalapi.DomainHash, + blues *[]*externalapi.DomainHash, reds *[]*externalapi.DomainHash, blueSet *[]*externalapi.DomainHash) error { + var k = int(gh.k) + counter := 0 + + var suspectsBlues = make([]*externalapi.DomainHash, 0) + isMergeBlue := true + //check that not-connected to at most k. + for _, block := range *blueSet { + isAnticone, err := gh.isAnticone(block, desiredBlock) + if err != nil { + return err + } + if isAnticone { + counter++ + suspectsBlues = append(suspectsBlues, block) + } + if counter > k { + isMergeBlue = false + break + } + } + if !isMergeBlue { + if !contains(desiredBlock, *reds) { + *reds = append(*reds, desiredBlock) + } + return nil + } + + // check that the k-cluster of each blue is still valid. + for _, blue := range suspectsBlues { + isDestroyed, err := gh.checkIfDestroy(blue, blueSet) + if err != nil { + return err + } + if isDestroyed { + isMergeBlue = false + break + } + } + if !isMergeBlue { + if !contains(desiredBlock, *reds) { + *reds = append(*reds, desiredBlock) + } + return nil + } + if !contains(desiredBlock, *blues) { + *blues = append(*blues, desiredBlock) + } + if !contains(desiredBlock, *blueSet) { + *blueSet = append(*blueSet, desiredBlock) + } + return nil +} + +/* ---------------isAnticone-------------------------- */ +func (gh *ghostdagHelper) isAnticone(blockA, blockB *externalapi.DomainHash) (bool, error) { + isAAncestorOfAB, err := gh.dagTopologyManager.IsAncestorOf(blockA, blockB) + if err != nil { + return false, err + } + isBAncestorOfA, err := gh.dagTopologyManager.IsAncestorOf(blockB, blockA) + if err != nil { + return false, err + } + return !isAAncestorOfAB && !isBAncestorOfA, nil + +} + +/* ----------------validateKCluster------------------- */ +func (gh *ghostdagHelper) validateKCluster(chain *externalapi.DomainHash, checkedBlock *externalapi.DomainHash, counter *int, blueSet *[]*externalapi.DomainHash) (bool, error) { + var k = int(gh.k) + isAnticone, err := gh.isAnticone(chain, checkedBlock) + if err != nil { + return false, err + } + if isAnticone { + if *counter > k { + return false, nil + } + ifDestroy, err := gh.checkIfDestroy(chain, blueSet) + if err != nil { + return false, err + } + if ifDestroy { + return false, nil + } + *counter++ + return true, nil + } + isAncestorOf, err := gh.dagTopologyManager.IsAncestorOf(checkedBlock, chain) + if err != nil { + return false, err + } + if isAncestorOf { + dataStore, err := gh.BlockData(chain) + if err != nil { + return false, err + } + if mergeSetReds := dataStore.MergeSetReds; contains(checkedBlock, mergeSetReds) { + return false, nil + } + } else { + return true, nil + } + + return false, nil +} + +/*----------------contains-------------------------- */ +func contains(item *externalapi.DomainHash, items []*externalapi.DomainHash) bool { + for _, r := range items { + if *r == *item { + return true + } + } + return false +} + +/* ----------------checkIfDestroy------------------- */ +/* find number of not-connected in his blue*/ +func (gh *ghostdagHelper) checkIfDestroy(blockBlue *externalapi.DomainHash, blueSet *[]*externalapi.DomainHash) (bool, error) { + // Goal: check that the K-cluster of each block in the blueSet is not destroyed when adding the block to the mergeSet. + var k = int(gh.k) + counter := 0 + for _, blue := range *blueSet { + isAnticone, err := gh.isAnticone(blue, blockBlue) + if err != nil { + return true, err + } + if isAnticone { + counter++ + } + if counter > k { + return true, nil + } + } + return false, nil +} + +/* ----------------findMergeSet------------------- */ +func (gh *ghostdagHelper) findMergeSet(parents []*externalapi.DomainHash, selectedParent *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + + allMergeSet := make([]*externalapi.DomainHash, 0) + blockQueue := make([]*externalapi.DomainHash, 0) + for _, parent := range parents { + if !contains(parent, blockQueue) { + blockQueue = append(blockQueue, parent) + } + + } + for len(blockQueue) > 0 { + block := blockQueue[0] + blockQueue = blockQueue[1:] + if *selectedParent == *block { + if !contains(block, allMergeSet) { + allMergeSet = append(allMergeSet, block) + } + continue + } + isancestorOf, err := gh.dagTopologyManager.IsAncestorOf(block, selectedParent) + if err != nil { + return nil, err + } + if isancestorOf { + continue + } + if !contains(block, allMergeSet) { + allMergeSet = append(allMergeSet, block) + } + err = gh.insertParent(block, &blockQueue) + if err != nil { + return nil, err + } + + } + return allMergeSet, nil +} + +/* ----------------insertParent------------------- */ +/* Insert all parents to the queue*/ +func (gh *ghostdagHelper) insertParent(child *externalapi.DomainHash, queue *[]*externalapi.DomainHash) error { + parents, err := gh.dagTopologyManager.Parents(child) + if err != nil { + return err + } + for _, parent := range parents { + if contains(parent, *queue) { + continue + } + *queue = append(*queue, parent) + } + return nil +} + +/* ----------------findBlueSet------------------- */ +func (gh *ghostdagHelper) findBlueSet(blueSet *[]*externalapi.DomainHash, selectedParent *externalapi.DomainHash) error { + for selectedParent != nil { + if !contains(selectedParent, *blueSet) { + *blueSet = append(*blueSet, selectedParent) + } + blockData, err := gh.dataStore.Get(gh.dbAccess, selectedParent) + if err != nil { + return err + } + mergeSetBlue := blockData.MergeSetBlues + for _, blue := range mergeSetBlue { + if contains(blue, *blueSet) { + continue + } + *blueSet = append(*blueSet, blue) + } + selectedParent = blockData.SelectedParent + } + return nil +} + +/* ----------------sortByBlueScore------------------- */ +func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error { + + var err error = nil + sort.Slice(arr, func(i, j int) bool { + + blockLeft, error := gh.dataStore.Get(gh.dbAccess, arr[i]) + if error != nil { + err = error + return false + } + + blockRight, error := gh.dataStore.Get(gh.dbAccess, arr[j]) + if error != nil { + err = error + return false + } + + if blockLeft.BlueScore < blockRight.BlueScore { + return true + } + if blockLeft.BlueScore == blockRight.BlueScore { + return ismoreHash(arr[j], arr[i]) + } + return false + }) + return err +} + +/* --------------------------------------------- */ + +func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { + return gh.dataStore.Get(gh.dbAccess, blockHash) +} +func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) { + panic("implement me") +} + +func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { + panic("implement me") +} diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go new file mode 100644 index 000000000..bd01b100e --- /dev/null +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -0,0 +1,273 @@ +package ghostdagmanager + +import ( + "encoding/json" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" + "os" + "path/filepath" + "reflect" + "testing" +) + +// TestGHOSTDAG iterates over several dag simulations, and checks +// that the blue score, blue set and selected parent of each +// block are calculated as expected. +func TestGHOSTDAG(t *testing.T) { + + type block struct { + ID string `json:"ID"` + Score uint64 `json:"ExpectedScore"` + SelectedParent string `json:"ExpectedSelectedParent"` + MergeSetReds []string `json:"ExpectedReds"` + MergeSetBlues []string `json:"ExpectedBlues"` + Parents []string `json:"Parents"` + } + + // json struct: + type testDag struct { + K model.KType `json:"K"` + GenesisID string `json:"GenesisID"` + ExpectedMergeSetReds []string `json:"ExpectedReds"` + Blocks []block `json:"Blocks"` + } + + type implManager struct { + function func( + databaseContext model.DBReader, + dagTopologyManager model.DAGTopologyManager, + ghostdagDataStore model.GHOSTDAGDataStore, + k model.KType) model.GHOSTDAGManager + implName string + } + + dagTopology := &DAGTopologyManagerImpl{ + parentsMap: make(map[externalapi.DomainHash][]*externalapi.DomainHash), + } + + ghostdagDataStore := &GHOSTDAGDataStoreImpl{ + dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), + } + var blockGHOSTDAGDataGenesis = &model.BlockGHOSTDAGData{ + BlueScore: 0, + SelectedParent: nil, + MergeSetBlues: nil, + MergeSetReds: nil, + BluesAnticoneSizes: nil, + } + + var testsCounter int + err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + jsonFile, err := os.Open(path) + if err != nil { + t.Fatalf("TestGHOSTDAG : failed opening the json file %s: %v", info.Name(), err) + } + defer jsonFile.Close() + var test testDag + decoder := json.NewDecoder(jsonFile) + decoder.DisallowUnknownFields() + err = decoder.Decode(&test) + if err != nil { + t.Fatalf("TestGHOSTDAG:failed decoding json: %v", err) + } + + var genesisHash externalapi.DomainHash + copy(genesisHash[:], test.GenesisID) + + dagTopology.parentsMap[genesisHash] = nil + + ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis + + //NOTE: FOR ADDING/REMOVING AN IMPLEMENTATION CHANGE BELOW: + implementationFactories := []implManager{ + {New, "Original"}, + {ghostdag2.New, "Tal's impl"}, + } + + for _, factory := range implementationFactories { + + g := factory.function(nil, dagTopology, ghostdagDataStore, model.KType(test.K)) + for _, testBlockData := range test.Blocks { + + blockID := StringToByte(testBlockData.ID) + dagTopology.parentsMap[*blockID] = StringToByteArray(testBlockData.Parents) + + err := g.GHOSTDAG(blockID) + if err != nil { + t.Fatalf("Test failed: \n Impl: %s,FileName: %s \n error on GHOSTDAG - block %s: %s.", + factory.implName, info.Name(), testBlockData.ID, err) + } + ghostdagData, err := ghostdagDataStore.Get(nil, blockID) + if err != nil { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: ghostdagDataStore error: %v.", + factory.implName, info.Name(), testBlockData.ID, err) + } + + if testBlockData.Score != (ghostdagData.BlueScore) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue score %d but got %d.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore) + } + + if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, string(ghostdagData.SelectedParent[:])) + } + + if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues)) + } + + if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds)) + } + + } + dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash) + dagTopology.parentsMap[genesisHash] = nil + ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) + ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis + } + + testsCounter++ + return nil + }) + if err != nil { + t.Fatal(err) + } + if testsCounter != 3 { + t.Fatalf("Expected 3 test files, ran %d instead", testsCounter) + } +} + +func hashesToStrings(arr []*externalapi.DomainHash) []string { + var strArr = make([]string, len(arr)) + for i, hash := range arr { + strArr[i] = string(hash[:]) + } + return strArr +} + +func StringToByte(strID string) *externalapi.DomainHash { + var domainHash externalapi.DomainHash + copy(domainHash[:], strID) + return &domainHash +} + +func StringToByteArray(stringIDArr []string) []*externalapi.DomainHash { + domainHashArr := make([]*externalapi.DomainHash, len(stringIDArr)) + for i, strID := range stringIDArr { + domainHashArr[i] = StringToByte(strID) + } + return domainHashArr +} + +/* ---------------------- */ +type GHOSTDAGDataStoreImpl struct { + dagMap map[externalapi.DomainHash]*model.BlockGHOSTDAGData +} + +func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { + ds.dagMap[*blockHash] = blockGHOSTDAGData +} + +func (ds *GHOSTDAGDataStoreImpl) IsStaged() bool { + panic("implement me") +} + +func (ds *GHOSTDAGDataStoreImpl) Discard() { + panic("implement me") +} + +func (ds *GHOSTDAGDataStoreImpl) Commit(dbTx model.DBTransaction) error { + panic("implement me") +} + +func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { + v, ok := ds.dagMap[*blockHash] + if ok { + return v, nil + } + return nil, nil +} + +type DAGTopologyManagerImpl struct { + parentsMap map[externalapi.DomainHash][]*externalapi.DomainHash +} + +func (dt *DAGTopologyManagerImpl) Tips() ([]*externalapi.DomainHash, error) { + panic("implement me") +} + +func (dt *DAGTopologyManagerImpl) AddTip(tipHash *externalapi.DomainHash) error { + panic("implement me") +} + +func (dt *DAGTopologyManagerImpl) Parents(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + v, ok := dt.parentsMap[*blockHash] + if !ok { + return []*externalapi.DomainHash{}, nil + } + + return v, nil +} + +func (dt *DAGTopologyManagerImpl) Children(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + panic("unimplemented") +} + +func (dt *DAGTopologyManagerImpl) IsParentOf(hashBlockA *externalapi.DomainHash, hashBlockB *externalapi.DomainHash) (bool, error) { + panic("unimplemented") +} + +func (dt *DAGTopologyManagerImpl) IsChildOf(hashBlockA *externalapi.DomainHash, hashBlockB *externalapi.DomainHash) (bool, error) { + panic("unimplemented") +} + +func (dt *DAGTopologyManagerImpl) IsAncestorOf(hashBlockA *externalapi.DomainHash, hashBlockB *externalapi.DomainHash) (bool, error) { + blockBParents, isOk := dt.parentsMap[*hashBlockB] + if !isOk { + return false, nil + } + + for _, parentOfB := range blockBParents { + if *parentOfB == *hashBlockA { + return true, nil + } + } + + for _, parentOfB := range blockBParents { + isAncestorOf, err := dt.IsAncestorOf(hashBlockA, parentOfB) + if err != nil { + return false, err + } + if isAncestorOf { + return true, nil + } + } + return false, nil + +} + +func (dt *DAGTopologyManagerImpl) IsDescendantOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { + panic("unimplemented") +} + +func (dt *DAGTopologyManagerImpl) IsAncestorOfAny(blockHash *externalapi.DomainHash, potentialDescendants []*externalapi.DomainHash) (bool, error) { + panic("unimplemented") +} +func (dt *DAGTopologyManagerImpl) IsInSelectedParentChainOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { + panic("unimplemented") +} + +func (dt *DAGTopologyManagerImpl) SetParents(blockHash *externalapi.DomainHash, parentHashes []*externalapi.DomainHash) error { + panic("unimplemented") +} diff --git a/domain/consensus/testdata/dags/dag0.json b/domain/consensus/testdata/dags/dag0.json new file mode 100644 index 000000000..8c36f23b4 --- /dev/null +++ b/domain/consensus/testdata/dags/dag0.json @@ -0,0 +1,252 @@ +{ + "K": 4, + "GenesisID": "A", + "ExpectedReds": [ + "Q", + "H", + "I" + ], + "Blocks": [ + { + "ID": "B", + "ExpectedScore": 1, + "ExpectedSelectedParent": "A", + "ExpectedReds": [], + "ExpectedBlues": [ + "A" + ], + "Parents": [ + "A" + ] + }, + { + "ID": "C", + "ExpectedScore": 2, + "ExpectedSelectedParent": "B", + "ExpectedReds": [], + "ExpectedBlues": [ + "B" + ], + "Parents": [ + "B" + ] + }, + { + "ID": "D", + "ExpectedScore": 1, + "ExpectedSelectedParent": "A", + "ExpectedReds": [], + "ExpectedBlues": [ + "A" + ], + "Parents": [ + "A" + ] + }, + { + "ID": "E", + "ExpectedScore": 4, + "ExpectedSelectedParent": "C", + "ExpectedReds": [], + "ExpectedBlues": [ + "C", + "D" + ], + "Parents": [ + "C", + "D" + ] + }, + { + "ID": "F", + "ExpectedScore": 1, + "ExpectedSelectedParent": "A", + "ExpectedReds": [], + "ExpectedBlues": [ + "A" + ], + "Parents": [ + "A" + ] + }, + { + "ID": "G", + "ExpectedScore": 2, + "ExpectedSelectedParent": "F", + "ExpectedReds": [], + "ExpectedBlues": [ + "F" + ], + "Parents": [ + "F" + ] + }, + { + "ID": "H", + "ExpectedScore": 1, + "ExpectedSelectedParent": "A", + "ExpectedReds": [], + "ExpectedBlues": [ + "A" + ], + "Parents": [ + "A" + ] + }, + { + "ID": "I", + "ExpectedScore": 1, + "ExpectedSelectedParent": "A", + "ExpectedReds": [], + "ExpectedBlues": [ + "A" + ], + "Parents": [ + "A" + ] + }, + { + "ID": "J", + "ExpectedScore": 7, + "ExpectedSelectedParent": "E", + "ExpectedReds": [], + "ExpectedBlues": [ + "E", + "F", + "G" + ], + "Parents": [ + "E", + "G" + ] + }, + { + "ID": "K", + "ExpectedScore": 8, + "ExpectedSelectedParent": "J", + "ExpectedReds": [], + "ExpectedBlues": [ + "J" + ], + "Parents": [ + "J" + ] + }, + { + "ID": "L", + "ExpectedScore": 9, + "ExpectedSelectedParent": "K", + "ExpectedReds": ["I"], + "ExpectedBlues": [ + "K" + ], + "Parents": [ + "I", + "K" + ] + }, + { + "ID": "M", + "ExpectedScore": 10, + "ExpectedSelectedParent": "L", + "ExpectedReds": [], + "ExpectedBlues": [ + "L" + ], + "Parents": [ + "L" + ] + }, + { + "ID": "N", + "ExpectedScore": 11, + "ExpectedSelectedParent": "M", + "ExpectedReds": [], + "ExpectedBlues": [ + "M" + ], + "Parents": [ + "M" + ] + }, + { + "ID": "O", + "ExpectedScore": 11, + "ExpectedSelectedParent": "M", + "ExpectedReds": [], + "ExpectedBlues": [ + "M" + ], + "Parents": [ + "M" + ] + }, + { + "ID": "2", + "ExpectedScore": 11, + "ExpectedSelectedParent": "M", + "ExpectedReds": [], + "ExpectedBlues": [ + "M" + ], + "Parents": [ + "M" + ] + }, + { + "ID": "Q", + "ExpectedScore": 11, + "ExpectedSelectedParent": "M", + "ExpectedReds": [], + "ExpectedBlues": [ + "M" + ], + "Parents": [ + "M" + ] + }, + { + "ID": "R", + "ExpectedScore": 11, + "ExpectedSelectedParent": "M", + "ExpectedReds": [], + "ExpectedBlues": [ + "M" + ], + "Parents": [ + "M" + ] + }, + { + "ID": "S", + "ExpectedScore": 12, + "ExpectedSelectedParent": "R", + "ExpectedReds": [], + "ExpectedBlues": [ + "R" + ], + "Parents": [ + "R" + ] + }, + { + "ID": "T", + "ExpectedScore": 16, + "ExpectedSelectedParent": "S", + "ExpectedReds": ["Q"], + "ExpectedBlues": [ + "S", + "2", + "N", + "O" + ], + "Parents": [ + "N", + "O", + "2", + "Q", + "S" + ] + } + ] +} diff --git a/domain/consensus/testdata/dags/dag1.json b/domain/consensus/testdata/dags/dag1.json new file mode 100644 index 000000000..d751b3c00 --- /dev/null +++ b/domain/consensus/testdata/dags/dag1.json @@ -0,0 +1,436 @@ +{ + "K": 4, + "GenesisID": "0", + "Blocks": [ + { + "ID": "1111", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "2", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "3", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "4", + "ExpectedScore": 2, + "ExpectedSelectedParent": "1111", + "ExpectedReds": [], + "ExpectedBlues": [ + "1111" + ], + "Parents": [ + "1111" + ] + }, + { + "ID": "5", + "ExpectedScore": 3, + "ExpectedSelectedParent": "3", + "ExpectedReds": [], + "ExpectedBlues": [ + "3", + "2" + ], + "Parents": [ + "2", + "3" + ] + }, + { + "ID": "6", + "ExpectedScore": 2, + "ExpectedSelectedParent": "3", + "ExpectedReds": [], + "ExpectedBlues": [ + "3" + ], + "Parents": [ + "3" + ] + }, + { + "ID": "7", + "ExpectedScore": 3, + "ExpectedSelectedParent": "6", + "ExpectedReds": [], + "ExpectedBlues": [ + "6" + ], + "Parents": [ + "6" + ] + }, + { + "ID": "8", + "ExpectedScore": 3, + "ExpectedSelectedParent": "1111", + "ExpectedReds": [], + "ExpectedBlues": [ + "1111", + "2" + ], + "Parents": [ + "1111", + "2" + ] + }, + { + "ID": "9", + "ExpectedScore": 5, + "ExpectedSelectedParent": "5", + "ExpectedReds": [], + "ExpectedBlues": [ + "5", + "6" + ], + "Parents": [ + "5", + "6" + ] + }, + { + "ID": "10", + "ExpectedScore": 5, + "ExpectedSelectedParent": "8", + "ExpectedReds": [], + "ExpectedBlues": [ + "8", + "4" + ], + "Parents": [ + "8", + "4" + ] + }, + { + "ID": "11", + "ExpectedScore": 7, + "ExpectedSelectedParent": "9", + "ExpectedReds": [], + "ExpectedBlues": [ + "9", + "7" + ], + "Parents": [ + "7", + "9" + ] + }, + { + "ID": "12", + "ExpectedScore": 8, + "ExpectedSelectedParent": "10", + "ExpectedReds": [ + "3", + "6" + ], + "ExpectedBlues": [ + "10", + "5", + "9" + ], + "Parents": [ + "10", + "9" + ] + }, + { + "ID": "13", + "ExpectedScore": 6, + "ExpectedSelectedParent": "8", + "ExpectedReds": [], + "ExpectedBlues": [ + "8", + "3", + "5" + ], + "Parents": [ + "5", + "8" + ] + }, + { + "ID": "14", + "ExpectedScore": 8, + "ExpectedSelectedParent": "13", + "ExpectedReds": [ + "4" + ], + "ExpectedBlues": [ + "13", + "10" + ], + "Parents": [ + "13", + "10" + ] + }, + { + "ID": "15", + "ExpectedScore": 9, + "ExpectedSelectedParent": "11", + "ExpectedReds": [ + "1111", + "8" + ], + "ExpectedBlues": [ + "11", + "13" + ], + "Parents": [ + "11", + "13" + ] + }, + { + "ID": "16", + "ExpectedScore": 8, + "ExpectedSelectedParent": "11", + "ExpectedReds": [], + "ExpectedBlues": [ + "11" + ], + "Parents": [ + "11" + ] + }, + { + "ID": "17", + "ExpectedScore": 9, + "ExpectedSelectedParent": "14", + "ExpectedReds": [], + "ExpectedBlues": [ + "14" + ], + "Parents": [ + "14" + ] + }, + { + "ID": "18", + "ExpectedScore": 7, + "ExpectedSelectedParent": "13", + "ExpectedReds": [], + "ExpectedBlues": [ + "13" + ], + "Parents": [ + "13" + ] + }, + { + "ID": "19", + "ExpectedScore": 10, + "ExpectedSelectedParent": "15", + "ExpectedReds": [ + "18" + ], + "ExpectedBlues": [ + "15" + ], + "Parents": [ + "18", + "15" + ] + }, + { + "ID": "20", + "ExpectedScore": 10, + "ExpectedSelectedParent": "17", + "ExpectedReds": [ + "6", + "7", + "9", + "11", + "16" + ], + "ExpectedBlues": [ + "17" + ], + "Parents": [ + "16", + "17" + ] + }, + { + "ID": "21", + "ExpectedScore": 12, + "ExpectedSelectedParent": "20", + "ExpectedReds": [], + "ExpectedBlues": [ + "20", + "18" + ], + "Parents": [ + "18", + "20" + ] + }, + { + "ID": "22", + "ExpectedScore": 13, + "ExpectedSelectedParent": "21", + "ExpectedReds": [ + "15", + "19" + ], + "ExpectedBlues": [ + "21" + ], + "Parents": [ + "19", + "21" + ] + }, + { + "ID": "23", + "ExpectedScore": 11, + "ExpectedSelectedParent": "17", + "ExpectedReds": [ + "6", + "9" + ], + "ExpectedBlues": [ + "17", + "12" + ], + "Parents": [ + "12", + "17" + ] + }, + { + "ID": "24", + "ExpectedScore": 13, + "ExpectedSelectedParent": "23", + "ExpectedReds": [ + "7", + "11", + "16" + ], + "ExpectedBlues": [ + "23", + "20" + ], + "Parents": [ + "20", + "23" + ] + }, + { + "ID": "25555", + "ExpectedScore": 13, + "ExpectedSelectedParent": "21", + "ExpectedReds": [], + "ExpectedBlues": [ + "21" + ], + "Parents": [ + "21" + ] + }, + { + "ID": "26", + "ExpectedScore": 15, + "ExpectedSelectedParent": "25555", + "ExpectedReds": [ + "12", + "15", + "19", + "23", + "24" + ], + "ExpectedBlues": [ + "25555", + "22" + ], + "Parents": [ + "22", + "24", + "25555" + ] + }, + { + "ID": "27", + "ExpectedScore": 9, + "ExpectedSelectedParent": "16", + "ExpectedReds": [], + "ExpectedBlues": [ + "16" + ], + "Parents": [ + "16" + ] + }, + { + "ID": "28", + "ExpectedScore": 14, + "ExpectedSelectedParent": "25555", + "ExpectedReds": [ + "12", + "23" + ], + "ExpectedBlues": [ + "25555" + ], + "Parents": [ + "23", + "25555" + ] + }, + { + "ID": "29", + "ExpectedScore": 17, + "ExpectedSelectedParent": "26", + "ExpectedReds": [], + "ExpectedBlues": [ + "26", + "28" + ], + "Parents": [ + "26", + "28" + ] + }, + { + "ID": "30", + "ExpectedScore": 10, + "ExpectedSelectedParent": "27", + "ExpectedReds": [], + "ExpectedBlues": [ + "27" + ], + "Parents": [ + "27" + ] + } + ] +} diff --git a/domain/consensus/testdata/dags/dag2.json b/domain/consensus/testdata/dags/dag2.json new file mode 100644 index 000000000..1be478e7f --- /dev/null +++ b/domain/consensus/testdata/dags/dag2.json @@ -0,0 +1,126 @@ +{ + "K": 18, + "GenesisID": "786", + "ExpectedReds": [], + "Blocks": [ + { + "ID": "21d", + "ExpectedScore": 1, + "ExpectedSelectedParent": "786", + "ExpectedReds": [], + "ExpectedBlues": [ + "786" + ], + "Parents": [ + "786" + ] + }, + { + "ID": "6ef", + "ExpectedScore": 2, + "ExpectedSelectedParent": "21d", + "ExpectedReds": [], + "ExpectedBlues": [ + "21d" + ], + "Parents": [ + "21d" + ] + }, + { + "ID": "c98", + "ExpectedScore": 3, + "ExpectedSelectedParent": "6ef", + "ExpectedReds": [], + "ExpectedBlues": [ + "6ef" + ], + "Parents": [ + "6ef" + ] + }, + { + "ID": "d1c", + "ExpectedScore": 1, + "ExpectedSelectedParent": "786", + "ExpectedReds": [], + "ExpectedBlues": [ + "786" + ], + "Parents": [ + "786" + ] + }, + { + "ID": "ec9", + "ExpectedScore": 5, + "ExpectedSelectedParent": "c98", + "ExpectedReds": [], + "ExpectedBlues": [ + "c98", + "d1c" + ], + "Parents": [ + "d1c", + "c98" + ] + }, + { + "ID": "f154", + "ExpectedScore": 1, + "ExpectedSelectedParent": "786", + "ExpectedReds": [], + "ExpectedBlues": [ + "786" + ], + "Parents": [ + "786" + ] + }, + { + "ID": "6c7", + "ExpectedScore": 4, + "ExpectedSelectedParent": "f154", + "ExpectedReds": [], + "ExpectedBlues": [ + "f154", + "d1c", + "21d" + ], + "Parents": [ + "d1c", + "21d", + "f154" + ] + }, + { + "ID": "015", + "ExpectedScore": 8, + "ExpectedSelectedParent": "ec9", + "ExpectedReds": [], + "ExpectedBlues": [ + "ec9", + "f154", + "6c7" + ], + "Parents": [ + "ec9", + "6c7" + ] + }, + { + "ID": "crash", + "ExpectedScore": 6, + "ExpectedSelectedParent": "6c7", + "ExpectedReds": [], + "ExpectedBlues": [ + "6c7", + "6ef" + ], + "Parents": [ + "6ef", + "6c7" + ] + } + ] +} From 9756d64f28453d84169fe9228bdc253dfac57479 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 2 Dec 2020 03:05:33 -0800 Subject: [PATCH 104/351] [NOD-1582] Fix orphan resolution (#1169) * [NOD-1582] Fix multiple request per missing ancestor * [NOD-1582] Don't remove peer on routerpkg.ErrRouteClosed from RPC * [NOD-1582] Use LogAndMeasureExecutionTime where possible --- app/protocol/flowcontext/blocks.go | 7 ++++ .../flows/blockrelay/handle_relay_invs.go | 39 +++++++++++++------ .../flows/handshake/receiveversion.go | 6 +++ app/protocol/flows/handshake/sendversion.go | 6 +++ app/rpc/rpccontext/notificationmanager.go | 4 +- .../server/grpcserver/grpc_connection.go | 1 - .../network/netadapter/standalone/routes.go | 5 --- 7 files changed, 50 insertions(+), 18 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index b5361a26f..28aba09ef 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -17,18 +17,25 @@ import ( // relays newly unorphaned transactions and possibly rebroadcast // manually added transactions when not in IBD. func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { + hash := consensusserialization.BlockHash(block) + log.Debugf("OnNewBlock start for block %s", hash) + defer log.Debugf("OnNewBlock end for block %s", hash) unorphanedBlocks, err := f.UnorphanBlocks(block) if err != nil { return err } + log.Debugf("OnNewBlock: block %s unorphaned %d blocks", hash, len(unorphanedBlocks)) + newBlocks := append([]*externalapi.DomainBlock{block}, unorphanedBlocks...) for _, newBlock := range newBlocks { blocklogger.LogBlock(block) + log.Tracef("OnNewBlock: passing block %s transactions to mining manager", hash) _ = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) if f.onBlockAddedToDAGHandler != nil { + log.Tracef("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash) err := f.onBlockAddedToDAGHandler(newBlock) if err != nil { return err diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index ed354f149..8cb17c35c 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -10,6 +10,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" mathUtil "github.com/kaspanet/kaspad/util/math" @@ -53,6 +54,7 @@ func HandleRelayInvs(context RelayInvsContext, incomingRoute *router.Route, outg func (flow *handleRelayInvsFlow) start() error { for { + log.Debugf("Waiting for inv") inv, err := flow.readInv() if err != nil { return err @@ -69,10 +71,12 @@ func (flow *handleRelayInvsFlow) start() error { return protocolerrors.Errorf(true, "sent inv of an invalid block %s", inv.Hash) } + log.Debugf("Block %s already exists. continuing...", inv.Hash) continue } if flow.IsOrphan(inv.Hash) { + log.Debugf("Block %s is a known orphan. continuing...", inv.Hash) continue } @@ -81,6 +85,7 @@ func (flow *handleRelayInvsFlow) start() error { return err } if flow.IsInIBD() { + log.Debugf("Got block %s while in IBD. continuing...", inv.Hash) // Block relay is disabled during IBD continue } @@ -118,10 +123,13 @@ func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) } func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "handleRelayInvsFlow.requestBlocks") + defer onEnd() + numHashesToRequest := mathUtil.MinInt(appmessage.MaxRequestRelayBlocksHashes, requestQueue.len()) hashesToRequest := requestQueue.dequeue(numHashesToRequest) - pendingBlocks := map[externalapi.DomainHash]struct{}{} + requestedBlocksSet := map[externalapi.DomainHash]struct{}{} var filteredHashesToRequest []*externalapi.DomainHash for _, hash := range hashesToRequest { exists := flow.SharedRequestedBlocks().addIfNotExists(hash) @@ -138,18 +146,19 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err continue } - pendingBlocks[*hash] = struct{}{} + requestedBlocksSet[*hash] = struct{}{} filteredHashesToRequest = append(filteredHashesToRequest, hash) } // Exit early if we've filtered out all the hashes if len(filteredHashesToRequest) == 0 { + log.Debugf("requestBlocks - no hashes to request. Returning..") return nil } - // In case the function returns earlier than expected, we want to make sure requestedBlocks is + // In case the function returns earlier than expected, we want to make sure flow.SharedRequestedBlocks() is // clean from any pending blocks. - defer flow.SharedRequestedBlocks().removeSet(pendingBlocks) + defer flow.SharedRequestedBlocks().removeSet(requestedBlocksSet) getRelayBlocksMsg := appmessage.NewMsgRequestRelayBlocks(filteredHashesToRequest) err := flow.outgoingRoute.Enqueue(getRelayBlocksMsg) @@ -157,7 +166,8 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err return err } - for len(pendingBlocks) > 0 { + for _, expectedHash := range filteredHashesToRequest { + log.Debugf("Waiting for block %s", expectedHash) msgBlock, err := flow.readMsgBlock() if err != nil { return err @@ -165,17 +175,17 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err block := appmessage.MsgBlockToDomainBlock(msgBlock) blockHash := consensusserialization.BlockHash(block) + log.Criticalf("got block %s", blockHash) - if _, ok := pendingBlocks[*blockHash]; !ok { - return protocolerrors.Errorf(true, "got unrequested block %s", blockHash) + if *blockHash != *expectedHash { + return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash) } - err = flow.processAndRelayBlock(requestQueue, block) + err = flow.processAndRelayBlock(requestQueue, requestedBlocksSet, block) if err != nil { return err } - delete(pendingBlocks, *blockHash) flow.SharedRequestedBlocks().remove(blockHash) } return nil @@ -202,8 +212,11 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock, } } -func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueSet, block *externalapi.DomainBlock) error { +func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueSet, requestedBlocksSet map[externalapi.DomainHash]struct{}, block *externalapi.DomainBlock) error { blockHash := consensusserialization.BlockHash(block) + log.Debugf("processAndRelayBlock start for block %s", blockHash) + defer log.Debugf("processAndRelayBlock end for block %s", blockHash) + err := flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { if !errors.As(err, &ruleerrors.RuleError{}) { @@ -240,6 +253,10 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS // Request the parents for the orphan block from the peer that sent it. for _, missingAncestor := range missingParentsError.MissingParentHashes { + if _, ok := requestedBlocksSet[*missingAncestor]; ok { + log.Debugf("ancestor %s already exists in requestedBlocksSet", missingAncestor) + continue + } requestQueue.enqueueIfNotExists(missingAncestor) } return nil @@ -254,7 +271,7 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS return err } - log.Infof("Accepted block %s via relay", blockHash) + log.Debugf("Accepted block %s via relay", blockHash) err = flow.StartIBDIfRequired() if err != nil { diff --git a/app/protocol/flows/handshake/receiveversion.go b/app/protocol/flows/handshake/receiveversion.go index 755e1db0c..b0191b9b7 100644 --- a/app/protocol/flows/handshake/receiveversion.go +++ b/app/protocol/flows/handshake/receiveversion.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -41,11 +42,16 @@ func ReceiveVersion(context HandleHandshakeContext, incomingRoute *router.Route, } func (flow *receiveVersionFlow) start() (*appmessage.NetAddress, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "receiveVersionFlow.start()") + defer onEnd() + message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) if err != nil { return nil, err } + log.Debugf("Got version message") + msgVersion, ok := message.(*appmessage.MsgVersion) if !ok { return nil, protocolerrors.New(true, "a version message must precede all others") diff --git a/app/protocol/flows/handshake/sendversion.go b/app/protocol/flows/handshake/sendversion.go index e037dc377..7d5f04774 100644 --- a/app/protocol/flows/handshake/sendversion.go +++ b/app/protocol/flows/handshake/sendversion.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/version" ) @@ -48,6 +49,9 @@ func SendVersion(context HandleHandshakeContext, incomingRoute *router.Route, } func (flow *sendVersionFlow) start() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "sendVersionFlow.start") + defer onEnd() + virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent() if err != nil { return err @@ -76,9 +80,11 @@ func (flow *sendVersionFlow) start() error { } // Wait for verack + log.Debugf("Waiting for verack") _, err = flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) if err != nil { return err } + log.Debugf("Got verack") return nil } diff --git a/app/rpc/rpccontext/notificationmanager.go b/app/rpc/rpccontext/notificationmanager.go index 2a6ed51fb..f3f3adb4c 100644 --- a/app/rpc/rpccontext/notificationmanager.go +++ b/app/rpc/rpccontext/notificationmanager.go @@ -65,7 +65,9 @@ func (nm *NotificationManager) NotifyBlockAdded(notification *appmessage.BlockAd for router, listener := range nm.listeners { if listener.propagateBlockAddedNotifications { err := router.OutgoingRoute().Enqueue(notification) - if err != nil { + if errors.Is(err, routerpkg.ErrRouteClosed) { + log.Warnf("Couldn't send notification: %s", err) + } else if err != nil { return err } } diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go b/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go index 19bee44a8..dc57d40d0 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_connection.go @@ -27,7 +27,6 @@ type gRPCConnection struct { streamLock sync.RWMutex stopChan chan struct{} - clientConn grpc.ClientConn onDisconnectedHandler server.OnDisconnectedHandler onInvalidMessageHandler server.OnInvalidMessageHandler diff --git a/infrastructure/network/netadapter/standalone/routes.go b/infrastructure/network/netadapter/standalone/routes.go index 0f1dc830a..fe277d2f8 100644 --- a/infrastructure/network/netadapter/standalone/routes.go +++ b/infrastructure/network/netadapter/standalone/routes.go @@ -62,8 +62,3 @@ func (r *Routes) WaitForDisconnect(timeout time.Duration) error { } } } - -// Disconnect closes the connection behind the routes, thus closing all routes -func (r *Routes) Disconnect() { - r.netConnection.Disconnect() -} From ab3c81c552cb9a835ece3f34434ff9f7d598267d Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Wed, 2 Dec 2020 11:55:33 +0200 Subject: [PATCH 105/351] [NOD-1583] Move all TestXXX interfaces to testapi --- .../model/interface_processes_blockbuilder.go | 10 ---------- .../interface_processes_consensusstatemanager.go | 9 --------- .../interface_processes_reachabilitytree.go | 8 -------- .../interface_processes_transactionvalidator.go | 8 -------- .../model/testapi/test_block_builder.go | 16 ++++++++++++++++ domain/consensus/model/testapi/test_consensus.go | 8 ++++---- .../testapi/test_consensus_state_manager.go | 15 +++++++++++++++ .../model/testapi/test_reachability_manager.go | 11 +++++++++++ .../model/testapi/test_transaction_validator.go | 13 +++++++++++++ .../processes/blockbuilder/test_block_builder.go | 2 +- .../test_consensus_state_manager.go | 3 ++- .../test_reachabilitymanager.go | 7 +++++-- .../test_transaction_validator.go | 3 ++- domain/consensus/test_consensus.go | 9 +++++---- domain/consensus/test_consensus_getters.go | 9 +++++---- 15 files changed, 79 insertions(+), 52 deletions(-) create mode 100644 domain/consensus/model/testapi/test_block_builder.go create mode 100644 domain/consensus/model/testapi/test_consensus_state_manager.go create mode 100644 domain/consensus/model/testapi/test_reachability_manager.go create mode 100644 domain/consensus/model/testapi/test_transaction_validator.go diff --git a/domain/consensus/model/interface_processes_blockbuilder.go b/domain/consensus/model/interface_processes_blockbuilder.go index 59c7bf60a..f8c23bac5 100644 --- a/domain/consensus/model/interface_processes_blockbuilder.go +++ b/domain/consensus/model/interface_processes_blockbuilder.go @@ -6,13 +6,3 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type BlockBuilder interface { BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) } - -// TestBlockBuilder adds to the main BlockBuilder methods required by tests -type TestBlockBuilder interface { - BlockBuilder - - // BuildBlockWithParents builds a block with provided parents, coinbaseData and transactions, - // and returns the block together with its past UTXO-diff from the virtual. - BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *UTXODiff, error) -} diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 96105d5c7..5f4dc783e 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -11,12 +11,3 @@ type ConsensusStateManager interface { HeaderTipsPruningPoint() (*externalapi.DomainHash, error) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (*UTXODiff, AcceptanceData, Multiset, error) } - -// TestConsensusStateManager adds to the main ConsensusStateManager methods required by tests -type TestConsensusStateManager interface { - ConsensusStateManager - AddUTXOToMultiset(multiset Multiset, entry *externalapi.UTXOEntry, - outpoint *externalapi.DomainOutpoint) error - ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) - VirtualFinalityPoint() (*externalapi.DomainHash, error) -} diff --git a/domain/consensus/model/interface_processes_reachabilitytree.go b/domain/consensus/model/interface_processes_reachabilitytree.go index f151d08c1..47284dae6 100644 --- a/domain/consensus/model/interface_processes_reachabilitytree.go +++ b/domain/consensus/model/interface_processes_reachabilitytree.go @@ -10,11 +10,3 @@ type ReachabilityManager interface { IsDAGAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) UpdateReindexRoot(selectedTip *externalapi.DomainHash) error } - -// TestReachabilityManager adds to the main ReachabilityManager methods required by tests -type TestReachabilityManager interface { - ReachabilityManager - SetReachabilityReindexWindow(reindexWindow uint64) - SetReachabilityReindexSlack(reindexSlack uint64) - ReachabilityReindexSlack() uint64 -} diff --git a/domain/consensus/model/interface_processes_transactionvalidator.go b/domain/consensus/model/interface_processes_transactionvalidator.go index ccf5de817..d7ea7735e 100644 --- a/domain/consensus/model/interface_processes_transactionvalidator.go +++ b/domain/consensus/model/interface_processes_transactionvalidator.go @@ -2,7 +2,6 @@ package model import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" ) // TransactionValidator exposes a set of validation classes, after which @@ -12,10 +11,3 @@ type TransactionValidator interface { ValidateTransactionInContextAndPopulateMassAndFee(tx *externalapi.DomainTransaction, povTransactionHash *externalapi.DomainHash, selectedParentMedianTime int64) error } - -// TestTransactionValidator adds to the main TransactionValidator methods required by tests -type TestTransactionValidator interface { - TransactionValidator - SigCache() *txscript.SigCache - SetSigCache(sigCache *txscript.SigCache) -} diff --git a/domain/consensus/model/testapi/test_block_builder.go b/domain/consensus/model/testapi/test_block_builder.go new file mode 100644 index 000000000..129d975b9 --- /dev/null +++ b/domain/consensus/model/testapi/test_block_builder.go @@ -0,0 +1,16 @@ +package testapi + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// TestBlockBuilder adds to the main BlockBuilder methods required by tests +type TestBlockBuilder interface { + model.BlockBuilder + + // BuildBlockWithParents builds a block with provided parents, coinbaseData and transactions, + // and returns the block together with its past UTXO-diff from the virtual. + BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) +} diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index d1cdc657f..a90804da0 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -33,11 +33,11 @@ type TestConsensus interface { ReachabilityDataStore() model.ReachabilityDataStore UTXODiffStore() model.UTXODiffStore - BlockBuilder() model.TestBlockBuilder + BlockBuilder() TestBlockBuilder BlockProcessor() model.BlockProcessor BlockValidator() model.BlockValidator CoinbaseManager() model.CoinbaseManager - ConsensusStateManager() model.TestConsensusStateManager + ConsensusStateManager() TestConsensusStateManager DAGTopologyManager() model.DAGTopologyManager DAGTraversalManager() model.DAGTraversalManager DifficultyManager() model.DifficultyManager @@ -46,7 +46,7 @@ type TestConsensus interface { MergeDepthManager() model.MergeDepthManager PastMedianTimeManager() model.PastMedianTimeManager PruningManager() model.PruningManager - ReachabilityManager() model.TestReachabilityManager + ReachabilityManager() TestReachabilityManager SyncManager() model.SyncManager - TransactionValidator() model.TestTransactionValidator + TransactionValidator() TestTransactionValidator } diff --git a/domain/consensus/model/testapi/test_consensus_state_manager.go b/domain/consensus/model/testapi/test_consensus_state_manager.go new file mode 100644 index 000000000..bf112cbb9 --- /dev/null +++ b/domain/consensus/model/testapi/test_consensus_state_manager.go @@ -0,0 +1,15 @@ +package testapi + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// TestConsensusStateManager adds to the main ConsensusStateManager methods required by tests +type TestConsensusStateManager interface { + model.ConsensusStateManager + AddUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, + outpoint *externalapi.DomainOutpoint) error + ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) + VirtualFinalityPoint() (*externalapi.DomainHash, error) +} diff --git a/domain/consensus/model/testapi/test_reachability_manager.go b/domain/consensus/model/testapi/test_reachability_manager.go new file mode 100644 index 000000000..324315772 --- /dev/null +++ b/domain/consensus/model/testapi/test_reachability_manager.go @@ -0,0 +1,11 @@ +package testapi + +import "github.com/kaspanet/kaspad/domain/consensus/model" + +// TestReachabilityManager adds to the main ReachabilityManager methods required by tests +type TestReachabilityManager interface { + model.ReachabilityManager + SetReachabilityReindexWindow(reindexWindow uint64) + SetReachabilityReindexSlack(reindexSlack uint64) + ReachabilityReindexSlack() uint64 +} diff --git a/domain/consensus/model/testapi/test_transaction_validator.go b/domain/consensus/model/testapi/test_transaction_validator.go new file mode 100644 index 000000000..0383e6be8 --- /dev/null +++ b/domain/consensus/model/testapi/test_transaction_validator.go @@ -0,0 +1,13 @@ +package testapi + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" +) + +// TestTransactionValidator adds to the main TransactionValidator methods required by tests +type TestTransactionValidator interface { + model.TransactionValidator + SigCache() *txscript.SigCache + SetSigCache(sigCache *txscript.SigCache) +} diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 08943658c..c9284d7f2 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -20,7 +20,7 @@ var tempBlockHash = &externalapi.DomainHash{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} // NewTestBlockBuilder creates an instance of a TestBlockBuilder -func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus testapi.TestConsensus) model.TestBlockBuilder { +func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus testapi.TestConsensus) testapi.TestBlockBuilder { return &testBlockBuilder{ blockBuilder: baseBlockBuilder.(*blockBuilder), testConsensus: testConsensus, diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go index e867382b3..b6314cc72 100644 --- a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -3,6 +3,7 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" ) type testConsensusStateManager struct { @@ -10,7 +11,7 @@ type testConsensusStateManager struct { } // NewTestConsensusStateManager creates an instance of a TestConsensusStateManager -func NewTestConsensusStateManager(baseConsensusStateManager model.ConsensusStateManager) model.TestConsensusStateManager { +func NewTestConsensusStateManager(baseConsensusStateManager model.ConsensusStateManager) testapi.TestConsensusStateManager { return &testConsensusStateManager{consensusStateManager: baseConsensusStateManager.(*consensusStateManager)} } diff --git a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go index 057794fb9..8aa3d0660 100644 --- a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go @@ -1,6 +1,9 @@ package reachabilitymanager -import "github.com/kaspanet/kaspad/domain/consensus/model" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" +) type testReachabilityManager struct { *reachabilityManager @@ -19,6 +22,6 @@ func (t testReachabilityManager) SetReachabilityReindexWindow(reindexWindow uint } // NewTestReachabilityManager creates an instance of a TestReachabilityManager -func NewTestReachabilityManager(manager model.ReachabilityManager) model.TestReachabilityManager { +func NewTestReachabilityManager(manager model.ReachabilityManager) testapi.TestReachabilityManager { return &testReachabilityManager{reachabilityManager: manager.(*reachabilityManager)} } diff --git a/domain/consensus/processes/transactionvalidator/test_transaction_validator.go b/domain/consensus/processes/transactionvalidator/test_transaction_validator.go index 342b682e2..86bf715b4 100644 --- a/domain/consensus/processes/transactionvalidator/test_transaction_validator.go +++ b/domain/consensus/processes/transactionvalidator/test_transaction_validator.go @@ -2,6 +2,7 @@ package transactionvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" ) @@ -10,7 +11,7 @@ type testTransactionValidator struct { } // NewTestTransactionValidator creates an instance of a TestTransactionValidator -func NewTestTransactionValidator(baseTransactionValidator model.TransactionValidator) model.TestTransactionValidator { +func NewTestTransactionValidator(baseTransactionValidator model.TransactionValidator) testapi.TestTransactionValidator { return &testTransactionValidator{transactionValidator: baseTransactionValidator.(*transactionValidator)} } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index a0dc83936..3ff69352b 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -3,16 +3,17 @@ package consensus import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" ) type testConsensus struct { *consensus - testBlockBuilder model.TestBlockBuilder - testReachabilityManager model.TestReachabilityManager - testConsensusStateManager model.TestConsensusStateManager - testTransactionValidator model.TestTransactionValidator + testBlockBuilder testapi.TestBlockBuilder + testReachabilityManager testapi.TestReachabilityManager + testConsensusStateManager testapi.TestConsensusStateManager + testTransactionValidator testapi.TestTransactionValidator } func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 9d9061f3d..8a668cc97 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -2,6 +2,7 @@ package consensus import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" ) func (tc *testConsensus) DatabaseContext() model.DBReader { @@ -56,7 +57,7 @@ func (tc *testConsensus) UTXODiffStore() model.UTXODiffStore { return tc.utxoDiffStore } -func (tc *testConsensus) BlockBuilder() model.TestBlockBuilder { +func (tc *testConsensus) BlockBuilder() testapi.TestBlockBuilder { return tc.testBlockBuilder } @@ -72,7 +73,7 @@ func (tc *testConsensus) CoinbaseManager() model.CoinbaseManager { return tc.coinbaseManager } -func (tc *testConsensus) ConsensusStateManager() model.TestConsensusStateManager { +func (tc *testConsensus) ConsensusStateManager() testapi.TestConsensusStateManager { return tc.testConsensusStateManager } @@ -108,7 +109,7 @@ func (tc *testConsensus) PruningManager() model.PruningManager { return tc.pruningManager } -func (tc *testConsensus) ReachabilityManager() model.TestReachabilityManager { +func (tc *testConsensus) ReachabilityManager() testapi.TestReachabilityManager { return tc.testReachabilityManager } @@ -116,6 +117,6 @@ func (tc *testConsensus) SyncManager() model.SyncManager { return tc.syncManager } -func (tc *testConsensus) TransactionValidator() model.TestTransactionValidator { +func (tc *testConsensus) TransactionValidator() testapi.TestTransactionValidator { return tc.testTransactionValidator } From 9866abb75adc437c2f78c603db2abab6ed45d0a7 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Wed, 2 Dec 2020 13:01:55 +0200 Subject: [PATCH 106/351] [NOD-1583] Split consensusserialization to consensushashing and serialization --- app/appmessage/p2p_msgblockheader.go | 4 +- app/appmessage/p2p_msgtx.go | 6 +-- app/protocol/flowcontext/blocks.go | 13 ++--- app/protocol/flowcontext/orphans.go | 6 +-- app/protocol/flowcontext/transactions.go | 8 +-- .../flows/blockrelay/handle_relay_invs.go | 6 +-- app/protocol/flows/handshake/sendversion.go | 4 +- app/protocol/flows/ibd/ibd.go | 8 +-- .../handle_request_selected_tip.go | 4 +- .../handle_relayed_transactions.go | 4 +- app/rpc/rpccontext/verbosedata.go | 13 ++--- app/rpc/rpchandlers/get_selected_tip_hash.go | 4 +- app/rpc/rpchandlers/submit_block.go | 4 +- app/rpc/rpchandlers/submit_transaction.go | 4 +- cmd/kaspaminer/mineloop.go | 6 +-- domain/consensus/consensus_test.go | 6 +-- domain/consensus/finality_test.go | 54 +++++++++---------- .../model/externalapi/transaction.go | 2 +- .../processes/blockbuilder/block_builder.go | 6 +-- .../blockprocessor/validateandinsertblock.go | 13 ++--- .../blockvalidator/block_body_in_context.go | 7 +-- .../blockvalidator/block_body_in_isolation.go | 12 ++--- .../block_body_in_isolation_test.go | 13 ++--- .../blockvalidator/block_header_in_context.go | 4 +- .../block_header_in_context_test.go | 4 +- .../block_header_in_isolation.go | 4 +- .../processes/blockvalidator/proof_of_work.go | 4 +- .../calculate_past_utxo.go | 10 ++-- .../consensusstatemanager/multisets.go | 11 ++-- .../populate_tx_with_utxo_entries.go | 4 +- .../resolve_block_status_test.go | 6 +-- .../set_pruning_utxo_set.go | 7 +-- .../verify_and_build_utxo.go | 16 +++--- .../pastmediantimemanager_test.go | 4 +- domain/consensus/ruleerrors/rule_error.go | 4 +- domain/consensus/test_consensus.go | 4 +- .../block.go | 10 ++-- .../transaction.go | 15 +++--- domain/consensus/utils/merkle/merkle.go | 6 +-- domain/consensus/utils/mining/solve.go | 4 +- .../common.go | 18 +++---- .../utils/testutils/create_transaction.go | 4 +- .../utils/txscript/reference_test.go | 4 +- domain/consensus/utils/txscript/script.go | 4 +- .../utxo.go => utxo/serialization.go} | 19 ++++--- .../serialization_test.go} | 2 +- .../utils/utxo/utxoalgebra/diff_helpers.go | 4 +- .../consensus/utils/utxoserialization/utxo.go | 4 +- domain/dagconfig/genesis_test.go | 10 ++-- .../blocktemplatebuilder/txselection.go | 13 ++--- domain/miningmanager/mempool/mempool.go | 40 +++++++------- .../miningmanager/mempool/mempool_utxoset.go | 10 ++-- testing/integration/basic_sync_test.go | 6 +-- testing/integration/mining_test.go | 4 +- testing/integration/tx_relay_test.go | 4 +- 55 files changed, 242 insertions(+), 228 deletions(-) rename domain/consensus/utils/{consensusserialization => consensushashing}/block.go (77%) rename domain/consensus/utils/{consensusserialization => consensushashing}/transaction.go (94%) rename domain/consensus/utils/{consensusserialization => serialization}/common.go (88%) rename domain/consensus/utils/{consensusserialization/utxo.go => utxo/serialization.go} (84%) rename domain/consensus/utils/{consensusserialization/utxo_test.go => utxo/serialization_test.go} (96%) diff --git a/app/appmessage/p2p_msgblockheader.go b/app/appmessage/p2p_msgblockheader.go index 203ba7f16..d0bb04494 100644 --- a/app/appmessage/p2p_msgblockheader.go +++ b/app/appmessage/p2p_msgblockheader.go @@ -7,7 +7,7 @@ package appmessage import ( "math" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/util/mstime" @@ -73,7 +73,7 @@ func (h *MsgBlockHeader) NumParentBlocks() byte { // BlockHash computes the block identifier hash for the given block header. func (h *MsgBlockHeader) BlockHash() *externalapi.DomainHash { - return consensusserialization.HeaderHash(BlockHeaderToDomainBlockHeader(h)) + return consensushashing.HeaderHash(BlockHeaderToDomainBlockHeader(h)) } // IsGenesis returns true iff this block is a genesis block diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index 343e5cf58..1cfad151c 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -10,7 +10,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" @@ -162,12 +162,12 @@ func (msg *MsgTx) IsCoinBase() bool { // TxHash generates the Hash for the transaction. func (msg *MsgTx) TxHash() *externalapi.DomainHash { - return consensusserialization.TransactionHash(MsgTxToDomainTransaction(msg)) + return consensushashing.TransactionHash(MsgTxToDomainTransaction(msg)) } // TxID generates the Hash for the transaction without the signature script, gas and payload fields. func (msg *MsgTx) TxID() *externalapi.DomainTransactionID { - return consensusserialization.TransactionID(MsgTxToDomainTransaction(msg)) + return consensushashing.TransactionID(MsgTxToDomainTransaction(msg)) } // Copy creates a deep copy of a transaction so that the original does not get diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 28aba09ef..592c1b53c 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -1,13 +1,14 @@ package flowcontext import ( + "sync/atomic" + "github.com/kaspanet/kaspad/app/protocol/blocklogger" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/pkg/errors" - "sync/atomic" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/flows/blockrelay" @@ -17,7 +18,7 @@ import ( // relays newly unorphaned transactions and possibly rebroadcast // manually added transactions when not in IBD. func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { - hash := consensusserialization.BlockHash(block) + hash := consensushashing.BlockHash(block) log.Debugf("OnNewBlock start for block %s", hash) defer log.Debugf("OnNewBlock end for block %s", hash) unorphanedBlocks, err := f.UnorphanBlocks(block) @@ -63,7 +64,7 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded( txIDsToBroadcast := make([]*externalapi.DomainTransactionID, len(transactionsAcceptedToMempool)+len(txIDsToRebroadcast)) for i, tx := range transactionsAcceptedToMempool { - txIDsToBroadcast[i] = consensusserialization.TransactionID(tx) + txIDsToBroadcast[i] = consensushashing.TransactionID(tx) } offset := len(transactionsAcceptedToMempool) for i, txID := range txIDsToRebroadcast { @@ -91,7 +92,7 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { err := f.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { - log.Infof("Validation failed for block %s: %s", consensusserialization.BlockHash(block), err) + log.Infof("Validation failed for block %s: %s", consensushashing.BlockHash(block), err) return nil } return err @@ -100,5 +101,5 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { if err != nil { return err } - return f.Broadcast(appmessage.NewMsgInvBlock(consensusserialization.BlockHash(block))) + return f.Broadcast(appmessage.NewMsgInvBlock(consensushashing.BlockHash(block))) } diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 5411dfb39..6e70c68be 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -3,7 +3,7 @@ package flowcontext import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/pkg/errors" ) @@ -12,7 +12,7 @@ func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphansMutex.Lock() defer f.orphansMutex.Unlock() - orphanHash := consensusserialization.BlockHash(orphanBlock) + orphanHash := consensushashing.BlockHash(orphanBlock) f.orphans[*orphanHash] = orphanBlock log.Infof("Received a block with missing parents, adding to orphan pool: %s", orphanHash) @@ -34,7 +34,7 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*ext // Find all the children of rootBlock among the orphans // and add them to the process queue - rootBlockHash := consensusserialization.BlockHash(rootBlock) + rootBlockHash := consensushashing.BlockHash(rootBlock) processQueue := f.addChildOrphansToProcessQueue(rootBlockHash, []externalapi.DomainHash{}) var unorphanedBlocks []*externalapi.DomainBlock diff --git a/app/protocol/flowcontext/transactions.go b/app/protocol/flowcontext/transactions.go index 5d59eae96..491248a55 100644 --- a/app/protocol/flowcontext/transactions.go +++ b/app/protocol/flowcontext/transactions.go @@ -6,7 +6,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" ) // AddTransaction adds transaction to the mempool and propagates it. @@ -19,7 +19,7 @@ func (f *FlowContext) AddTransaction(tx *externalapi.DomainTransaction) error { return err } - transactionID := consensusserialization.TransactionID(tx) + transactionID := consensushashing.TransactionID(tx) f.transactionsToRebroadcast[*transactionID] = tx inv := appmessage.NewMsgInvTransaction([]*externalapi.DomainTransactionID{transactionID}) return f.Broadcast(inv) @@ -32,7 +32,7 @@ func (f *FlowContext) updateTransactionsToRebroadcast(block *externalapi.DomainB // anymore, although they are not included in the UTXO set. // This is probably ok, since red blocks are quite rare. for _, tx := range block.Transactions { - delete(f.transactionsToRebroadcast, *consensusserialization.TransactionID(tx)) + delete(f.transactionsToRebroadcast, *consensushashing.TransactionID(tx)) } } @@ -48,7 +48,7 @@ func (f *FlowContext) txIDsToRebroadcast() []*externalapi.DomainTransactionID { txIDs := make([]*externalapi.DomainTransactionID, len(f.transactionsToRebroadcast)) i := 0 for _, tx := range f.transactionsToRebroadcast { - txIDs[i] = consensusserialization.TransactionID(tx) + txIDs[i] = consensushashing.TransactionID(tx) i++ } return txIDs diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 8cb17c35c..19c4bda1b 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -9,7 +9,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" @@ -174,7 +174,7 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err } block := appmessage.MsgBlockToDomainBlock(msgBlock) - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) log.Criticalf("got block %s", blockHash) if *blockHash != *expectedHash { @@ -213,7 +213,7 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock, } func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueSet, requestedBlocksSet map[externalapi.DomainHash]struct{}, block *externalapi.DomainBlock) error { - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) log.Debugf("processAndRelayBlock start for block %s", blockHash) defer log.Debugf("processAndRelayBlock end for block %s", blockHash) diff --git a/app/protocol/flows/handshake/sendversion.go b/app/protocol/flows/handshake/sendversion.go index 7d5f04774..a7633fa8c 100644 --- a/app/protocol/flows/handshake/sendversion.go +++ b/app/protocol/flows/handshake/sendversion.go @@ -4,7 +4,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/version" @@ -56,7 +56,7 @@ func (flow *sendVersionFlow) start() error { if err != nil { return err } - selectedTipHash := consensusserialization.BlockHash(virtualSelectedParent) + selectedTipHash := consensushashing.BlockHash(virtualSelectedParent) subnetworkID := flow.Config().SubnetworkID // Version message. diff --git a/app/protocol/flows/ibd/ibd.go b/app/protocol/flows/ibd/ibd.go index edf80314a..912698ac3 100644 --- a/app/protocol/flows/ibd/ibd.go +++ b/app/protocol/flows/ibd/ibd.go @@ -8,7 +8,7 @@ import ( "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/config" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" @@ -143,7 +143,7 @@ func (flow *handleIBDFlow) syncMissingBlockBodies() error { } block := appmessage.MsgBlockToDomainBlock(msgIBDBlock.MsgBlock) - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) if *expectedHash != *blockHash { return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash) } @@ -179,7 +179,7 @@ func (flow *handleIBDFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHa err = flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "got invalid block %s during IBD", blockHash) } @@ -333,7 +333,7 @@ func (flow *handleIBDFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHead Transactions: nil, } - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockHash) if err != nil { return err diff --git a/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go b/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go index dbaf41daa..2477b995f 100644 --- a/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go +++ b/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go @@ -3,7 +3,7 @@ package selectedtip import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" ) @@ -61,6 +61,6 @@ func (flow *handleRequestSelectedTipFlow) sendSelectedTipHash() error { if err != nil { return err } - msgSelectedTip := appmessage.NewMsgSelectedTip(consensusserialization.BlockHash(virtualSelectedParent)) + msgSelectedTip := appmessage.NewMsgSelectedTip(consensushashing.BlockHash(virtualSelectedParent)) return flow.outgoingRoute.Enqueue(msgSelectedTip) } diff --git a/app/protocol/flows/relaytransactions/handle_relayed_transactions.go b/app/protocol/flows/relaytransactions/handle_relayed_transactions.go index 41b7aabad..9fc42aec3 100644 --- a/app/protocol/flows/relaytransactions/handle_relayed_transactions.go +++ b/app/protocol/flows/relaytransactions/handle_relayed_transactions.go @@ -6,7 +6,7 @@ import ( "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/miningmanager/mempool" "github.com/kaspanet/kaspad/infrastructure/network/netadapter" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" @@ -167,7 +167,7 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact continue } tx := appmessage.MsgTxToDomainTransaction(msgTx) - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) if txID != expectedID { return protocolerrors.Errorf(true, "expected transaction %s, but got %s", expectedID, txID) diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index ad6dbd775..5af013237 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -3,10 +3,11 @@ package rpccontext import ( "encoding/hex" "fmt" - "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" "math/big" "strconv" + "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" + "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" @@ -14,7 +15,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/pointers" @@ -23,7 +24,7 @@ import ( // BuildBlockVerboseData builds a BlockVerboseData from the given block. // This method must be called with the DAG lock held for reads func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { - hash := consensusserialization.BlockHash(block) + hash := consensushashing.BlockHash(block) blockHeader := block.Header blueScore, err := blocks.ExtractBlueScore(block) @@ -48,14 +49,14 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ txIDs := make([]string, len(block.Transactions)) for i, tx := range block.Transactions { - txIDs[i] = consensusserialization.TransactionID(tx).String() + txIDs[i] = consensushashing.TransactionID(tx).String() } result.TxIDs = txIDs if includeTransactionVerboseData { transactionVerboseData := make([]*appmessage.TransactionVerboseData, len(block.Transactions)) for i, tx := range block.Transactions { - txID := consensusserialization.TransactionID(tx).String() + txID := consensushashing.TransactionID(tx).String() data, err := ctx.BuildTransactionVerboseData(tx, txID, blockHeader, hash.String()) if err != nil { return nil, err @@ -100,7 +101,7 @@ func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransactio txReply := &appmessage.TransactionVerboseData{ TxID: txID, - Hash: consensusserialization.TransactionHash(tx).String(), + Hash: consensushashing.TransactionHash(tx).String(), Size: estimatedsize.TransactionEstimatedSerializedSize(tx), TransactionVerboseInputs: ctx.buildTransactionVerboseInputs(tx), TransactionVerboseOutputs: ctx.buildTransactionVerboseOutputs(tx, nil), diff --git a/app/rpc/rpchandlers/get_selected_tip_hash.go b/app/rpc/rpchandlers/get_selected_tip_hash.go index 9f2a63415..3831b98d0 100644 --- a/app/rpc/rpchandlers/get_selected_tip_hash.go +++ b/app/rpc/rpchandlers/get_selected_tip_hash.go @@ -3,7 +3,7 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -15,7 +15,7 @@ func HandleGetSelectedTipHash(context *rpccontext.Context, _ *router.Router, _ a } response := appmessage.NewGetSelectedTipHashResponseMessage( - consensusserialization.BlockHash(selectedTip).String()) + consensushashing.BlockHash(selectedTip).String()) return response, nil } diff --git a/app/rpc/rpchandlers/submit_block.go b/app/rpc/rpchandlers/submit_block.go index eca17c389..e5fb5f799 100644 --- a/app/rpc/rpchandlers/submit_block.go +++ b/app/rpc/rpchandlers/submit_block.go @@ -3,7 +3,7 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -21,7 +21,7 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap return errorMessage, nil } - log.Infof("Accepted block %s via submitBlock", consensusserialization.BlockHash(domainBlock)) + log.Infof("Accepted block %s via submitBlock", consensushashing.BlockHash(domainBlock)) response := appmessage.NewSubmitBlockResponseMessage() return response, nil diff --git a/app/rpc/rpchandlers/submit_transaction.go b/app/rpc/rpchandlers/submit_transaction.go index 061e6e308..46e4437eb 100644 --- a/app/rpc/rpchandlers/submit_transaction.go +++ b/app/rpc/rpchandlers/submit_transaction.go @@ -3,7 +3,7 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/miningmanager/mempool" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" @@ -14,7 +14,7 @@ func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, requ submitTransactionRequest := request.(*appmessage.SubmitTransactionRequestMessage) domainTransaction := appmessage.MsgTxToDomainTransaction(submitTransactionRequest.Transaction) - transactionID := consensusserialization.TransactionID(domainTransaction) + transactionID := consensushashing.TransactionID(domainTransaction) err := context.ProtocolManager.AddTransaction(domainTransaction) if err != nil { if !errors.As(err, &mempool.RuleError{}) { diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index a084a1236..26b38dd42 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -9,7 +9,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -95,7 +95,7 @@ func mineNextBlock(client *minerClient, miningAddr util.Address, foundBlock chan } func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error { - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) log.Infof("Found block %s with parents %s. Submitting to %s", blockHash, block.Header.ParentHashes, client.Address()) err := client.SubmitBlock(block) @@ -114,7 +114,7 @@ func solveBlock(block *externalapi.DomainBlock, stopChan chan struct{}, foundBlo return default: block.Header.Nonce = i - hash := consensusserialization.BlockHash(block) + hash := consensushashing.BlockHash(block) atomic.AddUint64(&hashesTried, 1) if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { foundBlock <- block diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index 63c1d1527..67662b591 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -5,7 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" @@ -31,7 +31,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) { t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrTimeTooOld, err) } - info, err := consensus.GetBlockInfo(consensusserialization.BlockHash(invalidBlock)) + info, err := consensus.GetBlockInfo(consensushashing.BlockHash(invalidBlock)) if err != nil { t.Fatalf("Failed to get block info: %v", err) } @@ -57,7 +57,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) { t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err) } - info, err = consensus.GetBlockInfo(consensusserialization.BlockHash(validBlock)) + info, err = consensus.GetBlockInfo(consensushashing.BlockHash(validBlock)) if err != nil { t.Fatalf("Failed to get block info: %v", err) } diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index f5ba1a48e..3beff0f45 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -5,7 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" @@ -49,7 +49,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed to process Block #%d: %v", i, err) } - mainChainTipHash = consensusserialization.BlockHash(mainChainTip) + mainChainTipHash = consensushashing.BlockHash(mainChainTip) blockInfo, err := consensus.GetBlockInfo(mainChainTipHash) if err != nil { @@ -69,7 +69,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) } - sideChainTipHash = consensusserialization.BlockHash(sideChainTip) + sideChainTipHash = consensushashing.BlockHash(sideChainTip) blockInfo, err := consensus.GetBlockInfo(sideChainTipHash) if err != nil { @@ -89,7 +89,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) } - sideChainTipHash = consensusserialization.BlockHash(sideChainTip) + sideChainTipHash = consensushashing.BlockHash(sideChainTip) } // Make sure that now the sideChainTip is valid and selectedTip @@ -107,7 +107,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) } - if *consensusserialization.BlockHash(selectedTip) != *sideChainTipHash { + if *consensushashing.BlockHash(selectedTip) != *sideChainTipHash { t.Fatalf("Overtaking block in side-chain is not selectedTip") } @@ -117,7 +117,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) } - mainChainTipHash = consensusserialization.BlockHash(mainChainTip) + mainChainTipHash = consensushashing.BlockHash(mainChainTip) } virtualFinality, err := consensus.ConsensusStateManager().VirtualFinalityPoint() @@ -137,7 +137,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err) } - sideChainTipHash = consensusserialization.BlockHash(sideChainTip) + sideChainTipHash = consensushashing.BlockHash(sideChainTip) } // Check that sideChainTip hash higher blue score than the selected parent @@ -145,7 +145,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) } - selectedTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), consensusserialization.BlockHash(selectedTip)) + selectedTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), consensushashing.BlockHash(selectedTip)) if err != nil { t.Fatalf("TestFinality: Failed getting the ghost dag data of the selected tip: %v", err) } @@ -222,7 +222,7 @@ func TestBoundedMergeDepth(t *testing.T) { } getStatus := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock) externalapi.BlockStatus { - blockInfo, err := consensus.GetBlockInfo(consensusserialization.BlockHash(block)) + blockInfo, err := consensus.GetBlockInfo(consensushashing.BlockHash(block)) if err != nil { t.Fatalf("TestBoundedMergeDepth: Failed to get block info: %v", err) } else if !blockInfo.Exists { @@ -248,21 +248,21 @@ func TestBoundedMergeDepth(t *testing.T) { // Create a chain selectedChain := make([]*externalapi.DomainBlock, 0, finalityInterval+1) - parent := consensusserialization.BlockHash(block1) + parent := consensushashing.BlockHash(block1) // Make sure this is always bigger than `blocksChain2` so it will stay the selected chain for i := 0; i < finalityInterval+2; i++ { block := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{parent}) selectedChain = append(selectedChain, block) - parent = consensusserialization.BlockHash(block) + parent = consensushashing.BlockHash(block) } // Create another chain blocksChain2 := make([]*externalapi.DomainBlock, 0, finalityInterval+1) - parent = consensusserialization.BlockHash(block1) + parent = consensushashing.BlockHash(block1) for i := 0; i < finalityInterval+1; i++ { block := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{parent}) blocksChain2 = append(blocksChain2, block) - parent = consensusserialization.BlockHash(block) + parent = consensushashing.BlockHash(block) } // Teardown and assign nil to make sure we use the right DAG from here on. @@ -284,20 +284,20 @@ func TestBoundedMergeDepth(t *testing.T) { } // submit a block pointing at tip(chain1) and on first block in chain2 directly - mergeDepthViolatingBlockBottom, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[0]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])}) + mergeDepthViolatingBlockBottom, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensushashing.BlockHash(blocksChain2[0]), consensushashing.BlockHash(selectedChain[len(selectedChain)-1])}) if !isViolatingMergeDepth { t.Fatalf("TestBoundedMergeDepth: Expected mergeDepthViolatingBlockBottom to violate merge depth") } // submit a block pointing at tip(chain1) and tip(chain2) should also obviously violate merge depth (this points at first block in chain2 indirectly) - mergeDepthViolatingTop, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[len(blocksChain2)-1]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])}) + mergeDepthViolatingTop, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensushashing.BlockHash(blocksChain2[len(blocksChain2)-1]), consensushashing.BlockHash(selectedChain[len(selectedChain)-1])}) if !isViolatingMergeDepth { t.Fatalf("TestBoundedMergeDepth: Expected mergeDepthViolatingTop to violate merge depth") } // the location of the parents in the slices need to be both `-X` so the `selectedChain` one will have higher blueScore (it's a chain longer by 1) - kosherizingBlock, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(blocksChain2[len(blocksChain2)-3]), consensusserialization.BlockHash(selectedChain[len(selectedChain)-3])}) - kosherizingBlockHash := consensusserialization.BlockHash(kosherizingBlock) + kosherizingBlock, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensushashing.BlockHash(blocksChain2[len(blocksChain2)-3]), consensushashing.BlockHash(selectedChain[len(selectedChain)-3])}) + kosherizingBlockHash := consensushashing.BlockHash(kosherizingBlock) if isViolatingMergeDepth { t.Fatalf("TestBoundedMergeDepth: Expected blueKosherizingBlock to not violate merge depth") } @@ -318,7 +318,7 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Expected kosherizingBlock to be blue by the virtual") } - pointAtBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{kosherizingBlockHash, consensusserialization.BlockHash(selectedChain[len(selectedChain)-1])}) + pointAtBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{kosherizingBlockHash, consensushashing.BlockHash(selectedChain[len(selectedChain)-1])}) if isViolatingMergeDepth { t.Fatalf("TestBoundedMergeDepth: Expected selectedTip to not violate merge depth") @@ -329,16 +329,16 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if *consensusserialization.BlockHash(virtualSelectedParent) != *consensusserialization.BlockHash(pointAtBlueKosherizing) { - t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensusserialization.BlockHash(pointAtBlueKosherizing), consensusserialization.BlockHash(virtualSelectedParent)) + if *consensushashing.BlockHash(virtualSelectedParent) != *consensushashing.BlockHash(pointAtBlueKosherizing) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(pointAtBlueKosherizing), consensushashing.BlockHash(virtualSelectedParent)) } // Now let's make the kosherizing block red and try to merge again - tip := consensusserialization.BlockHash(selectedChain[len(selectedChain)-1]) + tip := consensushashing.BlockHash(selectedChain[len(selectedChain)-1]) // we use k-1 because `kosherizingBlock` points at tip-2, so 2+k-1 = k+1 anticone. for i := 0; i < int(params.K)-1; i++ { block := buildAndInsertBlock(consensusReal, []*externalapi.DomainHash{tip}) - tip = consensusserialization.BlockHash(block) + tip = consensushashing.BlockHash(block) } virtualSelectedParent, err = consensusReal.GetVirtualSelectedParent() @@ -346,8 +346,8 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if *consensusserialization.BlockHash(virtualSelectedParent) != *tip { - t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, consensusserialization.BlockHash(virtualSelectedParent)) + if *consensushashing.BlockHash(virtualSelectedParent) != *tip { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, consensushashing.BlockHash(virtualSelectedParent)) } virtualGhotDagData, err = consensusReal.GHOSTDAGDataStore().Get(consensusReal.DatabaseContext(), model.VirtualBlockHash) @@ -372,7 +372,7 @@ func TestBoundedMergeDepth(t *testing.T) { } // Now `pointAtBlueKosherizing` itself is actually still blue, so we can still point at that even though we can't point at kosherizing directly anymore - transitiveBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensusserialization.BlockHash(pointAtBlueKosherizing), tip}) + transitiveBlueKosherizing, isViolatingMergeDepth := checkViolatingMergeDepth(consensusReal, []*externalapi.DomainHash{consensushashing.BlockHash(pointAtBlueKosherizing), tip}) if isViolatingMergeDepth { t.Fatalf("TestBoundedMergeDepth: Expected transitiveBlueKosherizing to not violate merge depth") } @@ -382,8 +382,8 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if *consensusserialization.BlockHash(virtualSelectedParent) != *consensusserialization.BlockHash(transitiveBlueKosherizing) { - t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensusserialization.BlockHash(transitiveBlueKosherizing), consensusserialization.BlockHash(virtualSelectedParent)) + if *consensushashing.BlockHash(virtualSelectedParent) != *consensushashing.BlockHash(transitiveBlueKosherizing) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(transitiveBlueKosherizing), consensushashing.BlockHash(virtualSelectedParent)) } // Lets validate the status of all the interesting blocks diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 9928ad732..83300d2c7 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -19,7 +19,7 @@ type DomainTransaction struct { Mass uint64 // ID is a field that is used to cache the transaction ID. - // Always use consensusserialization.TransactionID instead of accessing this field directly + // Always use consensushashing.TransactionID instead of accessing this field directly ID *DomainTransactionID } diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index fbd059ab7..515465dce 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -5,7 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" @@ -193,8 +193,8 @@ func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.Accep } } sort.Slice(acceptedTransactions, func(i, j int) bool { - acceptedTransactionIID := consensusserialization.TransactionID(acceptedTransactions[i]) - acceptedTransactionJID := consensusserialization.TransactionID(acceptedTransactions[j]) + acceptedTransactionIID := consensushashing.TransactionID(acceptedTransactions[i]) + acceptedTransactionJID := consensushashing.TransactionID(acceptedTransactions[j]) return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID) }) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index f521c9b52..c5b2de299 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -2,16 +2,17 @@ package blockprocessor import ( "fmt" + "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/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" ) func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error { - hash := consensusserialization.HeaderHash(block.Header) + hash := consensushashing.HeaderHash(block.Header) log.Debugf("Validating block %s", hash) syncInfo, err := bp.syncManager.GetSyncInfo() @@ -222,7 +223,7 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode *e } func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *externalapi.SyncInfo) error { - blockHash := consensusserialization.HeaderHash(block.Header) + blockHash := consensushashing.HeaderHash(block.Header) hasHeader, err := bp.hasHeader(blockHash) if err != nil { return err @@ -251,7 +252,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { bp.discardAllChanges() - hash := consensusserialization.BlockHash(block) + hash := consensushashing.BlockHash(block) bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid) commitErr := bp.commitAllChanges() if commitErr != nil { @@ -264,7 +265,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex } func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error { - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) hasHeader, err := bp.hasHeader(blockHash) if err != nil { @@ -283,7 +284,7 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) } func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, mode *externalapi.SyncInfo) error { - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) if mode.State != externalapi.SyncStateHeadersFirst { bp.blockStore.Stage(blockHash, block) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index dcf281a2f..b2897fee2 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -1,12 +1,13 @@ package blockvalidator import ( + "math" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/pkg/errors" - "math" ) // ValidateBodyInContext validates block bodies in the context of the current @@ -39,7 +40,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi. // Ensure all transactions in the block are finalized. for _, tx := range block.Transactions { if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore, blockTime) { - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains unfinalized "+ "transaction %s", txID) } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 635d5ef77..4f0dbd9e7 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -4,7 +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/coinbase" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" @@ -132,7 +132,7 @@ func (v *blockValidator) checkTransactionsInIsolation(block *externalapi.DomainB err := v.transactionValidator.ValidateTransactionInIsolation(tx) if err != nil { return errors.Wrapf(err, "transaction %s failed isolation "+ - "check", consensusserialization.TransactionID(tx)) + "check", consensushashing.TransactionID(tx)) } } @@ -152,7 +152,7 @@ func (v *blockValidator) checkBlockHashMerkleRoot(block *externalapi.DomainBlock func (v *blockValidator) checkBlockDuplicateTransactions(block *externalapi.DomainBlock) error { existingTxIDs := make(map[externalapi.DomainTransactionID]struct{}) for _, tx := range block.Transactions { - id := consensusserialization.TransactionID(tx) + id := consensushashing.TransactionID(tx) if _, exists := existingTxIDs[*id]; exists { return errors.Wrapf(ruleerrors.ErrDuplicateTx, "block contains duplicate "+ "transaction %s", id) @@ -166,7 +166,7 @@ func (v *blockValidator) checkBlockDoubleSpends(block *externalapi.DomainBlock) usedOutpoints := make(map[externalapi.DomainOutpoint]*externalapi.DomainTransactionID) for _, tx := range block.Transactions { for _, input := range tx.Inputs { - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) if spendingTxID, exists := usedOutpoints[input.PreviousOutpoint]; exists { return errors.Wrapf(ruleerrors.ErrDoubleSpendInSameBlock, "transaction %s spends "+ "outpoint %s that was already spent by "+ @@ -184,14 +184,14 @@ func (v *blockValidator) checkBlockHasNoChainedTransactions(block *externalapi.D transactions := block.Transactions transactionsSet := make(map[externalapi.DomainTransactionID]struct{}, len(transactions)) for _, transaction := range transactions { - txID := consensusserialization.TransactionID(transaction) + txID := consensushashing.TransactionID(transaction) transactionsSet[*txID] = struct{}{} } for _, transaction := range transactions { for i, transactionInput := range transaction.Inputs { if _, ok := transactionsSet[transactionInput.PreviousOutpoint.TransactionID]; ok { - txID := consensusserialization.TransactionID(transaction) + txID := consensushashing.TransactionID(transaction) return errors.Wrapf(ruleerrors.ErrChainedTransactions, "block contains chained "+ "transactions: Input %d of transaction %s spend "+ "an output of transaction %s", i, txID, transactionInput.PreviousOutpoint.TransactionID) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 3fe1177a1..9f9966eeb 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -1,16 +1,17 @@ package blockvalidator_test import ( + "math" + "testing" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" - "math" - "testing" ) func TestChainedTransactions(t *testing.T) { @@ -86,7 +87,7 @@ func TestCheckBlockSanity(t *testing.T) { t.Fatalf("Error setting up consensus: %+v", err) } defer teardown() - blockHash := consensusserialization.BlockHash(&exampleValidBlock) + 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)) } @@ -99,7 +100,7 @@ func TestCheckBlockSanity(t *testing.T) { } // Test with block with wrong transactions sorting order - blockHash = consensusserialization.BlockHash(&blockWithWrongTxOrder) + blockHash = consensushashing.BlockHash(&blockWithWrongTxOrder) consensus.BlockStore().Stage(blockHash, &blockWithWrongTxOrder) err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) { @@ -108,7 +109,7 @@ func TestCheckBlockSanity(t *testing.T) { // Test a block with invalid parents order // We no longer require blocks to have ordered parents - blockHash = consensusserialization.BlockHash(&unOrderedParentsBlock) + blockHash = consensushashing.BlockHash(&unOrderedParentsBlock) consensus.BlockStore().Stage(blockHash, &unOrderedParentsBlock) err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) if err != nil { diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 1d76108ed..168ca800a 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -3,7 +3,7 @@ package blockvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/pkg/errors" ) @@ -96,7 +96,7 @@ func (v *blockValidator) validateMedianTime(header *externalapi.DomainBlockHeade // Ensure the timestamp for the block header is not before the // median time of the last several blocks (medianTimeBlocks). - hash := consensusserialization.HeaderHash(header) + hash := consensushashing.HeaderHash(header) pastMedianTime, err := v.pastMedianTimeManager.PastMedianTime(hash) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index 4f46a8c4f..e6c8238f9 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -8,7 +8,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/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" ) @@ -34,7 +34,7 @@ func TestValidateMedianTime(t *testing.T) { t.Fatalf("expected error %s but got %+v", expectedErr, err) } - return block, consensusserialization.BlockHash(block) + return block, consensushashing.BlockHash(block) } pastMedianTime := func(parents ...*externalapi.DomainHash) int64 { diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 6c13cb4ee..9a1347688 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -3,7 +3,7 @@ package blockvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/pkg/errors" ) @@ -25,7 +25,7 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain } func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader) error { - hash := consensusserialization.HeaderHash(header) + hash := consensushashing.HeaderHash(header) if len(header.ParentHashes) == 0 && *hash != *v.genesisHash { return errors.Wrapf(ruleerrors.ErrNoParents, "block has no parents") } diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index e6de47b69..a63b70f93 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -3,7 +3,7 @@ package blockvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/util" "github.com/pkg/errors" @@ -93,7 +93,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) // to avoid proof of work checks is set. if !v.skipPoW { // The block hash must be less than the claimed target. - hash := consensusserialization.HeaderHash(header) + hash := consensushashing.HeaderHash(header) hashNum := hashes.ToBig(hash) if hashNum.Cmp(target) > 0 { return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block hash of %064x is higher than "+ diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index a988c94e4..bd01ca567 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -1,7 +1,7 @@ package consensusstatemanager import ( - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" @@ -132,7 +132,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH accumulatedMass := uint64(0) for i, blueBlock := range blueBlocks { - blueBlockHash := consensusserialization.BlockHash(blueBlock) + blueBlockHash := consensushashing.BlockHash(blueBlock) log.Tracef("Applying blue block %s", blueBlockHash) blockAcceptanceData := &model.BlockAcceptanceData{ TransactionAcceptanceData: make([]*model.TransactionAcceptanceData, len(blueBlock.Transactions)), @@ -143,7 +143,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH for j, transaction := range blueBlock.Transactions { var isAccepted bool - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) log.Tracef("Attempting to accept transaction %s in block %s", transactionID, blueBlockHash) @@ -172,7 +172,7 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap accumulatedMassBefore uint64, selectedParentPastMedianTime int64, blockBlueScore uint64) ( isAccepted bool, accumulatedMassAfter uint64, err error) { - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) log.Tracef("maybeAcceptTransaction start for transaction %s in block %s", transactionID, blockHash) defer log.Tracef("maybeAcceptTransaction end for transaction %s in block %s", transactionID, blockHash) @@ -232,7 +232,7 @@ func (csm *consensusStateManager) checkTransactionMass( transaction *externalapi.DomainTransaction, accumulatedMassBefore uint64) ( isAccepted bool, accumulatedMassAfter uint64) { - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) log.Tracef("checkTransactionMass start for transaction %s", transactionID) defer log.Tracef("checkTransactionMass end for transaction %s", transactionID) diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index fc77e95d2..c3b1e7336 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -3,8 +3,9 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" ) @@ -29,7 +30,7 @@ func (csm *consensusStateManager) calculateMultiset( for _, blockAcceptanceData := range acceptanceData { for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { transaction := transactionAcceptanceData.Transaction - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) if !transactionAcceptanceData.IsAccepted { log.Tracef("Skipping transaction %s because it was not accepted", transactionID) continue @@ -53,7 +54,7 @@ func (csm *consensusStateManager) calculateMultiset( func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi.DomainTransaction, blockBlueScore uint64, isCoinbase bool) error { - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) log.Tracef("addTransactionToMultiset start for transaction %s", transactionID) defer log.Tracef("addTransactionToMultiset end for transaction %s", transactionID) @@ -90,7 +91,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi. func addUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error { - serializedUTXO, err := consensusserialization.SerializeUTXO(entry, outpoint) + serializedUTXO, err := utxo.SerializeUTXO(entry, outpoint) if err != nil { return err } @@ -102,7 +103,7 @@ func addUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, func removeUTXOFromMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error { - serializedUTXO, err := consensusserialization.SerializeUTXO(entry, outpoint) + serializedUTXO, err := utxo.SerializeUTXO(entry, outpoint) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go index 9e9f4a00c..1b6e38d73 100644 --- a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go +++ b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go @@ -4,7 +4,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/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" ) @@ -19,7 +19,7 @@ func (csm *consensusStateManager) PopulateTransactionWithUTXOEntries(transaction func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualOrDiff( transaction *externalapi.DomainTransaction, utxoDiff *model.UTXODiff) error { - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff start for transaction %s", transactionID) defer log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff end for transaction %s", transactionID) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 3dae149b0..ad0f1eaa5 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -6,7 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -54,8 +54,8 @@ func TestDoubleSpends(t *testing.T) { t.Fatalf("Error creating spendingTransaction2: %+v", err) } spendingTransaction2.Outputs[0].Value-- // tweak the value to create a different ID - spendingTransaction1ID := consensusserialization.TransactionID(spendingTransaction1) - spendingTransaction2ID := consensusserialization.TransactionID(spendingTransaction2) + spendingTransaction1ID := consensushashing.TransactionID(spendingTransaction1) + spendingTransaction2ID := consensushashing.TransactionID(spendingTransaction2) if *spendingTransaction1ID == *spendingTransaction2ID { t.Fatalf("spendingTransaction1 and spendingTransaction2 ids are equal") } diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 83e37e6f4..7c6b667a8 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -5,7 +5,8 @@ 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/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" @@ -130,9 +131,9 @@ func (p protoUTXOSetIterator) Next() bool { } func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { - entry, outpoint, err := consensusserialization.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair) + entry, outpoint, err := utxo.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair) if err != nil { - if consensusserialization.IsMalformedError(err) { + if serialization.IsMalformedError(err) { return nil, nil, errors.Wrap(ruleerrors.ErrMalformedUTXO, "malformed utxo") } return nil, nil, err diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index c38c32cee..17226e863 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -8,7 +8,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/coinbase" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" @@ -40,7 +40,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo coinbaseTransaction := block.Transactions[0] log.Tracef("Validating coinbase transaction %s for block %s", - consensusserialization.TransactionID(coinbaseTransaction), blockHash) + consensushashing.TransactionID(coinbaseTransaction), blockHash) err = csm.validateCoinbaseTransaction(blockHash, coinbaseTransaction) if err != nil { return err @@ -70,7 +70,7 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block log.Tracef("The past median time of %s is %d", blockHash, selectedParentMedianTime) for i, transaction := range block.Transactions { - transactionID := consensusserialization.TransactionID(transaction) + transactionID := consensushashing.TransactionID(transaction) log.Tracef("Validating transaction %s in block %s against "+ "the block's past UTXO", transactionID, blockHash) if i == transactionhelper.CoinbaseTransactionIndex { @@ -143,8 +143,8 @@ func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData } sort.Slice(acceptedTransactions, func(i, j int) bool { return transactionid.Less( - consensusserialization.TransactionID(acceptedTransactions[i]), - consensusserialization.TransactionID(acceptedTransactions[j])) + consensushashing.TransactionID(acceptedTransactions[i]), + consensushashing.TransactionID(acceptedTransactions[j])) }) return merkle.CalculateIDMerkleRoot(acceptedTransactions) @@ -156,7 +156,7 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa defer log.Tracef("validateCoinbaseTransaction end for block %s", blockHash) log.Tracef("Extracting coinbase data for coinbase transaction %s in block %s", - consensusserialization.TransactionID(coinbaseTransaction), blockHash) + consensushashing.TransactionID(coinbaseTransaction), blockHash) _, coinbaseData, err := coinbase.ExtractCoinbaseDataAndBlueScore(coinbaseTransaction) if err != nil { return err @@ -168,8 +168,8 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa return err } - coinbaseTransactionHash := consensusserialization.TransactionHash(coinbaseTransaction) - expectedCoinbaseTransactionHash := consensusserialization.TransactionHash(expectedCoinbaseTransaction) + coinbaseTransactionHash := consensushashing.TransactionHash(coinbaseTransaction) + expectedCoinbaseTransactionHash := consensushashing.TransactionHash(expectedCoinbaseTransaction) log.Tracef("given coinbase hash: %s, expected coinbase hash: %s", coinbaseTransactionHash, expectedCoinbaseTransactionHash) diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index 5cce8cca9..37f54f51a 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -5,7 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" ) @@ -36,7 +36,7 @@ func TestPastMedianTime(t *testing.T) { t.Fatalf("ValidateAndInsertBlock: %+v", err) } - blockHashes[i] = consensusserialization.BlockHash(block) + blockHashes[i] = consensushashing.BlockHash(block) } tests := []struct { diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 6dab741f2..720aef602 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/pkg/errors" ) @@ -311,7 +311,7 @@ type InvalidTransaction struct { } func (invalid InvalidTransaction) String() string { - return fmt.Sprintf("(%v: %s)", consensusserialization.TransactionID(invalid.Transaction), invalid.err) + return fmt.Sprintf("(%v: %s)", consensushashing.TransactionID(invalid.Transaction), invalid.err) } // ErrInvalidTransactionsInNewBlock indicates that some transactions in a new block are invalid diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 3ff69352b..216befae1 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -4,7 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" ) type testConsensus struct { @@ -44,7 +44,7 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba return nil, err } - return consensusserialization.BlockHash(block), nil + return consensushashing.BlockHash(block), nil } func (tc *testConsensus) DiscardAllStores() { diff --git a/domain/consensus/utils/consensusserialization/block.go b/domain/consensus/utils/consensushashing/block.go similarity index 77% rename from domain/consensus/utils/consensusserialization/block.go rename to domain/consensus/utils/consensushashing/block.go index bec976620..be4c2c8f2 100644 --- a/domain/consensus/utils/consensusserialization/block.go +++ b/domain/consensus/utils/consensushashing/block.go @@ -1,8 +1,10 @@ -package consensusserialization +package consensushashing import ( "io" + "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/pkg/errors" @@ -33,14 +35,14 @@ func serializeHeader(w io.Writer, header *externalapi.DomainBlockHeader) error { timestamp := header.TimeInMilliseconds numParents := len(header.ParentHashes) - if err := writeElements(w, header.Version, uint64(numParents)); err != nil { + if err := serialization.WriteElements(w, header.Version, uint64(numParents)); err != nil { return err } for _, hash := range header.ParentHashes { - if err := WriteElement(w, hash); err != nil { + if err := serialization.WriteElement(w, hash); err != nil { return err } } - return writeElements(w, &header.HashMerkleRoot, &header.AcceptedIDMerkleRoot, &header.UTXOCommitment, timestamp, + return serialization.WriteElements(w, &header.HashMerkleRoot, &header.AcceptedIDMerkleRoot, &header.UTXOCommitment, timestamp, header.Bits, header.Nonce) } diff --git a/domain/consensus/utils/consensusserialization/transaction.go b/domain/consensus/utils/consensushashing/transaction.go similarity index 94% rename from domain/consensus/utils/consensusserialization/transaction.go rename to domain/consensus/utils/consensushashing/transaction.go index e1a8b6fb9..182f00136 100644 --- a/domain/consensus/utils/consensusserialization/transaction.go +++ b/domain/consensus/utils/consensushashing/transaction.go @@ -1,8 +1,10 @@ -package consensusserialization +package consensushashing import ( "io" + "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" @@ -39,7 +41,7 @@ func TransactionHashForSigning(tx *externalapi.DomainTransaction, hashType uint3 panic(errors.Wrap(err, "TransactionHashForSigning() failed. this should never fail for structurally-valid transactions")) } - err = WriteElement(writer, hashType) + err = serialization.WriteElement(writer, hashType) if err != nil { panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) } @@ -65,7 +67,6 @@ func TransactionHash(tx *externalapi.DomainTransaction) *externalapi.DomainHash // TransactionID generates the Hash for the transaction without the signature script and payload field. func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransactionID { - // If transaction ID is already cached, return it if tx.ID != nil { return tx.ID @@ -98,7 +99,7 @@ func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodi } count := uint64(len(tx.Inputs)) - err = WriteElement(w, count) + err = serialization.WriteElement(w, count) if err != nil { return err } @@ -111,7 +112,7 @@ func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodi } count = uint64(len(tx.Outputs)) - err = WriteElement(w, count) + err = serialization.WriteElement(w, count) if err != nil { return err } @@ -138,7 +139,7 @@ func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodi return err } - err = WriteElement(w, &tx.PayloadHash) + err = serialization.WriteElement(w, &tx.PayloadHash) if err != nil { return err } @@ -189,7 +190,7 @@ func writeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error { func writeVarBytes(w io.Writer, data []byte) error { dataLength := uint64(len(data)) - err := WriteElement(w, dataLength) + err := serialization.WriteElement(w, dataLength) if err != nil { return err } diff --git a/domain/consensus/utils/merkle/merkle.go b/domain/consensus/utils/merkle/merkle.go index 5a86d0dcf..432c4e3b4 100644 --- a/domain/consensus/utils/merkle/merkle.go +++ b/domain/consensus/utils/merkle/merkle.go @@ -4,7 +4,7 @@ import ( "math" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/pkg/errors" ) @@ -48,7 +48,7 @@ func hashMerkleBranches(left, right *externalapi.DomainHash) *externalapi.Domain func CalculateHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash { txHashes := make([]*externalapi.DomainHash, len(transactions)) for i, tx := range transactions { - txHashes[i] = consensusserialization.TransactionHash(tx) + txHashes[i] = consensushashing.TransactionHash(tx) } return merkleRoot(txHashes) } @@ -62,7 +62,7 @@ func CalculateIDMerkleRoot(transactions []*externalapi.DomainTransaction) *exter txIDs := make([]*externalapi.DomainHash, len(transactions)) for i, tx := range transactions { - txIDs[i] = (*externalapi.DomainHash)(consensusserialization.TransactionID(tx)) + txIDs[i] = (*externalapi.DomainHash)(consensushashing.TransactionID(tx)) } return merkleRoot(txIDs) } diff --git a/domain/consensus/utils/mining/solve.go b/domain/consensus/utils/mining/solve.go index 844e3475b..39b969d2f 100644 --- a/domain/consensus/utils/mining/solve.go +++ b/domain/consensus/utils/mining/solve.go @@ -5,7 +5,7 @@ import ( "math/rand" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" utilsMath "github.com/kaspanet/kaspad/domain/consensus/utils/math" "github.com/pkg/errors" @@ -17,7 +17,7 @@ func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) { for i := rd.Uint64(); i < math.MaxUint64; i++ { block.Header.Nonce = i - hash := consensusserialization.BlockHash(block) + hash := consensushashing.BlockHash(block) if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { return } diff --git a/domain/consensus/utils/consensusserialization/common.go b/domain/consensus/utils/serialization/common.go similarity index 88% rename from domain/consensus/utils/consensusserialization/common.go rename to domain/consensus/utils/serialization/common.go index b76446503..ce15bcc3d 100644 --- a/domain/consensus/utils/consensusserialization/common.go +++ b/domain/consensus/utils/serialization/common.go @@ -1,4 +1,4 @@ -package consensusserialization +package serialization import ( "io" @@ -97,9 +97,9 @@ func WriteElement(w io.Writer, element interface{}) error { return errors.Wrapf(errNoEncodingForType, "couldn't find a way to write type %T", element) } -// writeElements writes multiple items to w. It is equivalent to multiple +// WriteElements writes multiple items to w. It is equivalent to multiple // calls to writeElement. -func writeElements(w io.Writer, elements ...interface{}) error { +func WriteElements(w io.Writer, elements ...interface{}) error { for _, element := range elements { err := WriteElement(w, element) if err != nil { @@ -109,9 +109,9 @@ func writeElements(w io.Writer, elements ...interface{}) error { return nil } -// readElement reads the next sequence of bytes from r using little endian +// ReadElement reads the next sequence of bytes from r using little endian // depending on the concrete type of element pointed to. -func readElement(r io.Reader, element interface{}) error { +func ReadElement(r io.Reader, element interface{}) error { // Attempt to read the element based on the concrete type via fast // type assertions first. switch e := element.(type) { @@ -174,11 +174,11 @@ func readElement(r io.Reader, element interface{}) error { return errors.Wrapf(errNoEncodingForType, "couldn't find a way to read type %T", element) } -// readElements reads multiple items from r. It is equivalent to multiple -// calls to readElement. -func readElements(r io.Reader, elements ...interface{}) error { +// ReadElements reads multiple items from r. It is equivalent to multiple +// calls to ReadElement. +func ReadElements(r io.Reader, elements ...interface{}) error { for _, element := range elements { - err := readElement(r, element) + err := ReadElement(r, element) if err != nil { return err } diff --git a/domain/consensus/utils/testutils/create_transaction.go b/domain/consensus/utils/testutils/create_transaction.go index 7fa6367d3..57d585de9 100644 --- a/domain/consensus/utils/testutils/create_transaction.go +++ b/domain/consensus/utils/testutils/create_transaction.go @@ -2,7 +2,7 @@ package testutils import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" ) @@ -19,7 +19,7 @@ func CreateTransaction(txToSpend *externalapi.DomainTransaction) (*externalapi.D } input := &externalapi.DomainTransactionInput{ PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: *consensusserialization.TransactionID(txToSpend), + TransactionID: *consensushashing.TransactionID(txToSpend), Index: 0, }, SignatureScript: signatureScript, diff --git a/domain/consensus/utils/txscript/reference_test.go b/domain/consensus/utils/txscript/reference_test.go index 1ff595b32..188535e41 100644 --- a/domain/consensus/utils/txscript/reference_test.go +++ b/domain/consensus/utils/txscript/reference_test.go @@ -15,7 +15,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/logger" @@ -231,7 +231,7 @@ func createSpendingTx(sigScript, scriptPubKey []byte) *externalapi.DomainTransac } outpoint = externalapi.DomainOutpoint{ - TransactionID: *consensusserialization.TransactionID(coinbaseTx), + TransactionID: *consensushashing.TransactionID(coinbaseTx), Index: 0, } input = &externalapi.DomainTransactionInput{ diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index 7615c2544..acbaaf5a4 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -9,7 +9,7 @@ import ( "fmt" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/pkg/errors" ) @@ -361,7 +361,7 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *external // The final hash is the double sha256 of both the serialized modified // transaction and the hash type (encoded as a 4-byte little-endian // value) appended. - return consensusserialization.TransactionHashForSigning(&txCopy, uint32(hashType)), nil + return consensushashing.TransactionHashForSigning(&txCopy, uint32(hashType)), nil } // asSmallInt returns the passed opcode, which must be true according to diff --git a/domain/consensus/utils/consensusserialization/utxo.go b/domain/consensus/utils/utxo/serialization.go similarity index 84% rename from domain/consensus/utils/consensusserialization/utxo.go rename to domain/consensus/utils/utxo/serialization.go index 3ebb4cb1e..c7367da36 100644 --- a/domain/consensus/utils/consensusserialization/utxo.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -1,10 +1,13 @@ -package consensusserialization +package utxo import ( "bytes" - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "io" + "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" + + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -51,7 +54,7 @@ func serializeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error return err } - err = WriteElement(w, outpoint.Index) + err = serialization.WriteElement(w, outpoint.Index) if err != nil { return errors.WithStack(err) } @@ -78,7 +81,7 @@ func deserializeOutpoint(r io.Reader) (*externalapi.DomainOutpoint, error) { } var index uint32 - err = readElement(r, &index) + err = serialization.ReadElement(r, &index) if err != nil { return nil, err } @@ -90,13 +93,13 @@ func deserializeOutpoint(r io.Reader) (*externalapi.DomainOutpoint, error) { } func serializeUTXOEntry(w io.Writer, entry *externalapi.UTXOEntry) error { - err := writeElements(w, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase) + err := serialization.WriteElements(w, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase) if err != nil { return err } count := uint64(len(entry.ScriptPublicKey)) - err = WriteElement(w, count) + err = serialization.WriteElement(w, count) if err != nil { return err } @@ -111,13 +114,13 @@ func serializeUTXOEntry(w io.Writer, entry *externalapi.UTXOEntry) error { func deserializeUTXOEntry(r io.Reader) (*externalapi.UTXOEntry, error) { entry := &externalapi.UTXOEntry{} - err := readElements(r, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase) + err := serialization.ReadElements(r, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase) if err != nil { return nil, err } count := uint64(len(entry.ScriptPublicKey)) - err = readElement(r, count) + err = serialization.ReadElement(r, count) if err != nil { return nil, err } diff --git a/domain/consensus/utils/consensusserialization/utxo_test.go b/domain/consensus/utils/utxo/serialization_test.go similarity index 96% rename from domain/consensus/utils/consensusserialization/utxo_test.go rename to domain/consensus/utils/utxo/serialization_test.go index 2d91a904c..3f8808c53 100644 --- a/domain/consensus/utils/consensusserialization/utxo_test.go +++ b/domain/consensus/utils/utxo/serialization_test.go @@ -1,4 +1,4 @@ -package consensusserialization +package utxo import ( "encoding/hex" diff --git a/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go b/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go index 98545f791..9ad870383 100644 --- a/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go +++ b/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go @@ -3,7 +3,7 @@ package utxoalgebra import ( "reflect" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" @@ -22,7 +22,7 @@ func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.Domai } isCoinbase := transactionhelper.IsCoinBase(transaction) - transactionID := *consensusserialization.TransactionID(transaction) + transactionID := *consensushashing.TransactionID(transaction) for i, output := range transaction.Outputs { outpoint := &externalapi.DomainOutpoint{ TransactionID: transactionID, diff --git a/domain/consensus/utils/utxoserialization/utxo.go b/domain/consensus/utils/utxoserialization/utxo.go index 86008237c..3d3b89e31 100644 --- a/domain/consensus/utils/utxoserialization/utxo.go +++ b/domain/consensus/utils/utxoserialization/utxo.go @@ -2,7 +2,7 @@ package utxoserialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" ) // ReadOnlyUTXOSetToProtoUTXOSet converts ReadOnlyUTXOSetIterator to ProtoUTXOSet @@ -17,7 +17,7 @@ func ReadOnlyUTXOSetToProtoUTXOSet(iter model.ReadOnlyUTXOSetIterator) (*ProtoUT return nil, err } - serializedUTXOBytes, err := consensusserialization.SerializeUTXO(entry, outpoint) + serializedUTXOBytes, err := utxo.SerializeUTXO(entry, outpoint) if err != nil { return nil, err } diff --git a/domain/dagconfig/genesis_test.go b/domain/dagconfig/genesis_test.go index 5c8607df3..dd6892757 100644 --- a/domain/dagconfig/genesis_test.go +++ b/domain/dagconfig/genesis_test.go @@ -7,14 +7,14 @@ package dagconfig import ( "testing" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" ) // TestGenesisBlock tests the genesis block of the main network for validity by // checking the encoded hash. func TestGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(MainnetParams.GenesisBlock) + hash := consensushashing.BlockHash(MainnetParams.GenesisBlock) if *MainnetParams.GenesisHash != *hash { t.Fatalf("TestGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, MainnetParams.GenesisHash) @@ -25,7 +25,7 @@ func TestGenesisBlock(t *testing.T) { // validity by checking the hash. func TestTestnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(TestnetParams.GenesisBlock) + hash := consensushashing.BlockHash(TestnetParams.GenesisBlock) if *TestnetParams.GenesisHash != *hash { t.Fatalf("TestTestnetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, @@ -37,7 +37,7 @@ func TestTestnetGenesisBlock(t *testing.T) { // for validity by checking the hash. func TestSimnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(SimnetParams.GenesisBlock) + hash := consensushashing.BlockHash(SimnetParams.GenesisBlock) if *SimnetParams.GenesisHash != *hash { t.Fatalf("TestSimnetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, @@ -49,7 +49,7 @@ func TestSimnetGenesisBlock(t *testing.T) { // for validity by checking the encoded hash. func TestDevnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(DevnetParams.GenesisBlock) + hash := consensushashing.BlockHash(DevnetParams.GenesisBlock) if *DevnetParams.GenesisHash != *hash { t.Fatalf("TestDevnetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, diff --git a/domain/miningmanager/blocktemplatebuilder/txselection.go b/domain/miningmanager/blocktemplatebuilder/txselection.go index 1f8fc773d..6ebfec689 100644 --- a/domain/miningmanager/blocktemplatebuilder/txselection.go +++ b/domain/miningmanager/blocktemplatebuilder/txselection.go @@ -1,12 +1,13 @@ package blocktemplatebuilder import ( - consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" - "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "math" "math/rand" "sort" + + consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" ) const ( @@ -103,7 +104,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx) if txsForBlockTemplate.totalMass+selectedTx.Mass < txsForBlockTemplate.totalMass || txsForBlockTemplate.totalMass+selectedTx.Mass > btb.policy.BlockMaxMass { log.Tracef("Tx %s would exceed the max block mass. "+ - "As such, stopping.", consensusserialization.TransactionID(tx)) + "As such, stopping.", consensushashing.TransactionID(tx)) break } @@ -121,7 +122,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx) log.Tracef("Tx %s would exceed the gas limit in "+ "subnetwork %s. Removing all remaining txs from this "+ "subnetwork.", - consensusserialization.TransactionID(tx), subnetworkID) + consensushashing.TransactionID(tx), subnetworkID) for _, candidateTx := range candidateTxs { // candidateTxs are ordered by subnetwork, so we can safely assume // that transactions after subnetworkID will not be relevant. @@ -146,7 +147,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx) txsForBlockTemplate.totalFees += selectedTx.Fee log.Tracef("Adding tx %s (feePerMegaGram %d)", - consensusserialization.TransactionID(tx), selectedTx.Fee*1e6/selectedTx.Mass) + consensushashing.TransactionID(tx), selectedTx.Fee*1e6/selectedTx.Mass) markCandidateTxForDeletion(selectedTx) } diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 908ffb5f4..e35b79589 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -16,7 +16,7 @@ import ( consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" miningmanagermodel "github.com/kaspanet/kaspad/domain/miningmanager/model" "github.com/kaspanet/kaspad/infrastructure/logger" @@ -148,7 +148,7 @@ type orphanTx struct { // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) removeOrphan(tx *consensusexternalapi.DomainTransaction, removeRedeemers bool) { // Nothing to do if passed tx is not an orphan. - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) otx, exists := mp.orphans[*txID] if !exists { return @@ -249,7 +249,7 @@ func (mp *mempool) addOrphan(tx *consensusexternalapi.DomainTransaction) { // This will periodically remove any expired orphans and evict a random // orphan if space is still needed. mp.limitNumOrphans() - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) mp.orphans[*txID] = &orphanTx{ tx: tx, expiration: mstime.Now().Add(orphanTTL), @@ -262,7 +262,7 @@ func (mp *mempool) addOrphan(tx *consensusexternalapi.DomainTransaction) { mp.orphansByPrev[txIn.PreviousOutpoint][*txID] = tx } - log.Debugf("Stored orphan transaction %s (total: %d)", consensusserialization.TransactionID(tx), + log.Debugf("Stored orphan transaction %s (total: %d)", consensushashing.TransactionID(tx), len(mp.orphans)) } @@ -358,7 +358,7 @@ func (mp *mempool) haveTransaction(txID *consensusexternalapi.DomainTransactionI // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) removeBlockTransactionsFromPool(txs []*consensusexternalapi.DomainTransaction) error { for _, tx := range txs[transactionhelper.CoinbaseTransactionIndex+1:] { - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) if _, exists := mp.fetchTxDesc(txID); !exists { continue @@ -378,7 +378,7 @@ func (mp *mempool) removeBlockTransactionsFromPool(txs []*consensusexternalapi.D // // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) removeTransactionAndItsChainedTransactions(tx *consensusexternalapi.DomainTransaction) error { - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) // Remove any transactions which rely on this one. for i := uint32(0); i < uint32(len(tx.Outputs)); i++ { prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *txID, Index: i} @@ -412,7 +412,7 @@ func (mp *mempool) cleanTransactionFromSets(tx *consensusexternalapi.DomainTrans return err } - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) delete(mp.pool, *txID) delete(mp.chainedTransactions, *txID) @@ -425,7 +425,7 @@ func (mp *mempool) cleanTransactionFromSets(tx *consensusexternalapi.DomainTrans // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) updateBlockTransactionChainedTransactions(tx *consensusexternalapi.DomainTransaction) { - prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx)} + prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)} for txOutIdx := range tx.Outputs { // Skip to the next available output if there are none. prevOut.Index = uint32(txOutIdx) @@ -439,7 +439,7 @@ func (mp *mempool) updateBlockTransactionChainedTransactions(tx *consensusextern if txDesc.depCount == 0 { // Transaction may be already removed by recursive calls, if removeRedeemers is true. // So avoid moving it into main pool - txDescID := consensusserialization.TransactionID(txDesc.DomainTransaction) + txDescID := consensushashing.TransactionID(txDesc.DomainTransaction) if _, ok := mp.chainedTransactions[*txDescID]; ok { delete(mp.chainedTransactions, *txDescID) mp.pool[*txDescID] = txDesc @@ -453,7 +453,7 @@ func (mp *mempool) updateBlockTransactionChainedTransactions(tx *consensusextern // // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) removeChainTransaction(tx *consensusexternalapi.DomainTransaction) { - delete(mp.chainedTransactions, *consensusserialization.TransactionID(tx)) + delete(mp.chainedTransactions, *consensushashing.TransactionID(tx)) for _, txIn := range tx.Inputs { delete(mp.chainedTransactionByPreviousOutpoint, txIn.PreviousOutpoint) } @@ -467,10 +467,10 @@ func (mp *mempool) removeChainTransaction(tx *consensusexternalapi.DomainTransac // // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) removeDoubleSpends(tx *consensusexternalapi.DomainTransaction) error { - txID := *consensusserialization.TransactionID(tx) + txID := *consensushashing.TransactionID(tx) for _, txIn := range tx.Inputs { if txRedeemer, ok := mp.mempoolUTXOSet.poolTransactionBySpendingOutpoint(txIn.PreviousOutpoint); ok { - if !(*consensusserialization.TransactionID(txRedeemer) == txID) { + if !(*consensushashing.TransactionID(txRedeemer) == txID) { err := mp.removeTransactionAndItsChainedTransactions(txRedeemer) if err != nil { return err @@ -493,7 +493,7 @@ func (mp *mempool) addTransaction(tx *consensusexternalapi.DomainTransaction, ma DomainTransaction: tx, depCount: len(parentsInPool), } - txID := *consensusserialization.TransactionID(tx) + txID := *consensushashing.TransactionID(tx) if len(parentsInPool) == 0 { mp.pool[txID] = txDescriptor @@ -523,7 +523,7 @@ func (mp *mempool) checkPoolDoubleSpend(tx *consensusexternalapi.DomainTransacti if txR, exists := mp.mempoolUTXOSet.poolTransactionBySpendingOutpoint(txIn.PreviousOutpoint); exists { str := fmt.Sprintf("output %s already spent by "+ "transaction %s in the memory pool", - txIn.PreviousOutpoint, consensusserialization.TransactionID(txR)) + txIn.PreviousOutpoint, consensushashing.TransactionID(txR)) return txRuleError(RejectDuplicate, str) } } @@ -557,7 +557,7 @@ func (mp *mempool) fetchTxDesc(txID *consensusexternalapi.DomainTransactionID) ( func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransaction, rejectDupOrphans bool) ( []*consensusexternalapi.DomainOutpoint, *txDescriptor, error) { - txID := consensusserialization.TransactionID(tx) + txID := consensushashing.TransactionID(tx) // Don't accept the transaction if it already exists in the pool. This // applies to orphan transactions as well when the reject duplicate @@ -687,7 +687,7 @@ func (mp *mempool) processOrphans(acceptedTx *consensusexternalapi.DomainTransac firstElement := processList.Remove(processList.Front()) processItem := firstElement.(*consensusexternalapi.DomainTransaction) - prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(processItem)} + prevOut := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(processItem)} for txOutIdx := range processItem.Outputs { // Look up all orphans that redeem the output that is // now available. This will typically only be one, but @@ -767,7 +767,7 @@ func (mp *mempool) processOrphans(acceptedTx *consensusexternalapi.DomainTransac // // This function is safe for concurrent access. func (mp *mempool) ValidateAndInsertTransaction(tx *consensusexternalapi.DomainTransaction, allowOrphan bool) error { - log.Tracef("Processing transaction %s", consensusserialization.TransactionID(tx)) + log.Tracef("Processing transaction %s", consensushashing.TransactionID(tx)) // Protect concurrent access. mp.mtx.Lock() @@ -809,7 +809,7 @@ func (mp *mempool) ValidateAndInsertTransaction(tx *consensusexternalapi.DomainT // which is not really always the case. str := fmt.Sprintf("orphan transaction %s references "+ "outputs of unknown or fully-spent "+ - "transaction %s", consensusserialization.TransactionID(tx), missingParents[0]) + "transaction %s", consensushashing.TransactionID(tx), missingParents[0]) return txRuleError(RejectDuplicate, str) } @@ -878,7 +878,7 @@ func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.Domain for _, tx := range txs[transactionhelper.CoinbaseTransactionIndex+1:] { err := mp.removeDoubleSpends(tx) if err != nil { - log.Infof("Failed removing tx from mempool: %s, '%s'", consensusserialization.TransactionID(tx), err) + log.Infof("Failed removing tx from mempool: %s, '%s'", consensushashing.TransactionID(tx), err) } mp.removeOrphan(tx, false) acceptedOrphans := mp.processOrphans(tx) @@ -898,7 +898,7 @@ func (mp *mempool) RemoveTransactions(txs []*consensusexternalapi.DomainTransact for _, tx := range txs { err := mp.removeDoubleSpends(tx) if err != nil { - log.Infof("Failed removing tx from mempool: %s, '%s'", consensusserialization.TransactionID(tx), err) + log.Infof("Failed removing tx from mempool: %s, '%s'", consensushashing.TransactionID(tx), err) } mp.removeOrphan(tx, true) } diff --git a/domain/miningmanager/mempool/mempool_utxoset.go b/domain/miningmanager/mempool/mempool_utxoset.go index 6b59fcd7a..e13c71c4e 100644 --- a/domain/miningmanager/mempool/mempool_utxoset.go +++ b/domain/miningmanager/mempool/mempool_utxoset.go @@ -4,7 +4,7 @@ import ( "math" consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/pkg/errors" ) @@ -42,7 +42,7 @@ func (mpus *mempoolUTXOSet) checkExists(tx *consensusexternalapi.DomainTransacti } // Check if it creates an already existing UTXO - outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx)} + outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)} for i := range tx.Outputs { outpoint.Index = uint32(i) if _, exists := mpus.poolUnspentOutputs[outpoint]; exists { @@ -57,13 +57,13 @@ func (mpus *mempoolUTXOSet) checkExists(tx *consensusexternalapi.DomainTransacti func (mpus *mempoolUTXOSet) addTx(tx *consensusexternalapi.DomainTransaction) error { for _, txIn := range tx.Inputs { if existingTx, exists := mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint]; exists { - return errors.Errorf("outpoint %s is already used by %s", txIn.PreviousOutpoint, consensusserialization.TransactionID(existingTx)) + return errors.Errorf("outpoint %s is already used by %s", txIn.PreviousOutpoint, consensushashing.TransactionID(existingTx)) } mpus.transactionByPreviousOutpoint[txIn.PreviousOutpoint] = tx } for i, txOut := range tx.Outputs { - outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx), Index: uint32(i)} + outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx), Index: uint32(i)} if _, exists := mpus.poolUnspentOutputs[outpoint]; exists { return errors.Errorf("outpoint %s already exists", outpoint) } @@ -87,7 +87,7 @@ func (mpus *mempoolUTXOSet) removeTx(tx *consensusexternalapi.DomainTransaction) delete(mpus.transactionByPreviousOutpoint, txIn.PreviousOutpoint) } - outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensusserialization.TransactionID(tx)} + outpoint := consensusexternalapi.DomainOutpoint{TransactionID: *consensushashing.TransactionID(tx)} for i := range tx.Outputs { outpoint.Index = uint32(i) if _, exists := mpus.poolUnspentOutputs[outpoint]; !exists { diff --git a/testing/integration/basic_sync_test.go b/testing/integration/basic_sync_test.go index 4dbb05517..0050ebd8c 100644 --- a/testing/integration/basic_sync_test.go +++ b/testing/integration/basic_sync_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/app/appmessage" ) @@ -37,7 +37,7 @@ func TestIntegrationBasicSync(t *testing.T) { t.Fatalf("Timeout waiting for block added notification on node directly connected to miner") } - blockHash := consensusserialization.BlockHash(block) + blockHash := consensushashing.BlockHash(block) if *header.BlockHash() != *blockHash { t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash()) } @@ -48,7 +48,7 @@ func TestIntegrationBasicSync(t *testing.T) { t.Fatalf("Timeout waiting for block added notification on node indirectly connected to miner") } - blockHash = consensusserialization.BlockHash(block) + blockHash = consensushashing.BlockHash(block) if *header.BlockHash() != *blockHash { t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash()) } diff --git a/testing/integration/mining_test.go b/testing/integration/mining_test.go index 8e2281c82..6b6fa77b1 100644 --- a/testing/integration/mining_test.go +++ b/testing/integration/mining_test.go @@ -7,7 +7,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/util" @@ -18,7 +18,7 @@ func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock { initialNonce := rand.Uint64() for i := initialNonce; i != initialNonce-1; i++ { block.Header.Nonce = i - hash := consensusserialization.BlockHash(block) + hash := consensushashing.BlockHash(block) if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { return block } diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 1975a5700..2e326e14a 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -9,7 +9,7 @@ import ( "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" @@ -86,7 +86,7 @@ func waitForPayeeToReceiveBlock(t *testing.T, payeeBlockAddedChan chan *appmessa func generateTx(t *testing.T, firstBlockCoinbase *externalapi.DomainTransaction, payer, payee *appHarness) *appmessage.MsgTx { txIns := make([]*appmessage.TxIn, 1) - txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensusserialization.TransactionID(firstBlockCoinbase), 0), []byte{}) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensushashing.TransactionID(firstBlockCoinbase), 0), []byte{}) payeeAddress, err := util.DecodeAddress(payee.miningAddress, util.Bech32PrefixKaspaSim) if err != nil { From a585f327632091b7049b49750a7144bc1864d21a Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 3 Dec 2020 13:24:24 +0200 Subject: [PATCH 107/351] [NOD-1551] Make UTXODiff immutable + skip cloning it in datastore (#1167) * [NOD-1551] Make UTXO-Diff implemented fully in utils/utxo * [NOD-1551] Fixes everywhere except database * [NOD-1551] Fix database * [NOD-1551] Add comments * [NOD-1551] Partial commit * [NOD-1551] Comlete making UTXOEntry immutable + don't clone it in UTXOCollectionClone * [NOD-1551] Rename ToUnmutable -> ToImmutable * [NOD-1551] Track immutable references generated from mutable UTXODiff, and invalidate them if the mutable one changed * [NOD-1551] Clone scriptPubKey in NewUTXOEntry * [NOD-1551] Remove redundant code * [NOD-1551] Remove redundant call for .CloneMutable and then .ToImmutable * [NOD-1551] Make utxoEntry pointert-receiver + clone ScriptPubKey in getter --- .../database/serialization/utxo_collection.go | 25 +- .../database/serialization/utxo_diff.go | 26 +- .../database/serialization/utxo_entry.go | 20 +- .../consensusstatestore.go | 2 +- .../consensusstatestore/utxo.go | 59 +- .../consensusstatestore/utxo_serialization.go | 4 +- .../utxodiffstore/utxodiffstore.go | 29 +- .../model/externalapi/transaction.go | 4 +- .../consensus/model/externalapi/utxoentry.go | 37 +- ...face_datastructures_consensusstatestore.go | 4 +- .../interface_datastructures_utxodiffstore.go | 4 +- ...terface_processes_consensusstatemanager.go | 2 +- domain/consensus/model/readonlyutxoset.go | 4 +- .../model/testapi/test_block_builder.go | 2 +- .../consensus/model/testapi/test_consensus.go | 3 +- .../testapi/test_consensus_state_manager.go | 2 +- domain/consensus/model/utxodiff.go | 85 +-- .../blockbuilder/test_block_builder.go | 4 +- .../calculate_past_utxo.go | 29 +- .../consensusstatemanager/multisets.go | 12 +- .../populate_tx_with_utxo_entries.go | 7 +- .../resolve_block_status.go | 5 +- .../set_pruning_utxo_set.go | 4 +- .../test_consensus_state_manager.go | 2 +- .../consensusstatemanager/update_virtual.go | 5 +- .../consensusstatemanager/utxo_diffs.go | 2 +- .../verify_and_build_utxo.go | 4 +- .../processes/transactionvalidator/mass.go | 4 +- .../transaction_in_context.go | 12 +- domain/consensus/test_consensus.go | 2 +- domain/consensus/utils/utxo/diff_algebra.go | 252 +++++++ .../consensus/utils/utxo/diff_algebra_test.go | 616 ++++++++++++++++++ .../utils/utxo/immutable_utxo_diff.go | 86 +++ .../consensus/utils/utxo/mutable_utxo_diff.go | 160 +++++ domain/consensus/utils/utxo/serialization.go | 38 +- .../utils/utxo/serialization_test.go | 7 +- .../consensus/utils/utxo/utxo_collection.go | 95 +++ domain/consensus/utils/utxo/utxo_entry.go | 40 ++ domain/consensus/utils/utxo/utxo_iterator.go | 33 +- .../utils/utxo/utxo_iterator_with_diff.go | 25 +- .../utxo/utxoalgebra/collection_helpers.go | 50 -- .../utils/utxo/utxoalgebra/diff_algebra.go | 253 ------- .../utxo/utxoalgebra/diff_algebra_test.go | 608 ----------------- .../utils/utxo/utxoalgebra/diff_helpers.go | 76 --- .../miningmanager/mempool/mempool_utxoset.go | 14 +- domain/miningmanager/mempool/policy.go | 2 +- 46 files changed, 1495 insertions(+), 1264 deletions(-) create mode 100644 domain/consensus/utils/utxo/diff_algebra.go create mode 100644 domain/consensus/utils/utxo/diff_algebra_test.go create mode 100644 domain/consensus/utils/utxo/immutable_utxo_diff.go create mode 100644 domain/consensus/utils/utxo/mutable_utxo_diff.go create mode 100644 domain/consensus/utils/utxo/utxo_collection.go create mode 100644 domain/consensus/utils/utxo/utxo_entry.go delete mode 100644 domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go delete mode 100644 domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go delete mode 100644 domain/consensus/utils/utxo/utxoalgebra/diff_algebra_test.go delete mode 100644 domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go diff --git a/domain/consensus/database/serialization/utxo_collection.go b/domain/consensus/database/serialization/utxo_collection.go index 81e51496c..703364f74 100644 --- a/domain/consensus/database/serialization/utxo_collection.go +++ b/domain/consensus/database/serialization/utxo_collection.go @@ -2,32 +2,39 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" ) -func utxoCollectionToDBUTXOCollection(utxoCollection model.UTXOCollection) []*DbUtxoCollectionItem { - items := make([]*DbUtxoCollectionItem, len(utxoCollection)) +func utxoCollectionToDBUTXOCollection(utxoCollection model.UTXOCollection) ([]*DbUtxoCollectionItem, error) { + items := make([]*DbUtxoCollectionItem, utxoCollection.Len()) i := 0 - for outpoint, entry := range utxoCollection { - outpointCopy := outpoint + utxoIterator := utxoCollection.Iterator() + for utxoIterator.Next() { + outpoint, entry, err := utxoIterator.Get() + if err != nil { + return nil, err + } + items[i] = &DbUtxoCollectionItem{ - Outpoint: DomainOutpointToDbOutpoint(&outpointCopy), + Outpoint: DomainOutpointToDbOutpoint(outpoint), UtxoEntry: UTXOEntryToDBUTXOEntry(entry), } i++ } - return items + return items, nil } func dbUTXOCollectionToUTXOCollection(items []*DbUtxoCollectionItem) (model.UTXOCollection, error) { - collection := make(model.UTXOCollection) + utxoMap := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, len(items)) for _, item := range items { outpoint, err := DbOutpointToDomainOutpoint(item.Outpoint) if err != nil { return nil, err } - collection[*outpoint] = DBUTXOEntryToUTXOEntry(item.UtxoEntry) + utxoMap[*outpoint] = DBUTXOEntryToUTXOEntry(item.UtxoEntry) } - return collection, nil + return utxo.NewUTXOCollection(utxoMap), nil } diff --git a/domain/consensus/database/serialization/utxo_diff.go b/domain/consensus/database/serialization/utxo_diff.go index 0d395fa7f..ec2cd8585 100644 --- a/domain/consensus/database/serialization/utxo_diff.go +++ b/domain/consensus/database/serialization/utxo_diff.go @@ -2,18 +2,29 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" ) // UTXODiffToDBUTXODiff converts UTXODiff to DbUtxoDiff -func UTXODiffToDBUTXODiff(diff *model.UTXODiff) *DbUtxoDiff { - return &DbUtxoDiff{ - ToAdd: utxoCollectionToDBUTXOCollection(diff.ToAdd), - ToRemove: utxoCollectionToDBUTXOCollection(diff.ToRemove), +func UTXODiffToDBUTXODiff(diff model.UTXODiff) (*DbUtxoDiff, error) { + toAdd, err := utxoCollectionToDBUTXOCollection(diff.ToAdd()) + if err != nil { + return nil, err } + + toRemove, err := utxoCollectionToDBUTXOCollection(diff.ToRemove()) + if err != nil { + return nil, err + } + + return &DbUtxoDiff{ + ToAdd: toAdd, + ToRemove: toRemove, + }, nil } // DBUTXODiffToUTXODiff converts DbUtxoDiff to UTXODiff -func DBUTXODiffToUTXODiff(diff *DbUtxoDiff) (*model.UTXODiff, error) { +func DBUTXODiffToUTXODiff(diff *DbUtxoDiff) (model.UTXODiff, error) { toAdd, err := dbUTXOCollectionToUTXOCollection(diff.ToAdd) if err != nil { return nil, err @@ -24,8 +35,5 @@ func DBUTXODiffToUTXODiff(diff *DbUtxoDiff) (*model.UTXODiff, error) { return nil, err } - return &model.UTXODiff{ - ToAdd: toAdd, - ToRemove: toRemove, - }, nil + return utxo.NewUTXODiffFromCollections(toAdd, toRemove) } diff --git a/domain/consensus/database/serialization/utxo_entry.go b/domain/consensus/database/serialization/utxo_entry.go index 4a17f6ee8..f8ec85873 100644 --- a/domain/consensus/database/serialization/utxo_entry.go +++ b/domain/consensus/database/serialization/utxo_entry.go @@ -2,24 +2,20 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" ) // UTXOEntryToDBUTXOEntry converts UTXOEntry to DbUtxoEntry -func UTXOEntryToDBUTXOEntry(utxoEntry *externalapi.UTXOEntry) *DbUtxoEntry { +func UTXOEntryToDBUTXOEntry(utxoEntry externalapi.UTXOEntry) *DbUtxoEntry { return &DbUtxoEntry{ - Amount: utxoEntry.Amount, - ScriptPublicKey: utxoEntry.ScriptPublicKey, - BlockBlueScore: utxoEntry.BlockBlueScore, - IsCoinbase: utxoEntry.IsCoinbase, + Amount: utxoEntry.Amount(), + ScriptPublicKey: utxoEntry.ScriptPublicKey(), + BlockBlueScore: utxoEntry.BlockBlueScore(), + IsCoinbase: utxoEntry.IsCoinbase(), } } // DBUTXOEntryToUTXOEntry convert DbUtxoEntry ro UTXOEntry -func DBUTXOEntryToUTXOEntry(dbUtxoEntry *DbUtxoEntry) *externalapi.UTXOEntry { - return &externalapi.UTXOEntry{ - Amount: dbUtxoEntry.Amount, - ScriptPublicKey: dbUtxoEntry.ScriptPublicKey, - BlockBlueScore: dbUtxoEntry.BlockBlueScore, - IsCoinbase: dbUtxoEntry.IsCoinbase, - } +func DBUTXOEntryToUTXOEntry(dbUtxoEntry *DbUtxoEntry) externalapi.UTXOEntry { + return utxo.NewUTXOEntry(dbUtxoEntry.Amount, dbUtxoEntry.ScriptPublicKey, dbUtxoEntry.IsCoinbase, dbUtxoEntry.BlockBlueScore) } diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go index c0ea148e4..b3a37a789 100644 --- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go +++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go @@ -9,7 +9,7 @@ import ( type consensusStateStore struct { tipsStaging []*externalapi.DomainHash virtualDiffParentsStaging []*externalapi.DomainHash - virtualUTXODiffStaging *model.UTXODiff + virtualUTXODiffStaging model.UTXODiff virtualUTXOSetStaging model.UTXOCollection tipsCache []*externalapi.DomainHash diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index 42ad6e029..6bc76113a 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -19,12 +19,12 @@ func utxoKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) { return utxoSetBucket.Key(serializedOutpoint), nil } -func (css *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error { +func (css *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff model.UTXODiff) error { if css.virtualUTXOSetStaging != nil { return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged") } - css.virtualUTXODiffStaging = virtualUTXODiff.Clone() + css.virtualUTXODiffStaging = virtualUTXODiff return nil } @@ -33,8 +33,13 @@ func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) return nil } - for toRemoveOutpoint := range css.virtualUTXODiffStaging.ToRemove { - dbKey, err := utxoKey(&toRemoveOutpoint) + toRemoveIterator := css.virtualUTXODiffStaging.ToRemove().Iterator() + for toRemoveIterator.Next() { + toRemoveOutpoint, _, err := toRemoveIterator.Get() + if err != nil { + return err + } + dbKey, err := utxoKey(toRemoveOutpoint) if err != nil { return err } @@ -44,8 +49,13 @@ func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) } } - for toAddOutpoint, toAddEntry := range css.virtualUTXODiffStaging.ToAdd { - dbKey, err := utxoKey(&toAddOutpoint) + toAddIterator := css.virtualUTXODiffStaging.ToAdd().Iterator() + for toAddIterator.Next() { + toAddOutpoint, toAddEntry, err := toAddIterator.Get() + if err != nil { + return err + } + dbKey, err := utxoKey(toAddOutpoint) if err != nil { return err } @@ -69,8 +79,13 @@ func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) e return nil } - for outpoint, utxoEntry := range css.virtualUTXOSetStaging { - dbKey, err := utxoKey(&outpoint) + iterator := css.virtualUTXOSetStaging.Iterator() + for iterator.Next() { + outpoint, utxoEntry, err := iterator.Get() + if err != nil { + return err + } + dbKey, err := utxoKey(outpoint) if err != nil { return err } @@ -90,7 +105,7 @@ func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) e } func (css *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( - *externalapi.UTXOEntry, error) { + externalapi.UTXOEntry, error) { if css.virtualUTXOSetStaging != nil { return css.utxoByOutpointFromStagedVirtualUTXOSet(outpoint) @@ -101,13 +116,13 @@ func (css *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoin func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( - *externalapi.UTXOEntry, error) { + externalapi.UTXOEntry, error) { if css.virtualUTXODiffStaging != nil { - if _, ok := css.virtualUTXODiffStaging.ToRemove[*outpoint]; ok { + if css.virtualUTXODiffStaging.ToRemove().Contains(outpoint) { return nil, errors.Errorf("outpoint was not found") } - if utxoEntry, ok := css.virtualUTXODiffStaging.ToAdd[*outpoint]; ok { + if utxoEntry, ok := css.virtualUTXODiffStaging.ToAdd().Get(outpoint); ok { return utxoEntry, nil } } @@ -126,8 +141,8 @@ func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContex } func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( - *externalapi.UTXOEntry, error) { - if utxoEntry, ok := css.virtualUTXOSetStaging[*outpoint]; ok { + externalapi.UTXOEntry, error) { + if utxoEntry, ok := css.virtualUTXOSetStaging.Get(outpoint); ok { return utxoEntry, nil } @@ -146,10 +161,10 @@ func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbCon outpoint *externalapi.DomainOutpoint) (bool, error) { if css.virtualUTXODiffStaging != nil { - if _, ok := css.virtualUTXODiffStaging.ToRemove[*outpoint]; ok { + if css.virtualUTXODiffStaging.ToRemove().Contains(outpoint) { return false, nil } - if _, ok := css.virtualUTXODiffStaging.ToAdd[*outpoint]; ok { + if _, ok := css.virtualUTXODiffStaging.ToAdd().Get(outpoint); ok { return true, nil } } @@ -163,8 +178,7 @@ func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbCon } func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool { - _, ok := css.virtualUTXOSetStaging[*outpoint] - return ok + return css.virtualUTXOSetStaging.Contains(outpoint) } func (css *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { @@ -193,7 +207,7 @@ func (u utxoSetIterator) Next() bool { return u.cursor.Next() } -func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { +func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) { key, err := u.cursor.Key() if err != nil { panic(err) @@ -222,18 +236,19 @@ func (css *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model return errors.New("cannot stage virtual UTXO set while virtual UTXO diff is staged") } - css.virtualUTXOSetStaging = make(model.UTXOCollection) + utxoMap := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry) for virtualUTXOSetIterator.Next() { outpoint, entry, err := virtualUTXOSetIterator.Get() if err != nil { return err } - if _, exists := css.virtualUTXOSetStaging[*outpoint]; exists { + if _, exists := utxoMap[*outpoint]; exists { return errors.Errorf("outpoint %s is found more than once in the given iterator", outpoint) } - css.virtualUTXOSetStaging[*outpoint] = entry + utxoMap[*outpoint] = entry } + css.virtualUTXOSetStaging = utxo.NewUTXOCollection(utxoMap) return nil } diff --git a/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go b/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go index f4853f043..6da8fab33 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go @@ -10,7 +10,7 @@ func serializeOutpoint(outpoint *externalapi.DomainOutpoint) ([]byte, error) { return proto.Marshal(serialization.DomainOutpointToDbOutpoint(outpoint)) } -func serializeUTXOEntry(entry *externalapi.UTXOEntry) ([]byte, error) { +func serializeUTXOEntry(entry externalapi.UTXOEntry) ([]byte, error) { return proto.Marshal(serialization.UTXOEntryToDBUTXOEntry(entry)) } @@ -24,7 +24,7 @@ func deserializeOutpoint(outpointBytes []byte) (*externalapi.DomainOutpoint, err return serialization.DbOutpointToDomainOutpoint(dbOutpoint) } -func deserializeUTXOEntry(entryBytes []byte) (*externalapi.UTXOEntry, error) { +func deserializeUTXOEntry(entryBytes []byte) (externalapi.UTXOEntry, error) { dbEntry := &serialization.DbUtxoEntry{} err := proto.Unmarshal(entryBytes, dbEntry) if err != nil { diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index ea0b14dcb..60d5e55e3 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -15,7 +15,7 @@ var utxoDiffChildBucket = dbkeys.MakeBucket([]byte("utxo-diff-children")) // utxoDiffStore represents a store of UTXODiffs type utxoDiffStore struct { - utxoDiffStaging map[externalapi.DomainHash]*model.UTXODiff + utxoDiffStaging map[externalapi.DomainHash]model.UTXODiff utxoDiffChildStaging map[externalapi.DomainHash]*externalapi.DomainHash toDelete map[externalapi.DomainHash]struct{} utxoDiffCache *lrucache.LRUCache @@ -25,7 +25,7 @@ type utxoDiffStore struct { // New instantiates a new UTXODiffStore func New(cacheSize int) model.UTXODiffStore { return &utxoDiffStore{ - utxoDiffStaging: make(map[externalapi.DomainHash]*model.UTXODiff), + utxoDiffStaging: make(map[externalapi.DomainHash]model.UTXODiff), utxoDiffChildStaging: make(map[externalapi.DomainHash]*externalapi.DomainHash), toDelete: make(map[externalapi.DomainHash]struct{}), utxoDiffCache: lrucache.New(cacheSize), @@ -34,8 +34,8 @@ func New(cacheSize int) model.UTXODiffStore { } // Stage stages the given utxoDiff for the given blockHash -func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) { - uds.utxoDiffStaging[*blockHash] = utxoDiff.Clone() +func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff model.UTXODiff, utxoDiffChild *externalapi.DomainHash) { + uds.utxoDiffStaging[*blockHash] = utxoDiff if utxoDiffChild != nil { uds.utxoDiffChildStaging[*blockHash] = utxoDiffChild.Clone() @@ -55,7 +55,7 @@ func (uds *utxoDiffStore) IsBlockHashStaged(blockHash *externalapi.DomainHash) b } func (uds *utxoDiffStore) Discard() { - uds.utxoDiffStaging = make(map[externalapi.DomainHash]*model.UTXODiff) + uds.utxoDiffStaging = make(map[externalapi.DomainHash]model.UTXODiff) uds.utxoDiffChildStaging = make(map[externalapi.DomainHash]*externalapi.DomainHash) uds.toDelete = make(map[externalapi.DomainHash]struct{}) } @@ -107,13 +107,13 @@ func (uds *utxoDiffStore) Commit(dbTx model.DBTransaction) error { } // UTXODiff gets the utxoDiff associated with the given blockHash -func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.UTXODiff, error) { +func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.UTXODiff, error) { if utxoDiff, ok := uds.utxoDiffStaging[*blockHash]; ok { - return utxoDiff.Clone(), nil + return utxoDiff, nil } if utxoDiff, ok := uds.utxoDiffCache.Get(blockHash); ok { - return utxoDiff.(*model.UTXODiff).Clone(), nil + return utxoDiff.(model.UTXODiff), nil } utxoDiffBytes, err := dbContext.Get(uds.utxoDiffHashAsKey(blockHash)) @@ -126,7 +126,7 @@ func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *external return nil, err } uds.utxoDiffCache.Add(blockHash, utxoDiff) - return utxoDiff.Clone(), nil + return utxoDiff, nil } // UTXODiffChild gets the utxoDiff child associated with the given blockHash @@ -187,16 +187,21 @@ func (uds *utxoDiffStore) utxoDiffChildHashAsKey(hash *externalapi.DomainHash) m return utxoDiffChildBucket.Key(hash[:]) } -func (uds *utxoDiffStore) serializeUTXODiff(utxoDiff *model.UTXODiff) ([]byte, error) { - dbUtxoDiff := serialization.UTXODiffToDBUTXODiff(utxoDiff) +func (uds *utxoDiffStore) serializeUTXODiff(utxoDiff model.UTXODiff) ([]byte, error) { + dbUtxoDiff, err := serialization.UTXODiffToDBUTXODiff(utxoDiff) + if err != nil { + return nil, err + } + bytes, err := proto.Marshal(dbUtxoDiff) if err != nil { return nil, errors.WithStack(err) } + return bytes, nil } -func (uds *utxoDiffStore) deserializeUTXODiff(utxoDiffBytes []byte) (*model.UTXODiff, error) { +func (uds *utxoDiffStore) deserializeUTXODiff(utxoDiffBytes []byte) (model.UTXODiff, error) { dbUTXODiff := &serialization.DbUtxoDiff{} err := proto.Unmarshal(utxoDiffBytes, dbUTXODiff) if err != nil { diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 83300d2c7..0ffdf0e48 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -62,7 +62,7 @@ type DomainTransactionInput struct { SignatureScript []byte Sequence uint64 - UTXOEntry *UTXOEntry + UTXOEntry UTXOEntry } // Clone returns a clone of DomainTransactionInput @@ -78,7 +78,7 @@ func (input *DomainTransactionInput) Clone() *DomainTransactionInput { PreviousOutpoint: *input.PreviousOutpoint.Clone(), SignatureScript: signatureScriptClone, Sequence: input.Sequence, - UTXOEntry: input.UTXOEntry.Clone(), + UTXOEntry: input.UTXOEntry, } } diff --git a/domain/consensus/model/externalapi/utxoentry.go b/domain/consensus/model/externalapi/utxoentry.go index 69f5a4756..22f9498b8 100644 --- a/domain/consensus/model/externalapi/utxoentry.go +++ b/domain/consensus/model/externalapi/utxoentry.go @@ -4,36 +4,9 @@ package externalapi // set such as whether or not it was contained in a coinbase tx, the blue // score of the block that accepts the tx, its public key script, and how // much it pays. -type UTXOEntry struct { - Amount uint64 - ScriptPublicKey []byte // The public key script for the output. - BlockBlueScore uint64 // Blue score of the block accepting the tx. - IsCoinbase bool -} - -// Clone returns a clone of UTXOEntry -func (entry *UTXOEntry) Clone() *UTXOEntry { - if entry == nil { - return nil - } - - scriptPublicKeyClone := make([]byte, len(entry.ScriptPublicKey)) - copy(scriptPublicKeyClone, entry.ScriptPublicKey) - - return &UTXOEntry{ - Amount: entry.Amount, - ScriptPublicKey: scriptPublicKeyClone, - BlockBlueScore: entry.BlockBlueScore, - IsCoinbase: entry.IsCoinbase, - } -} - -// NewUTXOEntry creates a new utxoEntry representing the given txOut -func NewUTXOEntry(amount uint64, scriptPubKey []byte, isCoinbase bool, blockBlueScore uint64) *UTXOEntry { - return &UTXOEntry{ - Amount: amount, - ScriptPublicKey: scriptPubKey, - BlockBlueScore: blockBlueScore, - IsCoinbase: isCoinbase, - } +type UTXOEntry interface { + Amount() uint64 + ScriptPublicKey() []byte // The public key script for the output. + BlockBlueScore() uint64 // Blue score of the block accepting the tx. + IsCoinbase() bool } diff --git a/domain/consensus/model/interface_datastructures_consensusstatestore.go b/domain/consensus/model/interface_datastructures_consensusstatestore.go index 022f8c547..df8fd2153 100644 --- a/domain/consensus/model/interface_datastructures_consensusstatestore.go +++ b/domain/consensus/model/interface_datastructures_consensusstatestore.go @@ -7,9 +7,9 @@ type ConsensusStateStore interface { Store IsStaged() bool - StageVirtualUTXODiff(virtualUTXODiff *UTXODiff) error + StageVirtualUTXODiff(virtualUTXODiff UTXODiff) error StageVirtualUTXOSet(virtualUTXOSetIterator ReadOnlyUTXOSetIterator) error - UTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (*externalapi.UTXOEntry, error) + UTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (externalapi.UTXOEntry, error) HasUTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) VirtualUTXOSetIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error) diff --git a/domain/consensus/model/interface_datastructures_utxodiffstore.go b/domain/consensus/model/interface_datastructures_utxodiffstore.go index 4d7ab3101..a774c55ef 100644 --- a/domain/consensus/model/interface_datastructures_utxodiffstore.go +++ b/domain/consensus/model/interface_datastructures_utxodiffstore.go @@ -5,9 +5,9 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // UTXODiffStore represents a store of UTXODiffs type UTXODiffStore interface { Store - Stage(blockHash *externalapi.DomainHash, utxoDiff *UTXODiff, utxoDiffChild *externalapi.DomainHash) + Stage(blockHash *externalapi.DomainHash, utxoDiff UTXODiff, utxoDiffChild *externalapi.DomainHash) IsStaged() bool - UTXODiff(dbContext DBReader, blockHash *externalapi.DomainHash) (*UTXODiff, error) + UTXODiff(dbContext DBReader, blockHash *externalapi.DomainHash) (UTXODiff, error) UTXODiffChild(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) HasUTXODiffChild(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) Delete(blockHash *externalapi.DomainHash) diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 5f4dc783e..208eef3ec 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -9,5 +9,5 @@ type ConsensusStateManager interface { SetPruningPointUTXOSet(serializedUTXOSet []byte) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) - CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (*UTXODiff, AcceptanceData, Multiset, error) + CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error) } diff --git a/domain/consensus/model/readonlyutxoset.go b/domain/consensus/model/readonlyutxoset.go index cba7d9c79..17f8c293e 100644 --- a/domain/consensus/model/readonlyutxoset.go +++ b/domain/consensus/model/readonlyutxoset.go @@ -5,12 +5,12 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // ReadOnlyUTXOSet represents a UTXOSet that can only be read from type ReadOnlyUTXOSet interface { Iterator() ReadOnlyUTXOSetIterator - Entry(outpoint *externalapi.DomainOutpoint) *externalapi.UTXOEntry + Entry(outpoint *externalapi.DomainOutpoint) externalapi.UTXOEntry } // ReadOnlyUTXOSetIterator is an iterator over all entries in a // ReadOnlyUTXOSet type ReadOnlyUTXOSetIterator interface { Next() bool - Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) + Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) } diff --git a/domain/consensus/model/testapi/test_block_builder.go b/domain/consensus/model/testapi/test_block_builder.go index 129d975b9..ce2e4d9bb 100644 --- a/domain/consensus/model/testapi/test_block_builder.go +++ b/domain/consensus/model/testapi/test_block_builder.go @@ -12,5 +12,5 @@ type TestBlockBuilder interface { // BuildBlockWithParents builds a block with provided parents, coinbaseData and transactions, // and returns the block together with its past UTXO-diff from the virtual. BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index a90804da0..f745d48d0 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -11,7 +11,8 @@ type TestConsensus interface { DatabaseContext() model.DBReader - BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) + BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) // AddBlock builds a block with given information, solves it, and adds to the DAG. // Returns the hash of the added block diff --git a/domain/consensus/model/testapi/test_consensus_state_manager.go b/domain/consensus/model/testapi/test_consensus_state_manager.go index bf112cbb9..251eae8a5 100644 --- a/domain/consensus/model/testapi/test_consensus_state_manager.go +++ b/domain/consensus/model/testapi/test_consensus_state_manager.go @@ -8,7 +8,7 @@ import ( // TestConsensusStateManager adds to the main ConsensusStateManager methods required by tests type TestConsensusStateManager interface { model.ConsensusStateManager - AddUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, + AddUTXOToMultiset(multiset model.Multiset, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) VirtualFinalityPoint() (*externalapi.DomainHash, error) diff --git a/domain/consensus/model/utxodiff.go b/domain/consensus/model/utxodiff.go index 7448f1c0f..6de4e2ce9 100644 --- a/domain/consensus/model/utxodiff.go +++ b/domain/consensus/model/utxodiff.go @@ -1,72 +1,33 @@ package model -import ( - "fmt" - "sort" - "strings" +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// UTXOCollection represents a set of UTXOs indexed by their outpoints -type UTXOCollection map[externalapi.DomainOutpoint]*externalapi.UTXOEntry - -// Clone returns a clone of UTXOCollection -func (uc UTXOCollection) Clone() UTXOCollection { - if uc == nil { - return nil - } - - clone := make(UTXOCollection, len(uc)) - for outpoint, entry := range uc { - clone[outpoint] = entry.Clone() - } - - return clone +// UTXOCollection represents a collection of UTXO entries, indexed by their outpoint +type UTXOCollection interface { + Iterator() ReadOnlyUTXOSetIterator + Get(outpoint *externalapi.DomainOutpoint) (externalapi.UTXOEntry, bool) + Contains(outpoint *externalapi.DomainOutpoint) bool + Len() int } -func (uc UTXOCollection) String() string { - utxoStrings := make([]string, len(uc)) - - i := 0 - for outpoint, utxoEntry := range uc { - utxoStrings[i] = fmt.Sprintf("(%s, %d) => %d, blueScore: %d", - outpoint.TransactionID, outpoint.Index, utxoEntry.Amount, utxoEntry.BlockBlueScore) - i++ - } - - // Sort strings for determinism. - sort.Strings(utxoStrings) - - return fmt.Sprintf("[ %s ]", strings.Join(utxoStrings, ", ")) +// UTXODiff represents the diff between two UTXO sets +type UTXODiff interface { + ToAdd() UTXOCollection + ToRemove() UTXOCollection + WithDiff(other UTXODiff) (UTXODiff, error) + DiffFrom(other UTXODiff) (UTXODiff, error) + CloneMutable() MutableUTXODiff } -// UTXODiff represents a diff between two UTXO Sets. -type UTXODiff struct { - ToAdd UTXOCollection - ToRemove UTXOCollection -} +// MutableUTXODiff represents a UTXO-Diff that can be mutated +type MutableUTXODiff interface { + ToImmutable() UTXODiff -// Clone returns a clone of UTXODiff -func (d *UTXODiff) Clone() *UTXODiff { - if d == nil { - return nil - } + WithDiff(other UTXODiff) (UTXODiff, error) + DiffFrom(other UTXODiff) (UTXODiff, error) + ToAdd() UTXOCollection + ToRemove() UTXOCollection - return &UTXODiff{ - ToAdd: d.ToAdd.Clone(), - ToRemove: d.ToRemove.Clone(), - } -} - -func (d UTXODiff) String() string { - return fmt.Sprintf("ToAdd: %s; ToRemove: %s", d.ToAdd, d.ToRemove) -} - -// NewUTXODiff instantiates an empty UTXODiff -func NewUTXODiff() *UTXODiff { - return &UTXODiff{ - ToAdd: UTXOCollection{}, - ToRemove: UTXOCollection{}, - } + WithDiffInPlace(other UTXODiff) error + AddTransaction(transaction *externalapi.DomainTransaction, blockBlueScore uint64) error } diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index c9284d7f2..967a1e4d4 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -31,7 +31,7 @@ func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus test // and returns the block together with its past UTXO-diff from the virtual. func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) ( - *externalapi.DomainBlock, *model.UTXODiff, error) { + *externalapi.DomainBlock, model.UTXODiff, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockWithParents") defer onEnd() @@ -72,7 +72,7 @@ func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.D }, nil } -func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, *model.UTXODiff, error) { +func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) { defer bb.testConsensus.DiscardAllStores() diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index bd01ca567..d5577b000 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -11,11 +11,10 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" ) func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( - *model.UTXODiff, model.AcceptanceData, model.Multiset, error) { + model.UTXODiff, model.AcceptanceData, model.Multiset, error) { log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) @@ -23,7 +22,7 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * if *blockHash == *csm.genesisHash { log.Tracef("Block %s is the genesis. By definition, "+ "it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash) - return &model.UTXODiff{}, model.AcceptanceData{}, multiset.New(), nil + return utxo.NewUTXODiff(), model.AcceptanceData{}, multiset.New(), nil } blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash) @@ -51,17 +50,17 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * } log.Tracef("The multiset of block %s resolved to: %s", blockHash, multiset.Hash()) - return utxoDiff, acceptanceData, multiset, nil + return utxoDiff.ToImmutable(), acceptanceData, multiset, nil } -func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainHash) (*model.UTXODiff, error) { +func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainHash) (model.MutableUTXODiff, error) { log.Tracef("restorePastUTXO start for block %s", blockHash) defer log.Tracef("restorePastUTXO end for block %s", blockHash) var err error log.Tracef("Collecting UTXO diffs for block %s", blockHash) - var utxoDiffs []*model.UTXODiff + var utxoDiffs []model.UTXODiff nextBlockHash := blockHash for { log.Tracef("Collecting UTXO diff for block %s", nextBlockHash) @@ -97,9 +96,9 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH // apply the diffs in reverse order log.Tracef("Applying the collected UTXO diffs for block %s in reverse order", blockHash) - accumulatedDiff := model.NewUTXODiff() + accumulatedDiff := utxo.NewMutableUTXODiff() for i := len(utxoDiffs) - 1; i >= 0; i-- { - accumulatedDiff, err = utxoalgebra.WithDiff(accumulatedDiff, utxoDiffs[i]) + err = accumulatedDiff.WithDiffInPlace(utxoDiffs[i]) if err != nil { return nil, err } @@ -110,8 +109,8 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH } func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash, - selectedParentPastUTXODiff *model.UTXODiff, ghostdagData *model.BlockGHOSTDAGData) ( - model.AcceptanceData, *model.UTXODiff, error) { + selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) ( + model.AcceptanceData, model.MutableUTXODiff, error) { log.Tracef("applyBlueBlocks start for block %s", blockHash) defer log.Tracef("applyBlueBlocks end for block %s", blockHash) @@ -128,7 +127,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime) multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks)) - accumulatedUTXODiff := selectedParentPastUTXODiff.Clone() + accumulatedUTXODiff := selectedParentPastUTXODiff accumulatedMass := uint64(0) for i, blueBlock := range blueBlocks { @@ -168,7 +167,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH } func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalapi.DomainTransaction, - blockHash *externalapi.DomainHash, isSelectedParent bool, accumulatedUTXODiff *model.UTXODiff, + blockHash *externalapi.DomainHash, isSelectedParent bool, accumulatedUTXODiff model.MutableUTXODiff, accumulatedMassBefore uint64, selectedParentPastMedianTime int64, blockBlueScore uint64) ( isAccepted bool, accumulatedMassAfter uint64, err error) { @@ -177,7 +176,7 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap defer log.Tracef("maybeAcceptTransaction end for transaction %s in block %s", transactionID, blockHash) log.Tracef("Populating transaction %s with UTXO entries", transactionID) - err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, accumulatedUTXODiff) + err = csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(transaction, accumulatedUTXODiff.ToImmutable()) if err != nil { if !errors.As(err, &(ruleerrors.RuleError{})) { return false, 0, err @@ -220,7 +219,7 @@ func (csm *consensusStateManager) maybeAcceptTransaction(transaction *externalap } log.Tracef("Adding transaction %s in block %s to the accumulated diff", transactionID, blockHash) - err = utxoalgebra.DiffAddTransaction(accumulatedUTXODiff, transaction, blockBlueScore) + err = accumulatedUTXODiff.AddTransaction(transaction, blockBlueScore) if err != nil { return false, 0, err } @@ -278,5 +277,5 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external return nil, err } - return utxo.IteratorWithDiff(virtualUTXOSetIterator, blockDiff) + return utxo.IteratorWithDiff(virtualUTXOSetIterator, blockDiff.ToImmutable()) } diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index c3b1e7336..7786b4992 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -72,12 +72,8 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi. TransactionID: *transactionID, Index: uint32(i), } - utxoEntry := &externalapi.UTXOEntry{ - Amount: output.Value, - ScriptPublicKey: output.ScriptPublicKey, - BlockBlueScore: blockBlueScore, - IsCoinbase: isCoinbase, - } + utxoEntry := utxo.NewUTXOEntry(output.Value, output.ScriptPublicKey, isCoinbase, blockBlueScore) + log.Tracef("Adding input %s at index %d from the multiset", transactionID, i) err := addUTXOToMultiset(multiset, utxoEntry, outpoint) if err != nil { @@ -88,7 +84,7 @@ func addTransactionToMultiset(multiset model.Multiset, transaction *externalapi. return nil } -func addUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, +func addUTXOToMultiset(multiset model.Multiset, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error { serializedUTXO, err := utxo.SerializeUTXO(entry, outpoint) @@ -100,7 +96,7 @@ func addUTXOToMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, return nil } -func removeUTXOFromMultiset(multiset model.Multiset, entry *externalapi.UTXOEntry, +func removeUTXOFromMultiset(multiset model.Multiset, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error { serializedUTXO, err := utxo.SerializeUTXO(entry, outpoint) diff --git a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go index 1b6e38d73..3b5c6ce08 100644 --- a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go +++ b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go @@ -5,7 +5,6 @@ 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/domain/consensus/utils/utxo/utxoalgebra" ) // PopulateTransactionWithUTXOEntries populates the transaction UTXO entries with data from the virtual's UTXO set. @@ -17,7 +16,7 @@ func (csm *consensusStateManager) PopulateTransactionWithUTXOEntries(transaction // from the virtual's UTXO set combined with the provided utxoDiff. // If utxoDiff == nil UTXO entries are taken from the virtual's UTXO set only func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualOrDiff( - transaction *externalapi.DomainTransaction, utxoDiff *model.UTXODiff) error { + transaction *externalapi.DomainTransaction, utxoDiff model.UTXODiff) error { transactionID := consensushashing.TransactionID(transaction) log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff start for transaction %s", transactionID) @@ -34,14 +33,14 @@ func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualO // check if utxoDiff says anything about the input's outpoint if utxoDiff != nil { - if utxoEntry, ok := utxoalgebra.CollectionGet(utxoDiff.ToAdd, &transactionInput.PreviousOutpoint); ok { + if utxoEntry, ok := utxoDiff.ToAdd().Get(&transactionInput.PreviousOutpoint); ok { log.Tracef("Populating outpoint %s:%d from the given utxoDiff", transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) transactionInput.UTXOEntry = utxoEntry continue } - if utxoalgebra.CollectionContains(utxoDiff.ToRemove, &transactionInput.PreviousOutpoint) { + if utxoDiff.ToRemove().Contains(&transactionInput.PreviousOutpoint) { log.Tracef("Outpoint %s:%d is missing in the given utxoDiff", transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index bd54054c0..3a2447aaf 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -4,7 +4,6 @@ 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/utxo/utxoalgebra" "github.com/pkg/errors" ) @@ -169,7 +168,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap } func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssignDiffChild( - blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { + blockHash *externalapi.DomainHash, pastUTXODiff model.UTXODiff) error { log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild start for block %s", blockHash) defer log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild end for block %s", blockHash) @@ -209,7 +208,7 @@ func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssign if err != nil { return err } - newDiff, err := utxoalgebra.DiffFrom(pastUTXODiff, currentDiff) + newDiff, err := pastUTXODiff.DiffFrom(currentDiff) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 7c6b667a8..fd211c9b2 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -88,7 +88,7 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt } log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff") - err = csm.updateVirtualDiffParents(model.NewUTXODiff()) + err = csm.updateVirtualDiffParents(utxo.NewUTXODiff()) if err != nil { return err } @@ -130,7 +130,7 @@ func (p protoUTXOSetIterator) Next() bool { 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) { diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go index b6314cc72..e10edc826 100644 --- a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -16,7 +16,7 @@ func NewTestConsensusStateManager(baseConsensusStateManager model.ConsensusState } func (csm testConsensusStateManager) AddUTXOToMultiset( - multiset model.Multiset, entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error { + multiset model.Multiset, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error { return addUTXOToMultiset(multiset, entry, outpoint) } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index f93bbe102..c87aed315 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -3,7 +3,6 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error { @@ -55,7 +54,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain return nil } -func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff *model.UTXODiff) error { +func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff model.UTXODiff) error { log.Tracef("updateVirtualDiffParents start") defer log.Tracef("updateVirtualDiffParents end") @@ -70,7 +69,7 @@ func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff *mode if err != nil { return err } - newDiff, err := utxoalgebra.DiffFrom(virtualUTXODiff, virtualDiffParentUTXODiff) + newDiff, err := virtualUTXODiff.DiffFrom(virtualDiffParentUTXODiff) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go index 1f55fb333..564ca9fa2 100644 --- a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go +++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go @@ -7,7 +7,7 @@ import ( ) func (csm *consensusStateManager) stageDiff(blockHash *externalapi.DomainHash, - utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { + utxoDiff model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { log.Tracef("stageDiff start for block %s", blockHash) defer log.Tracef("stageDiff end for block %s", blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 17226e863..369145187 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -19,7 +19,7 @@ import ( ) func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, - pastUTXODiff *model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error { + pastUTXODiff model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error { log.Tracef("verifyUTXO start for block %s", blockHash) defer log.Tracef("verifyUTXO end for block %s", blockHash) @@ -58,7 +58,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo } func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock, - blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { + blockHash *externalapi.DomainHash, pastUTXODiff model.UTXODiff) error { log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash) defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash) diff --git a/domain/consensus/processes/transactionvalidator/mass.go b/domain/consensus/processes/transactionvalidator/mass.go index 562062193..6b5d15daf 100644 --- a/domain/consensus/processes/transactionvalidator/mass.go +++ b/domain/consensus/processes/transactionvalidator/mass.go @@ -37,8 +37,8 @@ func (v *transactionValidator) transactionMass(tx *externalapi.DomainTransaction // Count the precise number of signature operations in the // referenced public key script. sigScript := input.SignatureScript - isP2SH := txscript.IsPayToScriptHash(utxoEntry.ScriptPublicKey) - sigOpsCount += uint64(txscript.GetPreciseSigOpCount(sigScript, utxoEntry.ScriptPublicKey, isP2SH)) + isP2SH := txscript.IsPayToScriptHash(utxoEntry.ScriptPublicKey()) + sigOpsCount += uint64(txscript.GetPreciseSigOpCount(sigScript, utxoEntry.ScriptPublicKey(), isP2SH)) } if len(missingOutpoints) > 0 { return 0, ruleerrors.NewErrMissingTxOut(missingOutpoints) diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index bc8dd7af4..9f40f9998 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -65,8 +65,8 @@ func (v *transactionValidator) checkTransactionCoinbaseMaturity( utxoEntry := input.UTXOEntry if utxoEntry == nil { missingOutpoints = append(missingOutpoints, &input.PreviousOutpoint) - } else if utxoEntry.IsCoinbase { - originBlueScore := utxoEntry.BlockBlueScore + } else if utxoEntry.IsCoinbase() { + originBlueScore := utxoEntry.BlockBlueScore() blueScoreSincePrev := txBlueScore - originBlueScore if blueScoreSincePrev < v.blockCoinbaseMaturity { return errors.Wrapf(ruleerrors.ErrImmatureSpend, "tried to spend coinbase "+ @@ -116,11 +116,11 @@ func (v *transactionValidator) checkTransactionInputAmounts(tx *externalapi.Doma return totalSompiIn, nil } -func (v *transactionValidator) checkEntryAmounts(entry *externalapi.UTXOEntry, totalSompiInBefore uint64) (totalSompiInAfter uint64, err error) { +func (v *transactionValidator) checkEntryAmounts(entry externalapi.UTXOEntry, totalSompiInBefore uint64) (totalSompiInAfter uint64, err error) { // The total of all outputs must not be more than the max // allowed per transaction. Also, we could potentially overflow // the accumulator so check for overflow. - originTxSompi := entry.Amount + originTxSompi := entry.Amount() totalSompiInAfter = totalSompiInBefore + originTxSompi if totalSompiInAfter < totalSompiInBefore || totalSompiInAfter > constants.MaxSompi { @@ -187,7 +187,7 @@ func (v *transactionValidator) validateTransactionScripts(tx *externalapi.Domain continue } - scriptPubKey := utxoEntry.ScriptPublicKey + scriptPubKey := utxoEntry.ScriptPublicKey() vm, err := txscript.NewEngine(scriptPubKey, tx, i, txscript.ScriptNoFlags, v.sigCache) if err != nil { @@ -241,7 +241,7 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries( // If the input blue score is set to the mempool blue score, then we // assume the transaction makes it into the next block when // evaluating its sequence blocks. - inputBlueScore := utxoEntry.BlockBlueScore + inputBlueScore := utxoEntry.BlockBlueScore() // Given a sequence number, we apply the relative time lock // mask in order to obtain the time lock delta required before diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 216befae1..927739f13 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -18,7 +18,7 @@ type testConsensus struct { func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) ( - *externalapi.DomainBlock, *model.UTXODiff, error) { + *externalapi.DomainBlock, model.UTXODiff, error) { // Require write lock because BuildBlockWithParents stages temporary data tc.lock.Lock() diff --git a/domain/consensus/utils/utxo/diff_algebra.go b/domain/consensus/utils/utxo/diff_algebra.go new file mode 100644 index 000000000..876ba8096 --- /dev/null +++ b/domain/consensus/utils/utxo/diff_algebra.go @@ -0,0 +1,252 @@ +package utxo + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" +) + +// checkIntersection checks if there is an intersection between two utxoCollections +func checkIntersection(collection1 utxoCollection, collection2 utxoCollection) bool { + for outpoint := range collection1 { + if collection2.Contains(&outpoint) { + return true + } + } + + return false +} + +// checkIntersectionWithRule checks if there is an intersection between two utxoCollections satisfying arbitrary rule +// returns the first outpoint in the two collections' intersection satsifying the rule, and a boolean indicating whether +// such outpoint exists +func checkIntersectionWithRule(collection1 utxoCollection, collection2 utxoCollection, + extraRule func(*externalapi.DomainOutpoint, externalapi.UTXOEntry, externalapi.UTXOEntry) bool) ( + *externalapi.DomainOutpoint, bool) { + + for outpoint, utxoEntry := range collection1 { + if diffEntry, ok := collection2.Get(&outpoint); ok { + if extraRule(&outpoint, utxoEntry, diffEntry) { + return &outpoint, true + } + } + } + + return nil, false +} + +// minInt returns the smaller of x or y integer values +func minInt(a, b int) int { + if a < b { + return a + } + return b +} + +// intersectionWithRemainderHavingBlueScore calculates an intersection between two utxoCollections +// having same blue score, returns the result and the remainder from collection1 +func intersectionWithRemainderHavingBlueScore(collection1, collection2 utxoCollection) (result, remainder utxoCollection) { + result = make(utxoCollection, minInt(len(collection1), len(collection2))) + remainder = make(utxoCollection, len(collection1)) + intersectionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder) + return +} + +// intersectionWithRemainderHavingBlueScoreInPlace calculates an intersection between two utxoCollections +// having same blue score, puts it into result and into remainder from collection1 +func intersectionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder utxoCollection) { + for outpoint, utxoEntry := range collection1 { + if collection2.containsWithBlueScore(&outpoint, utxoEntry.BlockBlueScore()) { + result.add(&outpoint, utxoEntry) + } else { + remainder.add(&outpoint, utxoEntry) + } + } +} + +// subtractionHavingBlueScore calculates a subtraction between collection1 and collection2 +// having same blue score, returns the result +func subtractionHavingBlueScore(collection1, collection2 utxoCollection) (result utxoCollection) { + result = make(utxoCollection, len(collection1)) + + subtractionHavingBlueScoreInPlace(collection1, collection2, result) + return +} + +// subtractionHavingBlueScoreInPlace calculates a subtraction between collection1 and collection2 +// having same blue score, puts it into result +func subtractionHavingBlueScoreInPlace(collection1, collection2, result utxoCollection) { + for outpoint, utxoEntry := range collection1 { + if !collection2.containsWithBlueScore(&outpoint, utxoEntry.BlockBlueScore()) { + result.add(&outpoint, utxoEntry) + } + } +} + +// subtractionWithRemainderHavingBlueScore calculates a subtraction between collection1 and collection2 +// having same blue score, returns the result and the remainder from collection1 +func subtractionWithRemainderHavingBlueScore(collection1, collection2 utxoCollection) (result, remainder utxoCollection) { + result = make(utxoCollection, len(collection1)) + remainder = make(utxoCollection, len(collection1)) + + subtractionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder) + return +} + +// subtractionWithRemainderHavingBlueScoreInPlace calculates a subtraction between collection1 and collection2 +// having same blue score, puts it into result and into remainder from collection1 +func subtractionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder utxoCollection) { + for outpoint, utxoEntry := range collection1 { + if !collection2.containsWithBlueScore(&outpoint, utxoEntry.BlockBlueScore()) { + result.add(&outpoint, utxoEntry) + } else { + remainder.add(&outpoint, utxoEntry) + } + } +} + +// DiffFrom returns a new mutableUTXODiff with the difference between this mutableUTXODiff and another +// Assumes that: +// Both mutableUTXODiffs are from the same base +// If a txOut exists in both mutableUTXODiffs, its underlying values would be the same +// +// diffFrom follows a set of rules represented by the following 3 by 3 table: +// +// | | this | | +// ---------+-----------+-----------+-----------+----------- +// | | toAdd | toRemove | None +// ---------+-----------+-----------+-----------+----------- +// other | toAdd | - | X | toAdd +// ---------+-----------+-----------+-----------+----------- +// | toRemove | X | - | toRemove +// ---------+-----------+-----------+-----------+----------- +// | None | toRemove | toAdd | - +// +// Key: +// - Don't add anything to the result +// X Return an error +// toAdd Add the UTXO into the toAdd collection of the result +// toRemove Add the UTXO into the toRemove collection of the result +// +// Examples: +// 1. This diff contains a UTXO in toAdd, and the other diff contains it in toRemove +// diffFrom results in an error +// 2. This diff contains a UTXO in toRemove, and the other diff does not contain it +// diffFrom results in the UTXO being added to toAdd +func diffFrom(this, other *mutableUTXODiff) (*mutableUTXODiff, error) { + // Note that the following cases are not accounted for, as they are impossible + // as long as the base utxoSet is the same: + // - if utxoEntry is in this.toAdd and other.toRemove + // - if utxoEntry is in this.toRemove and other.toAdd + + // check that NOT (entries with unequal blue scores AND utxoEntry is in this.toAdd and/or other.toRemove) -> Error + isNotAddedOutputRemovedWithBlueScore := func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry externalapi.UTXOEntry) bool { + return !(diffEntry.BlockBlueScore() != utxoEntry.BlockBlueScore() && + (this.toAdd.containsWithBlueScore(outpoint, diffEntry.BlockBlueScore()) || + other.toRemove.containsWithBlueScore(outpoint, utxoEntry.BlockBlueScore()))) + } + + if offendingOutpoint, ok := + checkIntersectionWithRule(this.toRemove, other.toAdd, isNotAddedOutputRemovedWithBlueScore); ok { + return nil, errors.Errorf("diffFrom: outpoint %s both in this.toAdd and in other.toRemove", offendingOutpoint) + } + + //check that NOT (entries with unequal blue score AND utxoEntry is in this.toRemove and/or other.toAdd) -> Error + isNotRemovedOutputAddedWithBlueScore := + func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry externalapi.UTXOEntry) bool { + + return !(diffEntry.BlockBlueScore() != utxoEntry.BlockBlueScore() && + (this.toRemove.containsWithBlueScore(outpoint, diffEntry.BlockBlueScore()) || + other.toAdd.containsWithBlueScore(outpoint, utxoEntry.BlockBlueScore()))) + } + + if offendingOutpoint, ok := + checkIntersectionWithRule(this.toAdd, other.toRemove, isNotRemovedOutputAddedWithBlueScore); ok { + return nil, errors.Errorf("diffFrom: outpoint %s both in this.toRemove and in other.toAdd", offendingOutpoint) + } + + // if have the same entry in this.toRemove and other.toRemove + // and existing entry is with different blue score, in this case - this is an error + if offendingOutpoint, ok := checkIntersectionWithRule(this.toRemove, other.toRemove, + func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry externalapi.UTXOEntry) bool { + return utxoEntry.BlockBlueScore() != diffEntry.BlockBlueScore() + }); ok { + return nil, errors.Errorf("diffFrom: outpoint %s both in this.toRemove and other.toRemove with different "+ + "blue scores, with no corresponding entry in this.toAdd", offendingOutpoint) + } + + result := &mutableUTXODiff{ + toAdd: make(utxoCollection, len(this.toRemove)+len(other.toAdd)), + toRemove: make(utxoCollection, len(this.toAdd)+len(other.toRemove)), + } + + // All transactions in this.toAdd: + // If they are not in other.toAdd - should be added in result.toRemove + inBothToAdd := make(utxoCollection, len(this.toAdd)) + subtractionWithRemainderHavingBlueScoreInPlace(this.toAdd, other.toAdd, result.toRemove, inBothToAdd) + // If they are in other.toRemove - base utxoSet is not the same + if checkIntersection(inBothToAdd, this.toRemove) != checkIntersection(inBothToAdd, other.toRemove) { + return nil, errors.New( + "diffFrom: outpoint both in this.toAdd, other.toAdd, and only one of this.toRemove and other.toRemove") + } + + // All transactions in other.toRemove: + // If they are not in this.toRemove - should be added in result.toRemove + subtractionHavingBlueScoreInPlace(other.toRemove, this.toRemove, result.toRemove) + + // All transactions in this.toRemove: + // If they are not in other.toRemove - should be added in result.toAdd + subtractionHavingBlueScoreInPlace(this.toRemove, other.toRemove, result.toAdd) + + // All transactions in other.toAdd: + // If they are not in this.toAdd - should be added in result.toAdd + subtractionHavingBlueScoreInPlace(other.toAdd, this.toAdd, result.toAdd) + + return result, nil +} + +// WithDiffInPlace applies provided diff to this diff in-place, that would be the result if +// first d, and than diff were applied to the same base +func withDiffInPlace(this *mutableUTXODiff, other *mutableUTXODiff) error { + if offendingOutpoint, ok := checkIntersectionWithRule(other.toRemove, this.toRemove, + func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry externalapi.UTXOEntry) bool { + return !this.toAdd.containsWithBlueScore(outpoint, entryToAdd.BlockBlueScore()) + }); ok { + return errors.Errorf( + "withDiffInPlace: outpoint %s both in this.toRemove and in other.toRemove", offendingOutpoint) + } + + if offendingOutpoint, ok := checkIntersectionWithRule(other.toAdd, this.toAdd, + func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry externalapi.UTXOEntry) bool { + return !other.toRemove.containsWithBlueScore(outpoint, existingEntry.BlockBlueScore()) + }); ok { + return errors.Errorf( + "withDiffInPlace: outpoint %s both in this.toAdd and in other.toAdd", offendingOutpoint) + } + + intersection := make(utxoCollection, minInt(len(other.toRemove), len(this.toAdd))) + // If not exists neither in toAdd nor in toRemove - add to toRemove + intersectionWithRemainderHavingBlueScoreInPlace(other.toRemove, this.toAdd, intersection, this.toRemove) + // If already exists in toAdd with the same blueScore - remove from toAdd + this.toAdd.removeMultiple(intersection) + + intersection = make(utxoCollection, minInt(len(other.toAdd), len(this.toRemove))) + // If not exists neither in toAdd nor in toRemove, or exists in toRemove with different blueScore - add to toAdd + intersectionWithRemainderHavingBlueScoreInPlace(other.toAdd, this.toRemove, intersection, this.toAdd) + // If already exists in toRemove with the same blueScore - remove from toRemove + this.toRemove.removeMultiple(intersection) + + return nil +} + +// WithDiff applies provided diff to this diff, creating a new mutableUTXODiff, that would be the result if +// first d, and than diff were applied to some base +func withDiff(this *mutableUTXODiff, diff *mutableUTXODiff) (*mutableUTXODiff, error) { + clone := this.clone() + + err := withDiffInPlace(clone, diff) + if err != nil { + return nil, err + } + + return clone, nil +} diff --git a/domain/consensus/utils/utxo/diff_algebra_test.go b/domain/consensus/utils/utxo/diff_algebra_test.go new file mode 100644 index 000000000..97b7efc4d --- /dev/null +++ b/domain/consensus/utils/utxo/diff_algebra_test.go @@ -0,0 +1,616 @@ +package utxo + +import ( + "reflect" + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +func (mud *mutableUTXODiff) equal(other *mutableUTXODiff) bool { + if mud == nil || other == nil { + return mud == other + } + + return reflect.DeepEqual(mud.toAdd, other.toAdd) && + reflect.DeepEqual(mud.toRemove, other.toRemove) +} + +// TestUTXOCollection makes sure that utxoCollection cloning and string representations work as expected. +func TestUTXOCollection(t *testing.T) { + txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") + txID1, _ := transactionid.FromString("1111111111111111111111111111111111111111111111111111111111111111") + outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) + outpoint1 := externalapi.NewDomainOutpoint(txID1, 0) + utxoEntry0 := NewUTXOEntry(10, []byte{}, true, 0) + utxoEntry1 := NewUTXOEntry(20, []byte{}, false, 1) + + // For each of the following test cases, we will: + // .String() the given collection and compare it to expectedStringWithMultiset + // .clone() the given collection and compare its value to itself (expected: equals) and its reference to itself (expected: not equal) + tests := []struct { + name string + collection utxoCollection + expectedString string + }{ + { + name: "empty collection", + collection: utxoCollection{}, + expectedString: "[ ]", + }, + { + name: "one member", + collection: utxoCollection{ + *outpoint0: utxoEntry1, + }, + expectedString: "[ (0000000000000000000000000000000000000000000000000000000000000000, 0) => 20, blueScore: 1 ]", + }, + { + name: "two members", + collection: utxoCollection{ + *outpoint0: utxoEntry0, + *outpoint1: utxoEntry1, + }, + expectedString: "[ (0000000000000000000000000000000000000000000000000000000000000000, 0) => 10, blueScore: 0, (1111111111111111111111111111111111111111111111111111111111111111, 0) => 20, blueScore: 1 ]", + }, + } + + for _, test := range tests { + // Test utxoCollection string representation + collectionString := test.collection.String() + if collectionString != test.expectedString { + t.Errorf("unexpected string in test \"%s\". "+ + "Expected: \"%s\", got: \"%s\".", test.name, test.expectedString, collectionString) + } + + // Test utxoCollection cloning + collectionClone := test.collection.Clone() + if reflect.ValueOf(collectionClone).Pointer() == reflect.ValueOf(test.collection).Pointer() { + t.Errorf("collection is reference-equal to its clone in test \"%s\". ", test.name) + } + if !reflect.DeepEqual(test.collection, collectionClone) { + t.Errorf("collection is not equal to its clone in test \"%s\". "+ + "Expected: \"%s\", got: \"%s\".", test.name, collectionString, collectionClone.String()) + } + } +} + +// TestutxoDiff makes sure that mutableUTXODiff creation, cloning, and string representations work as expected. +func TestUTXODiff(t *testing.T) { + txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") + txID1, _ := transactionid.FromString("1111111111111111111111111111111111111111111111111111111111111111") + outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) + outpoint1 := externalapi.NewDomainOutpoint(txID1, 0) + utxoEntry0 := NewUTXOEntry(10, []byte{}, true, 0) + utxoEntry1 := NewUTXOEntry(20, []byte{}, false, 1) + + diff := newMutableUTXODiff() + + if len(diff.toAdd) != 0 || len(diff.toRemove) != 0 { + t.Errorf("new diff is not empty") + } + + err := diff.addEntry(outpoint0, utxoEntry0) + if err != nil { + t.Fatalf("error adding entry to utxo diff: %s", err) + } + + err = diff.removeEntry(outpoint1, utxoEntry1) + if err != nil { + t.Fatalf("error adding entry to utxo diff: %s", err) + } + + // Test mutableUTXODiff cloning + clonedDiff := diff.clone() + if clonedDiff == diff { + t.Errorf("cloned diff is reference-equal to the original") + } + if !reflect.DeepEqual(clonedDiff, diff) { + t.Errorf("cloned diff not equal to the original"+ + "Original: \"%v\", cloned: \"%v\".", diff, clonedDiff) + } + + // Test mutableUTXODiff string representation + expectedDiffString := "toAdd: [ (0000000000000000000000000000000000000000000000000000000000000000, 0) => 10, blueScore: 0 ]; toRemove: [ (1111111111111111111111111111111111111111111111111111111111111111, 0) => 20, blueScore: 1 ]" + diffString := clonedDiff.String() + if diffString != expectedDiffString { + t.Errorf("unexpected diff string. "+ + "Expected: \"%s\", got: \"%s\".", expectedDiffString, diffString) + } +} + +// TestutxoDiffRules makes sure that all diffFrom and WithDiff rules are followed. +// Each test case represents a cell in the two tables outlined in the documentation for mutableUTXODiff. +func TestUTXODiffRules(t *testing.T) { + txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") + outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) + utxoEntry1 := NewUTXOEntry(10, []byte{}, true, 0) + utxoEntry2 := NewUTXOEntry(20, []byte{}, true, 1) + + // For each of the following test cases, we will: + // this.diffFrom(other) and compare it to expectedDiffFromResult + // this.WithDiff(other) and compare it to expectedWithDiffResult + // this.withDiffInPlace(other) and compare it to expectedWithDiffResult + // + // Note: an expected nil result means that we expect the respective operation to fail + // See the following spreadsheet for a summary of all test-cases: + // https://docs.google.com/spreadsheets/d/1E8G3mp5y1-yifouwLLXRLueSRfXdDRwRKFieYE07buY/edit?usp=sharing + tests := []struct { + name string + this *mutableUTXODiff + other *mutableUTXODiff + expectedDiffFromResult *mutableUTXODiff + expectedWithDiffResult *mutableUTXODiff + }{ + { + name: "first toAdd in this, first toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd in this, second in toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd in this, second in toRemove in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + }, + { + name: "first in toAdd in this and other, second in toRemove in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd in this and toRemove in other, second in toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{}, + }, + }, + { + name: "first in toAdd in this, empty other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + }, + { + name: "first in toRemove in this and in toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + }, + { + name: "first in toRemove in this, second in toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + }, + { + name: "first in toRemove in this and other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: nil, + }, + { + name: "first in toRemove in this, second in toRemove in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: nil, + }, + { + name: "first in toRemove in this and toAdd in other, second in toRemove in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: nil, + }, + { + name: "first in toRemove in this and other, second in toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: nil, + }, + { + name: "first in toRemove in this, empty other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + }, + { + name: "first in toAdd in this and other, second in toRemove in this", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd in this, second in toRemove in this and toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd in this and toRemove in other, second in toRemove in this", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + }, + { + name: "first in toAdd in this, second in toRemove in this and in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd and second in toRemove in both this and other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: nil, + }, + { + name: "first in toAdd in this and toRemove in other, second in toRemove in this and toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: nil, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + }, + { + name: "first in toAdd and second in toRemove in this, empty other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry2}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + }, + { + name: "empty this, first in toAdd in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{}, + }, + }, + { + name: "empty this, first in toRemove in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{*outpoint0: utxoEntry1}, + }, + }, + { + name: "empty this, first in toAdd and second in toRemove in other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{*outpoint0: utxoEntry1}, + toRemove: utxoCollection{*outpoint0: utxoEntry2}, + }, + }, + { + name: "empty this, empty other", + this: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + other: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedDiffFromResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + expectedWithDiffResult: &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + }, + }, + } + + for _, test := range tests { + // diffFrom from test.this to test.other + diffResult, err := diffFrom(test.this, test.other) + + // Test whether diffFrom returned an error + isDiffFromOk := err == nil + expectedIsDiffFromOk := test.expectedDiffFromResult != nil + if isDiffFromOk != expectedIsDiffFromOk { + t.Errorf("unexpected diffFrom error in test \"%s\". "+ + "Expected: \"%t\", got: \"%t\".", test.name, expectedIsDiffFromOk, isDiffFromOk) + } + + // If not error, test the diffFrom result + if isDiffFromOk && !test.expectedDiffFromResult.equal(diffResult) { + t.Errorf("unexpected diffFrom result in test \"%s\". "+ + "Expected: \"%v\", got: \"%v\".", test.name, test.expectedDiffFromResult, diffResult) + } + + // Make sure that WithDiff after diffFrom results in the original test.other + if isDiffFromOk { + otherResult, err := withDiff(test.this, diffResult) + if err != nil { + t.Errorf("WithDiff unexpectedly failed in test \"%s\": %s", test.name, err) + } + if !test.other.equal(otherResult) { + t.Errorf("unexpected WithDiff result in test \"%s\". "+ + "Expected: \"%v\", got: \"%v\".", test.name, test.other, otherResult) + } + } + + // WithDiff from test.this to test.other + withDiffResult, err := withDiff(test.this, test.other) + + // Test whether WithDiff returned an error + isWithDiffOk := err == nil + expectedIsWithDiffOk := test.expectedWithDiffResult != nil + if isWithDiffOk != expectedIsWithDiffOk { + t.Errorf("unexpected WithDiff error in test \"%s\". "+ + "Expected: \"%t\", got: \"%t\".", test.name, expectedIsWithDiffOk, isWithDiffOk) + } + + // If not error, test the WithDiff result + if isWithDiffOk && !withDiffResult.equal(test.expectedWithDiffResult) { + t.Errorf("unexpected WithDiff result in test \"%s\". "+ + "Expected: \"%v\", got: \"%v\".", test.name, test.expectedWithDiffResult, withDiffResult) + } + + // Repeat WithDiff check test.this time using withDiffInPlace + thisClone := test.this.clone() + err = withDiffInPlace(thisClone, test.other) + + // Test whether withDiffInPlace returned an error + isWithDiffInPlaceOk := err == nil + expectedIsWithDiffInPlaceOk := test.expectedWithDiffResult != nil + if isWithDiffInPlaceOk != expectedIsWithDiffInPlaceOk { + t.Errorf("unexpected withDiffInPlace error in test \"%s\". "+ + "Expected: \"%t\", got: \"%t\".", test.name, expectedIsWithDiffInPlaceOk, isWithDiffInPlaceOk) + } + + // If not error, test the withDiffInPlace result + if isWithDiffInPlaceOk && !thisClone.equal(test.expectedWithDiffResult) { + t.Errorf("unexpected withDiffInPlace result in test \"%s\". "+ + "Expected: \"%v\", got: \"%v\".", test.name, test.expectedWithDiffResult, thisClone) + } + + // Make sure that diffFrom after WithDiff results in the original test.other + if isWithDiffOk { + otherResult, err := diffFrom(test.this, withDiffResult) + if err != nil { + t.Errorf("diffFrom unexpectedly failed in test \"%s\": %s", test.name, err) + } + if !test.other.equal(otherResult) { + t.Errorf("unexpected diffFrom result in test \"%s\". "+ + "Expected: \"%v\", got: \"%v\".", test.name, test.other, otherResult) + } + } + } +} diff --git a/domain/consensus/utils/utxo/immutable_utxo_diff.go b/domain/consensus/utils/utxo/immutable_utxo_diff.go new file mode 100644 index 000000000..3bc7a4a6c --- /dev/null +++ b/domain/consensus/utils/utxo/immutable_utxo_diff.go @@ -0,0 +1,86 @@ +package utxo + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/pkg/errors" +) + +type immutableUTXODiff struct { + mutableUTXODiff *mutableUTXODiff + + isInvalidated bool +} + +func (iud *immutableUTXODiff) ToAdd() model.UTXOCollection { + if iud.isInvalidated { + panic("Attempt to read from an invalidated UTXODiff") + } + + return iud.mutableUTXODiff.ToAdd() +} + +func (iud *immutableUTXODiff) ToRemove() model.UTXOCollection { + if iud.isInvalidated { + panic("Attempt to read from an invalidated UTXODiff") + } + + return iud.mutableUTXODiff.ToRemove() +} + +func (iud *immutableUTXODiff) WithDiff(other model.UTXODiff) (model.UTXODiff, error) { + if iud.isInvalidated { + panic("Attempt to read from an invalidated UTXODiff") + } + + return iud.mutableUTXODiff.WithDiff(other) +} + +func (iud *immutableUTXODiff) DiffFrom(other model.UTXODiff) (model.UTXODiff, error) { + if iud.isInvalidated { + panic("Attempt to read from an invalidated UTXODiff") + } + + return iud.mutableUTXODiff.DiffFrom(other) +} + +// NewUTXODiff creates an empty UTXODiff +func NewUTXODiff() model.UTXODiff { + return newUTXODiff() +} + +func newUTXODiff() *immutableUTXODiff { + return &immutableUTXODiff{ + mutableUTXODiff: newMutableUTXODiff(), + isInvalidated: false, + } +} + +// NewUTXODiffFromCollections returns a new UTXODiff with the given toAdd and toRemove collections +func NewUTXODiffFromCollections(toAdd, toRemove model.UTXOCollection) (model.UTXODiff, error) { + add, ok := toAdd.(utxoCollection) + if !ok { + return nil, errors.New("toAdd is not of type utxoCollection") + } + remove, ok := toRemove.(utxoCollection) + if !ok { + return nil, errors.New("toRemove is not of type utxoCollection") + } + return &immutableUTXODiff{ + mutableUTXODiff: &mutableUTXODiff{ + toAdd: add, + toRemove: remove, + }, + }, nil +} + +func (iud *immutableUTXODiff) CloneMutable() model.MutableUTXODiff { + return iud.cloneMutable() +} + +func (iud *immutableUTXODiff) cloneMutable() *mutableUTXODiff { + if iud == nil { + return nil + } + + return iud.mutableUTXODiff.clone() +} diff --git a/domain/consensus/utils/utxo/mutable_utxo_diff.go b/domain/consensus/utils/utxo/mutable_utxo_diff.go new file mode 100644 index 000000000..cae0b6459 --- /dev/null +++ b/domain/consensus/utils/utxo/mutable_utxo_diff.go @@ -0,0 +1,160 @@ +package utxo + +import ( + "fmt" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + "github.com/pkg/errors" +) + +type mutableUTXODiff struct { + toAdd utxoCollection + toRemove utxoCollection + + immutableReferences []*immutableUTXODiff +} + +// NewMutableUTXODiff creates an empty mutable UTXO-Diff +func NewMutableUTXODiff() model.MutableUTXODiff { + return newMutableUTXODiff() +} + +func newMutableUTXODiff() *mutableUTXODiff { + return &mutableUTXODiff{ + toAdd: utxoCollection{}, + toRemove: utxoCollection{}, + } +} + +func (mud *mutableUTXODiff) ToImmutable() model.UTXODiff { + immutableReference := &immutableUTXODiff{ + mutableUTXODiff: mud, + isInvalidated: false, + } + + mud.immutableReferences = append(mud.immutableReferences, immutableReference) + + return immutableReference +} + +func (mud *mutableUTXODiff) invalidateImmutableReferences() { + for _, immutableReference := range mud.immutableReferences { + immutableReference.isInvalidated = true + } + + mud.immutableReferences = nil +} + +func (mud *mutableUTXODiff) WithDiff(other model.UTXODiff) (model.UTXODiff, error) { + o, ok := other.(*immutableUTXODiff) + if !ok { + return nil, errors.New("other is not of type *immutableUTXODiff") + } + + result, err := withDiff(mud, o.mutableUTXODiff) + if err != nil { + return nil, err + } + + return result.ToImmutable(), nil +} + +func (mud *mutableUTXODiff) WithDiffInPlace(other model.UTXODiff) error { + o, ok := other.(*immutableUTXODiff) + if !ok { + return errors.New("other is not of type *immutableUTXODiff") + } + + mud.invalidateImmutableReferences() + + return withDiffInPlace(mud, o.mutableUTXODiff) +} + +func (mud *mutableUTXODiff) DiffFrom(other model.UTXODiff) (model.UTXODiff, error) { + o, ok := other.(*immutableUTXODiff) + if !ok { + return nil, errors.New("other is not of type *immutableUTXODiff") + } + + result, err := diffFrom(mud, o.mutableUTXODiff) + if err != nil { + return nil, err + } + + return result.ToImmutable(), nil +} + +func (mud *mutableUTXODiff) ToAdd() model.UTXOCollection { + return mud.toAdd +} + +func (mud *mutableUTXODiff) ToRemove() model.UTXOCollection { + return mud.toRemove +} +func (mud *mutableUTXODiff) AddTransaction(transaction *externalapi.DomainTransaction, blockBlueScore uint64) error { + mud.invalidateImmutableReferences() + + for _, input := range transaction.Inputs { + err := mud.removeEntry(&input.PreviousOutpoint, input.UTXOEntry) + if err != nil { + return err + } + } + + isCoinbase := transactionhelper.IsCoinBase(transaction) + transactionID := *consensushashing.TransactionID(transaction) + for i, output := range transaction.Outputs { + outpoint := &externalapi.DomainOutpoint{ + TransactionID: transactionID, + Index: uint32(i), + } + entry := NewUTXOEntry(output.Value, output.ScriptPublicKey, isCoinbase, blockBlueScore) + + err := mud.addEntry(outpoint, entry) + if err != nil { + return err + } + } + + return nil +} + +func (mud *mutableUTXODiff) addEntry(outpoint *externalapi.DomainOutpoint, entry externalapi.UTXOEntry) error { + if mud.toRemove.containsWithBlueScore(outpoint, entry.BlockBlueScore()) { + mud.toRemove.remove(outpoint) + } else if mud.toAdd.Contains(outpoint) { + return errors.Errorf("AddEntry: Cannot add outpoint %s twice", outpoint) + } else { + mud.toAdd.add(outpoint, entry) + } + return nil +} + +func (mud *mutableUTXODiff) removeEntry(outpoint *externalapi.DomainOutpoint, entry externalapi.UTXOEntry) error { + if mud.toAdd.containsWithBlueScore(outpoint, entry.BlockBlueScore()) { + mud.toAdd.remove(outpoint) + } else if mud.toRemove.Contains(outpoint) { + return errors.Errorf("removeEntry: Cannot remove outpoint %s twice", outpoint) + } else { + mud.toRemove.add(outpoint, entry) + } + return nil +} + +func (mud *mutableUTXODiff) clone() *mutableUTXODiff { + if mud == nil { + return nil + } + + return &mutableUTXODiff{ + toAdd: mud.toAdd.Clone(), + toRemove: mud.toRemove.Clone(), + } +} + +func (mud *mutableUTXODiff) String() string { + return fmt.Sprintf("toAdd: %s; toRemove: %s", mud.toAdd, mud.toRemove) +} diff --git a/domain/consensus/utils/utxo/serialization.go b/domain/consensus/utils/utxo/serialization.go index c7367da36..5ce29c774 100644 --- a/domain/consensus/utils/utxo/serialization.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -4,19 +4,16 @@ import ( "bytes" "io" - "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" - - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" - - "github.com/pkg/errors" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + "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) { +func SerializeUTXO(entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) ([]byte, error) { w := &bytes.Buffer{} err := serializeOutpoint(w, outpoint) @@ -33,7 +30,7 @@ func SerializeUTXO(entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOut } // DeserializeUTXO deserializes the given byte slice to UTXOEntry-outpoint pair -func DeserializeUTXO(utxoBytes []byte) (entry *externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint, err error) { +func DeserializeUTXO(utxoBytes []byte) (entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint, err error) { r := bytes.NewReader(utxoBytes) outpoint, err = deserializeOutpoint(r) if err != nil { @@ -92,19 +89,19 @@ func deserializeOutpoint(r io.Reader) (*externalapi.DomainOutpoint, error) { }, nil } -func serializeUTXOEntry(w io.Writer, entry *externalapi.UTXOEntry) error { - err := serialization.WriteElements(w, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase) +func serializeUTXOEntry(w io.Writer, entry externalapi.UTXOEntry) error { + err := serialization.WriteElements(w, entry.BlockBlueScore(), entry.Amount(), entry.IsCoinbase()) if err != nil { return err } - count := uint64(len(entry.ScriptPublicKey)) + count := uint64(len(entry.ScriptPublicKey())) err = serialization.WriteElement(w, count) if err != nil { return err } - _, err = w.Write(entry.ScriptPublicKey) + _, err = w.Write(entry.ScriptPublicKey()) if err != nil { return errors.WithStack(err) } @@ -112,23 +109,26 @@ func serializeUTXOEntry(w io.Writer, entry *externalapi.UTXOEntry) error { return nil } -func deserializeUTXOEntry(r io.Reader) (*externalapi.UTXOEntry, error) { - entry := &externalapi.UTXOEntry{} - err := serialization.ReadElements(r, entry.BlockBlueScore, entry.Amount, entry.IsCoinbase) +func deserializeUTXOEntry(r io.Reader) (externalapi.UTXOEntry, error) { + var blockBlueScore uint64 + var amount uint64 + var isCoinbase bool + err := serialization.ReadElements(r, blockBlueScore, amount, isCoinbase) if err != nil { return nil, err } - count := uint64(len(entry.ScriptPublicKey)) - err = serialization.ReadElement(r, count) + var scriptPubKeyLen int + err = serialization.ReadElement(r, scriptPubKeyLen) if err != nil { return nil, err } - _, err = r.Read(entry.ScriptPublicKey) + scriptPubKey := make([]byte, scriptPubKeyLen) + _, err = r.Read(scriptPubKey) if err != nil { return nil, errors.WithStack(err) } - return entry, nil + return NewUTXOEntry(amount, scriptPubKey, isCoinbase, blockBlueScore), nil } diff --git a/domain/consensus/utils/utxo/serialization_test.go b/domain/consensus/utils/utxo/serialization_test.go index 3f8808c53..cb4c1a78f 100644 --- a/domain/consensus/utils/utxo/serialization_test.go +++ b/domain/consensus/utils/utxo/serialization_test.go @@ -12,12 +12,7 @@ func Benchmark_serializeUTXO(b *testing.B) { if err != nil { b.Fatalf("Error decoding scriptPublicKey string: %s", err) } - entry := &externalapi.UTXOEntry{ - Amount: 5000000000, - ScriptPublicKey: scriptPublicKey, // p2pkh - BlockBlueScore: 1432432, - IsCoinbase: false, - } + entry := NewUTXOEntry(5000000000, scriptPublicKey, false, 1432432) outpoint := &externalapi.DomainOutpoint{ TransactionID: externalapi.DomainTransactionID{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, diff --git a/domain/consensus/utils/utxo/utxo_collection.go b/domain/consensus/utils/utxo/utxo_collection.go new file mode 100644 index 000000000..4e409123d --- /dev/null +++ b/domain/consensus/utils/utxo/utxo_collection.go @@ -0,0 +1,95 @@ +package utxo + +import ( + "fmt" + "sort" + "strings" + + "github.com/kaspanet/kaspad/domain/consensus/model" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +type utxoCollection map[externalapi.DomainOutpoint]externalapi.UTXOEntry + +// NewUTXOCollection creates a UTXO-Collection from the given map from outpoint to UTXOEntry +func NewUTXOCollection(utxoMap map[externalapi.DomainOutpoint]externalapi.UTXOEntry) model.UTXOCollection { + return utxoCollection(utxoMap) +} + +// Get returns the model.UTXOEntry represented by provided outpoint, +// and a boolean value indicating if said model.UTXOEntry is in the set or not +func (uc utxoCollection) Get(outpoint *externalapi.DomainOutpoint) (externalapi.UTXOEntry, bool) { + entry, ok := uc[*outpoint] + return entry, ok +} + +// Contains returns a boolean value indicating whether a UTXO entry is in the set +func (uc utxoCollection) Contains(outpoint *externalapi.DomainOutpoint) bool { + _, ok := uc[*outpoint] + return ok +} + +func (uc utxoCollection) Len() int { + return len(uc) +} + +func (uc utxoCollection) Clone() utxoCollection { + if uc == nil { + return nil + } + + clone := make(utxoCollection, len(uc)) + for outpoint, entry := range uc { + clone[outpoint] = entry + } + + return clone +} + +func (uc utxoCollection) String() string { + utxoStrings := make([]string, len(uc)) + + i := 0 + for outpoint, utxoEntry := range uc { + utxoStrings[i] = fmt.Sprintf("(%s, %d) => %d, blueScore: %d", + outpoint.TransactionID, outpoint.Index, utxoEntry.Amount(), utxoEntry.BlockBlueScore()) + i++ + } + + // Sort strings for determinism. + sort.Strings(utxoStrings) + + return fmt.Sprintf("[ %s ]", strings.Join(utxoStrings, ", ")) +} + +// add adds a new UTXO entry to this collection +func (uc utxoCollection) add(outpoint *externalapi.DomainOutpoint, entry externalapi.UTXOEntry) { + uc[*outpoint] = entry +} + +// addMultiple adds multiple UTXO entries to this collection +func (uc utxoCollection) addMultiple(collectionToAdd utxoCollection) { + for outpoint, entry := range collectionToAdd { + uc[outpoint] = entry + } +} + +// remove removes a UTXO entry from this collection if it exists +func (uc utxoCollection) remove(outpoint *externalapi.DomainOutpoint) { + delete(uc, *outpoint) +} + +// removeMultiple removes multiple UTXO entries from this collection if it exists +func (uc utxoCollection) removeMultiple(collectionToRemove utxoCollection) { + for outpoint := range collectionToRemove { + delete(uc, outpoint) + } +} + +// containsWithBlueScore returns a boolean value indicating whether a model.UTXOEntry +// is in the set and its blue score is equal to the given blue score. +func (uc utxoCollection) containsWithBlueScore(outpoint *externalapi.DomainOutpoint, blueScore uint64) bool { + entry, ok := uc.Get(outpoint) + return ok && entry.BlockBlueScore() == blueScore +} diff --git a/domain/consensus/utils/utxo/utxo_entry.go b/domain/consensus/utils/utxo/utxo_entry.go new file mode 100644 index 000000000..68b63793e --- /dev/null +++ b/domain/consensus/utils/utxo/utxo_entry.go @@ -0,0 +1,40 @@ +package utxo + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +type utxoEntry struct { + amount uint64 + scriptPublicKey []byte + blockBlueScore uint64 + isCoinbase bool +} + +// NewUTXOEntry creates a new utxoEntry representing the given txOut +func NewUTXOEntry(amount uint64, scriptPubKey []byte, isCoinbase bool, blockBlueScore uint64) externalapi.UTXOEntry { + scriptPubKeyClone := make([]byte, len(scriptPubKey)) + copy(scriptPubKeyClone, scriptPubKey) + return &utxoEntry{ + amount: amount, + scriptPublicKey: scriptPubKeyClone, + blockBlueScore: blockBlueScore, + isCoinbase: isCoinbase, + } +} + +func (u *utxoEntry) Amount() uint64 { + return u.amount +} + +func (u *utxoEntry) ScriptPublicKey() []byte { + clone := make([]byte, len(u.scriptPublicKey)) + copy(clone, u.scriptPublicKey) + return clone +} + +func (u *utxoEntry) BlockBlueScore() uint64 { + return u.blockBlueScore +} + +func (u *utxoEntry) IsCoinbase() bool { + return u.isCoinbase +} diff --git a/domain/consensus/utils/utxo/utxo_iterator.go b/domain/consensus/utils/utxo/utxo_iterator.go index d75b33c5d..b78154ba2 100644 --- a/domain/consensus/utils/utxo/utxo_iterator.go +++ b/domain/consensus/utils/utxo/utxo_iterator.go @@ -3,11 +3,12 @@ package utxo import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" ) type utxoOutpointEntryPair struct { outpoint externalapi.DomainOutpoint - entry *externalapi.UTXOEntry + entry externalapi.UTXOEntry } type utxoCollectionIterator struct { @@ -15,11 +16,10 @@ type utxoCollectionIterator struct { pairs []utxoOutpointEntryPair } -// CollectionIterator creates a utxo iterator from give UTXO collection -func CollectionIterator(collection model.UTXOCollection) model.ReadOnlyUTXOSetIterator { - pairs := make([]utxoOutpointEntryPair, len(collection)) +func (uc utxoCollection) Iterator() model.ReadOnlyUTXOSetIterator { + pairs := make([]utxoOutpointEntryPair, len(uc)) i := 0 - for outpoint, entry := range collection { + for outpoint, entry := range uc { pairs[i] = utxoOutpointEntryPair{ outpoint: outpoint, entry: entry, @@ -29,12 +29,25 @@ func CollectionIterator(collection model.UTXOCollection) model.ReadOnlyUTXOSetIt return &utxoCollectionIterator{index: -1, pairs: pairs} } -func (u *utxoCollectionIterator) Next() bool { - u.index++ - return u.index < len(u.pairs) +func (uci *utxoCollectionIterator) Next() bool { + uci.index++ + return uci.index < len(uci.pairs) } -func (u *utxoCollectionIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { - pair := u.pairs[u.index] +func (uci *utxoCollectionIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) { + pair := uci.pairs[uci.index] return &pair.outpoint, pair.entry, nil } + +func (uci *utxoCollectionIterator) WithDiff(diff model.UTXODiff) (model.ReadOnlyUTXOSetIterator, error) { + d, ok := diff.(*immutableUTXODiff) + if !ok { + return nil, errors.New("diff is not of type *immutableUTXODiff") + } + + return &readOnlyUTXOIteratorWithDiff{ + baseIterator: uci, + diff: d, + toAddIterator: diff.ToAdd().Iterator(), + }, nil +} diff --git a/domain/consensus/utils/utxo/utxo_iterator_with_diff.go b/domain/consensus/utils/utxo/utxo_iterator_with_diff.go index f8b0da037..1a92aea08 100644 --- a/domain/consensus/utils/utxo/utxo_iterator_with_diff.go +++ b/domain/consensus/utils/utxo/utxo_iterator_with_diff.go @@ -3,24 +3,29 @@ package utxo import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxo/utxoalgebra" + "github.com/pkg/errors" ) type readOnlyUTXOIteratorWithDiff struct { baseIterator model.ReadOnlyUTXOSetIterator - diff *model.UTXODiff + diff *immutableUTXODiff currentOutpoint *externalapi.DomainOutpoint - currentUTXOEntry *externalapi.UTXOEntry + currentUTXOEntry externalapi.UTXOEntry currentErr error toAddIterator model.ReadOnlyUTXOSetIterator } // IteratorWithDiff applies a UTXODiff to given utxo iterator -func IteratorWithDiff(iterator model.ReadOnlyUTXOSetIterator, diff *model.UTXODiff) (model.ReadOnlyUTXOSetIterator, error) { +func IteratorWithDiff(iterator model.ReadOnlyUTXOSetIterator, diff model.UTXODiff) (model.ReadOnlyUTXOSetIterator, error) { + d, ok := diff.(*immutableUTXODiff) + if !ok { + return nil, errors.New("diff is not of type *immutableUTXODiff") + } + if iteratorWithDiff, ok := iterator.(*readOnlyUTXOIteratorWithDiff); ok { - combinedDiff, err := utxoalgebra.WithDiff(iteratorWithDiff.diff, diff) + combinedDiff, err := iteratorWithDiff.diff.WithDiff(d) if err != nil { return nil, err } @@ -30,15 +35,15 @@ func IteratorWithDiff(iterator model.ReadOnlyUTXOSetIterator, diff *model.UTXODi return &readOnlyUTXOIteratorWithDiff{ baseIterator: iterator, - diff: diff, - toAddIterator: CollectionIterator(diff.ToAdd), + diff: d, + toAddIterator: d.mutableUTXODiff.toAdd.Iterator(), }, nil } func (r *readOnlyUTXOIteratorWithDiff) Next() bool { - for r.baseIterator.Next() { // keep looping until we reach an outpoint/entry pair that is not in r.diff.ToRemove + for r.baseIterator.Next() { // keep looping until we reach an outpoint/entry pair that is not in r.diff.toRemove r.currentOutpoint, r.currentUTXOEntry, r.currentErr = r.baseIterator.Get() - if !utxoalgebra.CollectionContainsWithBlueScore(r.diff.ToRemove, r.currentOutpoint, r.currentUTXOEntry.BlockBlueScore) { + if !r.diff.mutableUTXODiff.toRemove.containsWithBlueScore(r.currentOutpoint, r.currentUTXOEntry.BlockBlueScore()) { return true } } @@ -51,6 +56,6 @@ func (r *readOnlyUTXOIteratorWithDiff) Next() bool { return false } -func (r *readOnlyUTXOIteratorWithDiff) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry, err error) { +func (r *readOnlyUTXOIteratorWithDiff) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) { return r.currentOutpoint, r.currentUTXOEntry, r.currentErr } diff --git a/domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go b/domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go deleted file mode 100644 index f0e969cf0..000000000 --- a/domain/consensus/utils/utxo/utxoalgebra/collection_helpers.go +++ /dev/null @@ -1,50 +0,0 @@ -package utxoalgebra - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// add adds a new UTXO entry to this collection -func collectionAdd(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint, entry *externalapi.UTXOEntry) { - collection[*outpoint] = entry -} - -// addMultiple adds multiple UTXO entries to this collection -func collectionAddMultiple(collection model.UTXOCollection, collectionToAdd model.UTXOCollection) { - for outpoint, entry := range collectionToAdd { - collection[outpoint] = entry - } -} - -// remove removes a UTXO entry from this collection if it exists -func collectionRemove(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint) { - delete(collection, *outpoint) -} - -// removeMultiple removes multiple UTXO entries from this collection if it exists -func collectionRemoveMultiple(collection model.UTXOCollection, collectionToRemove model.UTXOCollection) { - for outpoint := range collectionToRemove { - delete(collection, outpoint) - } -} - -// CollectionGet returns the model.UTXOEntry represented by provided outpoint, -// and a boolean value indicating if said model.UTXOEntry is in the set or not -func CollectionGet(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint) (*externalapi.UTXOEntry, bool) { - entry, ok := collection[*outpoint] - return entry, ok -} - -// CollectionContains returns a boolean value indicating whether a UTXO entry is in the set -func CollectionContains(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint) bool { - _, ok := collection[*outpoint] - return ok -} - -// CollectionContainsWithBlueScore returns a boolean value indicating whether a model.UTXOEntry -// is in the set and its blue score is equal to the given blue score. -func CollectionContainsWithBlueScore(collection model.UTXOCollection, outpoint *externalapi.DomainOutpoint, blueScore uint64) bool { - entry, ok := CollectionGet(collection, outpoint) - return ok && entry.BlockBlueScore == blueScore -} diff --git a/domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go b/domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go deleted file mode 100644 index ad186c74c..000000000 --- a/domain/consensus/utils/utxo/utxoalgebra/diff_algebra.go +++ /dev/null @@ -1,253 +0,0 @@ -package utxoalgebra - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" -) - -// checkIntersection checks if there is an intersection between two model.UTXOCollections -func checkIntersection(collection1 model.UTXOCollection, collection2 model.UTXOCollection) bool { - for outpoint := range collection1 { - if CollectionContains(collection2, &outpoint) { - return true - } - } - - return false -} - -// checkIntersectionWithRule checks if there is an intersection between two model.UTXOCollections satisfying arbitrary rule -// returns the first outpoint in the two collections' intersection satsifying the rule, and a boolean indicating whether -// such outpoint exists -func checkIntersectionWithRule(collection1 model.UTXOCollection, collection2 model.UTXOCollection, - extraRule func(*externalapi.DomainOutpoint, *externalapi.UTXOEntry, *externalapi.UTXOEntry) bool) ( - *externalapi.DomainOutpoint, bool) { - - for outpoint, utxoEntry := range collection1 { - if diffEntry, ok := CollectionGet(collection2, &outpoint); ok { - if extraRule(&outpoint, utxoEntry, diffEntry) { - return &outpoint, true - } - } - } - - return nil, false -} - -// minInt returns the smaller of x or y integer values -func minInt(a, b int) int { - if a < b { - return a - } - return b -} - -// intersectionWithRemainderHavingBlueScore calculates an intersection between two model.UTXOCollections -// having same blue score, returns the result and the remainder from collection1 -func intersectionWithRemainderHavingBlueScore(collection1, collection2 model.UTXOCollection) (result, remainder model.UTXOCollection) { - result = make(model.UTXOCollection, minInt(len(collection1), len(collection2))) - remainder = make(model.UTXOCollection, len(collection1)) - intersectionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder) - return -} - -// intersectionWithRemainderHavingBlueScoreInPlace calculates an intersection between two model.UTXOCollections -// having same blue score, puts it into result and into remainder from collection1 -func intersectionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder model.UTXOCollection) { - for outpoint, utxoEntry := range collection1 { - if CollectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { - collectionAdd(result, &outpoint, utxoEntry) - } else { - collectionAdd(remainder, &outpoint, utxoEntry) - } - } -} - -// subtractionHavingBlueScore calculates a subtraction between collection1 and collection2 -// having same blue score, returns the result -func subtractionHavingBlueScore(collection1, collection2 model.UTXOCollection) (result model.UTXOCollection) { - result = make(model.UTXOCollection, len(collection1)) - - subtractionHavingBlueScoreInPlace(collection1, collection2, result) - return -} - -// subtractionHavingBlueScoreInPlace calculates a subtraction between collection1 and collection2 -// having same blue score, puts it into result -func subtractionHavingBlueScoreInPlace(collection1, collection2, result model.UTXOCollection) { - for outpoint, utxoEntry := range collection1 { - if !CollectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { - collectionAdd(result, &outpoint, utxoEntry) - } - } -} - -// subtractionWithRemainderHavingBlueScore calculates a subtraction between collection1 and collection2 -// having same blue score, returns the result and the remainder from collection1 -func subtractionWithRemainderHavingBlueScore(collection1, collection2 model.UTXOCollection) (result, remainder model.UTXOCollection) { - result = make(model.UTXOCollection, len(collection1)) - remainder = make(model.UTXOCollection, len(collection1)) - - subtractionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder) - return -} - -// subtractionWithRemainderHavingBlueScoreInPlace calculates a subtraction between collection1 and collection2 -// having same blue score, puts it into result and into remainder from collection1 -func subtractionWithRemainderHavingBlueScoreInPlace(collection1, collection2, result, remainder model.UTXOCollection) { - for outpoint, utxoEntry := range collection1 { - if !CollectionContainsWithBlueScore(collection2, &outpoint, utxoEntry.BlockBlueScore) { - collectionAdd(result, &outpoint, utxoEntry) - } else { - collectionAdd(remainder, &outpoint, utxoEntry) - } - } -} - -// DiffFrom returns a new utxoDiff with the difference between this utxoDiff and another -// Assumes that: -// Both utxoDiffs are from the same base -// If a txOut exists in both utxoDiffs, its underlying values would be the same -// -// diffFrom follows a set of rules represented by the following 3 by 3 table: -// -// | | this | | -// ---------+-----------+-----------+-----------+----------- -// | | ToAdd | ToRemove | None -// ---------+-----------+-----------+-----------+----------- -// other | ToAdd | - | X | ToAdd -// ---------+-----------+-----------+-----------+----------- -// | ToRemove | X | - | ToRemove -// ---------+-----------+-----------+-----------+----------- -// | None | ToRemove | ToAdd | - -// -// Key: -// - Don't add anything to the result -// X Return an error -// ToAdd Add the UTXO into the ToAdd collection of the result -// ToRemove Add the UTXO into the ToRemove collection of the result -// -// Examples: -// 1. This diff contains a UTXO in ToAdd, and the other diff contains it in ToRemove -// diffFrom results in an error -// 2. This diff contains a UTXO in ToRemove, and the other diff does not contain it -// diffFrom results in the UTXO being added to ToAdd -func DiffFrom(this, other *model.UTXODiff) (*model.UTXODiff, error) { - // Note that the following cases are not accounted for, as they are impossible - // as long as the base utxoSet is the same: - // - if utxoEntry is in this.ToAdd and other.ToRemove - // - if utxoEntry is in this.ToRemove and other.ToAdd - - // check that NOT (entries with unequal blue scores AND utxoEntry is in this.ToAdd and/or other.ToRemove) -> Error - isNotAddedOutputRemovedWithBlueScore := func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry *externalapi.UTXOEntry) bool { - return !(diffEntry.BlockBlueScore != utxoEntry.BlockBlueScore && - (CollectionContainsWithBlueScore(this.ToAdd, outpoint, diffEntry.BlockBlueScore) || - CollectionContainsWithBlueScore(other.ToRemove, outpoint, utxoEntry.BlockBlueScore))) - } - - if offendingOutpoint, ok := - checkIntersectionWithRule(this.ToRemove, other.ToAdd, isNotAddedOutputRemovedWithBlueScore); ok { - return nil, errors.Errorf("diffFrom: outpoint %s both in this.ToAdd and in other.ToRemove", offendingOutpoint) - } - - //check that NOT (entries with unequal blue score AND utxoEntry is in this.ToRemove and/or other.ToAdd) -> Error - isNotRemovedOutputAddedWithBlueScore := - func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry *externalapi.UTXOEntry) bool { - - return !(diffEntry.BlockBlueScore != utxoEntry.BlockBlueScore && - (CollectionContainsWithBlueScore(this.ToRemove, outpoint, diffEntry.BlockBlueScore) || - CollectionContainsWithBlueScore(other.ToAdd, outpoint, utxoEntry.BlockBlueScore))) - } - - if offendingOutpoint, ok := - checkIntersectionWithRule(this.ToAdd, other.ToRemove, isNotRemovedOutputAddedWithBlueScore); ok { - return nil, errors.Errorf("diffFrom: outpoint %s both in this.ToRemove and in other.ToAdd", offendingOutpoint) - } - - // if have the same entry in this.ToRemove and other.ToRemove - // and existing entry is with different blue score, in this case - this is an error - if offendingOutpoint, ok := checkIntersectionWithRule(this.ToRemove, other.ToRemove, - func(outpoint *externalapi.DomainOutpoint, utxoEntry, diffEntry *externalapi.UTXOEntry) bool { - return utxoEntry.BlockBlueScore != diffEntry.BlockBlueScore - }); ok { - return nil, errors.Errorf("diffFrom: outpoint %s both in this.ToRemove and other.ToRemove with different "+ - "blue scores, with no corresponding entry in this.ToAdd", offendingOutpoint) - } - - result := model.UTXODiff{ - ToAdd: make(model.UTXOCollection, len(this.ToRemove)+len(other.ToAdd)), - ToRemove: make(model.UTXOCollection, len(this.ToAdd)+len(other.ToRemove)), - } - - // All transactions in this.ToAdd: - // If they are not in other.ToAdd - should be added in result.ToRemove - inBothToAdd := make(model.UTXOCollection, len(this.ToAdd)) - subtractionWithRemainderHavingBlueScoreInPlace(this.ToAdd, other.ToAdd, result.ToRemove, inBothToAdd) - // If they are in other.ToRemove - base utxoSet is not the same - if checkIntersection(inBothToAdd, this.ToRemove) != checkIntersection(inBothToAdd, other.ToRemove) { - return nil, errors.New( - "diffFrom: outpoint both in this.ToAdd, other.ToAdd, and only one of this.ToRemove and other.ToRemove") - } - - // All transactions in other.ToRemove: - // If they are not in this.ToRemove - should be added in result.ToRemove - subtractionHavingBlueScoreInPlace(other.ToRemove, this.ToRemove, result.ToRemove) - - // All transactions in this.ToRemove: - // If they are not in other.ToRemove - should be added in result.ToAdd - subtractionHavingBlueScoreInPlace(this.ToRemove, other.ToRemove, result.ToAdd) - - // All transactions in other.ToAdd: - // If they are not in this.ToAdd - should be added in result.ToAdd - subtractionHavingBlueScoreInPlace(other.ToAdd, this.ToAdd, result.ToAdd) - - return &result, nil -} - -// WithDiffInPlace applies provided diff to this diff in-place, that would be the result if -// first d, and than diff were applied to the same base -func WithDiffInPlace(this *model.UTXODiff, diff *model.UTXODiff) error { - if offendingOutpoint, ok := checkIntersectionWithRule(diff.ToRemove, this.ToRemove, - func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry *externalapi.UTXOEntry) bool { - return !CollectionContainsWithBlueScore(this.ToAdd, outpoint, entryToAdd.BlockBlueScore) - }); ok { - return errors.Errorf( - "withDiffInPlace: outpoint %s both in this.ToRemove and in diff.ToRemove", offendingOutpoint) - } - - if offendingOutpoint, ok := checkIntersectionWithRule(diff.ToAdd, this.ToAdd, - func(outpoint *externalapi.DomainOutpoint, entryToAdd, existingEntry *externalapi.UTXOEntry) bool { - return !CollectionContainsWithBlueScore(diff.ToRemove, outpoint, existingEntry.BlockBlueScore) - }); ok { - return errors.Errorf( - "withDiffInPlace: outpoint %s both in this.ToAdd and in diff.ToAdd", offendingOutpoint) - } - - intersection := make(model.UTXOCollection, minInt(len(diff.ToRemove), len(this.ToAdd))) - // If not exists neither in ToAdd nor in ToRemove - add to ToRemove - intersectionWithRemainderHavingBlueScoreInPlace(diff.ToRemove, this.ToAdd, intersection, this.ToRemove) - // If already exists in ToAdd with the same blueScore - remove from ToAdd - collectionRemoveMultiple(this.ToAdd, intersection) - - intersection = make(model.UTXOCollection, minInt(len(diff.ToAdd), len(this.ToRemove))) - // If not exists neither in ToAdd nor in ToRemove, or exists in ToRemove with different blueScore - add to ToAdd - intersectionWithRemainderHavingBlueScoreInPlace(diff.ToAdd, this.ToRemove, intersection, this.ToAdd) - // If already exists in ToRemove with the same blueScore - remove from ToRemove - collectionRemoveMultiple(this.ToRemove, intersection) - - return nil -} - -// WithDiff applies provided diff to this diff, creating a new utxoDiff, that would be the result if -// first d, and than diff were applied to some base -func WithDiff(this *model.UTXODiff, diff *model.UTXODiff) (*model.UTXODiff, error) { - clone := this.Clone() - - err := WithDiffInPlace(clone, diff) - if err != nil { - return nil, err - } - - return clone, nil -} diff --git a/domain/consensus/utils/utxo/utxoalgebra/diff_algebra_test.go b/domain/consensus/utils/utxo/utxoalgebra/diff_algebra_test.go deleted file mode 100644 index e42e9514e..000000000 --- a/domain/consensus/utils/utxo/utxoalgebra/diff_algebra_test.go +++ /dev/null @@ -1,608 +0,0 @@ -package utxoalgebra - -import ( - "reflect" - "testing" - - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" - - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// TestUTXOCollection makes sure that model.UTXOCollection cloning and string representations work as expected. -func TestUTXOCollection(t *testing.T) { - txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") - txID1, _ := transactionid.FromString("1111111111111111111111111111111111111111111111111111111111111111") - outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) - outpoint1 := externalapi.NewDomainOutpoint(txID1, 0) - utxoEntry0 := externalapi.NewUTXOEntry(10, []byte{}, true, 0) - utxoEntry1 := externalapi.NewUTXOEntry(20, []byte{}, false, 1) - - // For each of the following test cases, we will: - // .String() the given collection and compare it to expectedStringWithMultiset - // .clone() the given collection and compare its value to itself (expected: equals) and its reference to itself (expected: not equal) - tests := []struct { - name string - collection model.UTXOCollection - expectedString string - }{ - { - name: "empty collection", - collection: model.UTXOCollection{}, - expectedString: "[ ]", - }, - { - name: "one member", - collection: model.UTXOCollection{ - *outpoint0: utxoEntry1, - }, - expectedString: "[ (0000000000000000000000000000000000000000000000000000000000000000, 0) => 20, blueScore: 1 ]", - }, - { - name: "two members", - collection: model.UTXOCollection{ - *outpoint0: utxoEntry0, - *outpoint1: utxoEntry1, - }, - expectedString: "[ (0000000000000000000000000000000000000000000000000000000000000000, 0) => 10, blueScore: 0, (1111111111111111111111111111111111111111111111111111111111111111, 0) => 20, blueScore: 1 ]", - }, - } - - for _, test := range tests { - // Test model.UTXOCollection string representation - collectionString := test.collection.String() - if collectionString != test.expectedString { - t.Errorf("unexpected string in test \"%s\". "+ - "Expected: \"%s\", got: \"%s\".", test.name, test.expectedString, collectionString) - } - - // Test model.UTXOCollection cloning - collectionClone := test.collection.Clone() - if reflect.ValueOf(collectionClone).Pointer() == reflect.ValueOf(test.collection).Pointer() { - t.Errorf("collection is reference-equal to its clone in test \"%s\". ", test.name) - } - if !reflect.DeepEqual(test.collection, collectionClone) { - t.Errorf("collection is not equal to its clone in test \"%s\". "+ - "Expected: \"%s\", got: \"%s\".", test.name, collectionString, collectionClone.String()) - } - } -} - -// Testmodel.UTXODiff makes sure that utxoDiff creation, cloning, and string representations work as expected. -func TestUTXODiff(t *testing.T) { - txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") - txID1, _ := transactionid.FromString("1111111111111111111111111111111111111111111111111111111111111111") - outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) - outpoint1 := externalapi.NewDomainOutpoint(txID1, 0) - utxoEntry0 := externalapi.NewUTXOEntry(10, []byte{}, true, 0) - utxoEntry1 := externalapi.NewUTXOEntry(20, []byte{}, false, 1) - - diff := model.NewUTXODiff() - - if len(diff.ToAdd) != 0 || len(diff.ToRemove) != 0 { - t.Errorf("new diff is not empty") - } - - err := diffAddEntry(diff, outpoint0, utxoEntry0) - if err != nil { - t.Fatalf("error adding entry to utxo diff: %s", err) - } - - err = diffRemoveEntry(diff, outpoint1, utxoEntry1) - if err != nil { - t.Fatalf("error adding entry to utxo diff: %s", err) - } - - // Test utxoDiff cloning - clonedDiff := diff.Clone() - if clonedDiff == diff { - t.Errorf("cloned diff is reference-equal to the original") - } - if !reflect.DeepEqual(clonedDiff, diff) { - t.Errorf("cloned diff not equal to the original"+ - "Original: \"%v\", cloned: \"%v\".", diff, clonedDiff) - } - - // Test utxoDiff string representation - expectedDiffString := "ToAdd: [ (0000000000000000000000000000000000000000000000000000000000000000, 0) => 10, blueScore: 0 ]; ToRemove: [ (1111111111111111111111111111111111111111111111111111111111111111, 0) => 20, blueScore: 1 ]" - diffString := clonedDiff.String() - if diffString != expectedDiffString { - t.Errorf("unexpected diff string. "+ - "Expected: \"%s\", got: \"%s\".", expectedDiffString, diffString) - } -} - -// Testmodel.UTXODiffRules makes sure that all diffFrom and WithDiff rules are followed. -// Each test case represents a cell in the two tables outlined in the documentation for utxoDiff. -func TestUTXODiffRules(t *testing.T) { - txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") - outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) - utxoEntry1 := externalapi.NewUTXOEntry(10, []byte{}, true, 0) - utxoEntry2 := externalapi.NewUTXOEntry(20, []byte{}, true, 1) - - // For each of the following test cases, we will: - // this.diffFrom(other) and compare it to expectedDiffFromResult - // this.WithDiff(other) and compare it to expectedWithDiffResult - // this.withDiffInPlace(other) and compare it to expectedWithDiffResult - // - // Note: an expected nil result means that we expect the respective operation to fail - // See the following spreadsheet for a summary of all test-cases: - // https://docs.google.com/spreadsheets/d/1E8G3mp5y1-yifouwLLXRLueSRfXdDRwRKFieYE07buY/edit?usp=sharing - tests := []struct { - name string - this *model.UTXODiff - other *model.UTXODiff - expectedDiffFromResult *model.UTXODiff - expectedWithDiffResult *model.UTXODiff - }{ - { - name: "first ToAdd in this, first ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd in this, second in ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd in this, second in ToRemove in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - }, - { - name: "first in ToAdd in this and other, second in ToRemove in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd in this and ToRemove in other, second in ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{}, - }, - }, - { - name: "first in ToAdd in this, empty other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - }, - { - name: "first in ToRemove in this and in ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - }, - { - name: "first in ToRemove in this, second in ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - }, - { - name: "first in ToRemove in this and other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: nil, - }, - { - name: "first in ToRemove in this, second in ToRemove in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: nil, - }, - { - name: "first in ToRemove in this and ToAdd in other, second in ToRemove in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: nil, - }, - { - name: "first in ToRemove in this and other, second in ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: nil, - }, - { - name: "first in ToRemove in this, empty other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - }, - { - name: "first in ToAdd in this and other, second in ToRemove in this", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd in this, second in ToRemove in this and ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd in this and ToRemove in other, second in ToRemove in this", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - }, - { - name: "first in ToAdd in this, second in ToRemove in this and in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd and second in ToRemove in both this and other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: nil, - }, - { - name: "first in ToAdd in this and ToRemove in other, second in ToRemove in this and ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: nil, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - }, - { - name: "first in ToAdd and second in ToRemove in this, empty other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry2}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - }, - { - name: "empty this, first in ToAdd in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{}, - }, - }, - { - name: "empty this, first in ToRemove in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry1}, - }, - }, - { - name: "empty this, first in ToAdd and second in ToRemove in other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{*outpoint0: utxoEntry1}, - ToRemove: model.UTXOCollection{*outpoint0: utxoEntry2}, - }, - }, - { - name: "empty this, empty other", - this: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - other: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedDiffFromResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - expectedWithDiffResult: &model.UTXODiff{ - ToAdd: model.UTXOCollection{}, - ToRemove: model.UTXOCollection{}, - }, - }, - } - - for _, test := range tests { - // diffFrom from test.this to test.other - diffResult, err := DiffFrom(test.this, test.other) - - // Test whether diffFrom returned an error - isDiffFromOk := err == nil - expectedIsDiffFromOk := test.expectedDiffFromResult != nil - if isDiffFromOk != expectedIsDiffFromOk { - t.Errorf("unexpected diffFrom error in test \"%s\". "+ - "Expected: \"%t\", got: \"%t\".", test.name, expectedIsDiffFromOk, isDiffFromOk) - } - - // If not error, test the diffFrom result - if isDiffFromOk && !diffEqual(test.expectedDiffFromResult, diffResult) { - t.Errorf("unexpected diffFrom result in test \"%s\". "+ - "Expected: \"%v\", got: \"%v\".", test.name, test.expectedDiffFromResult, diffResult) - } - - // Make sure that WithDiff after diffFrom results in the original test.other - if isDiffFromOk { - otherResult, err := WithDiff(test.this, diffResult) - if err != nil { - t.Errorf("WithDiff unexpectedly failed in test \"%s\": %s", test.name, err) - } - if !diffEqual(test.other, otherResult) { - t.Errorf("unexpected WithDiff result in test \"%s\". "+ - "Expected: \"%v\", got: \"%v\".", test.name, test.other, otherResult) - } - } - - // WithDiff from test.this to test.other - withDiffResult, err := WithDiff(test.this, test.other) - - // Test whether WithDiff returned an error - isWithDiffOk := err == nil - expectedIsWithDiffOk := test.expectedWithDiffResult != nil - if isWithDiffOk != expectedIsWithDiffOk { - t.Errorf("unexpected WithDiff error in test \"%s\". "+ - "Expected: \"%t\", got: \"%t\".", test.name, expectedIsWithDiffOk, isWithDiffOk) - } - - // If not error, test the WithDiff result - if isWithDiffOk && !diffEqual(withDiffResult, test.expectedWithDiffResult) { - t.Errorf("unexpected WithDiff result in test \"%s\". "+ - "Expected: \"%v\", got: \"%v\".", test.name, test.expectedWithDiffResult, withDiffResult) - } - - // Repeat WithDiff check test.this time using withDiffInPlace - thisClone := test.this.Clone() - err = WithDiffInPlace(thisClone, test.other) - - // Test whether withDiffInPlace returned an error - isWithDiffInPlaceOk := err == nil - expectedIsWithDiffInPlaceOk := test.expectedWithDiffResult != nil - if isWithDiffInPlaceOk != expectedIsWithDiffInPlaceOk { - t.Errorf("unexpected withDiffInPlace error in test \"%s\". "+ - "Expected: \"%t\", got: \"%t\".", test.name, expectedIsWithDiffInPlaceOk, isWithDiffInPlaceOk) - } - - // If not error, test the withDiffInPlace result - if isWithDiffInPlaceOk && !diffEqual(thisClone, test.expectedWithDiffResult) { - t.Errorf("unexpected withDiffInPlace result in test \"%s\". "+ - "Expected: \"%v\", got: \"%v\".", test.name, test.expectedWithDiffResult, thisClone) - } - - // Make sure that diffFrom after WithDiff results in the original test.other - if isWithDiffOk { - otherResult, err := DiffFrom(test.this, withDiffResult) - if err != nil { - t.Errorf("diffFrom unexpectedly failed in test \"%s\": %s", test.name, err) - } - if !diffEqual(test.other, otherResult) { - t.Errorf("unexpected diffFrom result in test \"%s\". "+ - "Expected: \"%v\", got: \"%v\".", test.name, test.other, otherResult) - } - } - } -} diff --git a/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go b/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go deleted file mode 100644 index 9ad870383..000000000 --- a/domain/consensus/utils/utxo/utxoalgebra/diff_helpers.go +++ /dev/null @@ -1,76 +0,0 @@ -package utxoalgebra - -import ( - "reflect" - - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" -) - -// DiffAddTransaction modifies the provided utxoDiff with provided transaction. -func DiffAddTransaction(utxoDiff *model.UTXODiff, transaction *externalapi.DomainTransaction, blockBlueScore uint64) error { - for _, input := range transaction.Inputs { - err := diffRemoveEntry(utxoDiff, &input.PreviousOutpoint, input.UTXOEntry) - if err != nil { - return err - } - } - - isCoinbase := transactionhelper.IsCoinBase(transaction) - transactionID := *consensushashing.TransactionID(transaction) - for i, output := range transaction.Outputs { - outpoint := &externalapi.DomainOutpoint{ - TransactionID: transactionID, - Index: uint32(i), - } - entry := &externalapi.UTXOEntry{ - Amount: output.Value, - ScriptPublicKey: output.ScriptPublicKey, - BlockBlueScore: blockBlueScore, - IsCoinbase: isCoinbase, - } - - err := diffAddEntry(utxoDiff, outpoint, entry) - if err != nil { - return err - } - } - - return nil -} - -func diffAddEntry(diff *model.UTXODiff, outpoint *externalapi.DomainOutpoint, entry *externalapi.UTXOEntry) error { - if CollectionContainsWithBlueScore(diff.ToRemove, outpoint, entry.BlockBlueScore) { - collectionRemove(diff.ToRemove, outpoint) - } else if _, exists := diff.ToAdd[*outpoint]; exists { - return errors.Errorf("AddEntry: Cannot add outpoint %s twice", outpoint) - } else { - collectionAdd(diff.ToAdd, outpoint, entry) - } - return nil -} - -func diffRemoveEntry(diff *model.UTXODiff, outpoint *externalapi.DomainOutpoint, entry *externalapi.UTXOEntry) error { - if CollectionContainsWithBlueScore(diff.ToAdd, outpoint, entry.BlockBlueScore) { - collectionRemove(diff.ToAdd, outpoint) - } else if _, exists := diff.ToRemove[*outpoint]; exists { - return errors.Errorf("removeEntry: Cannot remove outpoint %s twice", outpoint) - } else { - collectionAdd(diff.ToRemove, outpoint, entry) - } - return nil -} - -func diffEqual(this *model.UTXODiff, other *model.UTXODiff) bool { - if this == nil || other == nil { - return this == other - } - - return reflect.DeepEqual(this.ToAdd, other.ToAdd) && - reflect.DeepEqual(this.ToRemove, other.ToRemove) -} diff --git a/domain/miningmanager/mempool/mempool_utxoset.go b/domain/miningmanager/mempool/mempool_utxoset.go index e13c71c4e..830b8b516 100644 --- a/domain/miningmanager/mempool/mempool_utxoset.go +++ b/domain/miningmanager/mempool/mempool_utxoset.go @@ -3,6 +3,8 @@ package mempool import ( "math" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/pkg/errors" @@ -13,13 +15,13 @@ const unacceptedBlueScore = math.MaxUint64 func newMempoolUTXOSet() *mempoolUTXOSet { return &mempoolUTXOSet{ transactionByPreviousOutpoint: make(map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.DomainTransaction), - poolUnspentOutputs: make(map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.UTXOEntry), + poolUnspentOutputs: make(map[consensusexternalapi.DomainOutpoint]consensusexternalapi.UTXOEntry), } } type mempoolUTXOSet struct { transactionByPreviousOutpoint map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.DomainTransaction - poolUnspentOutputs map[consensusexternalapi.DomainOutpoint]*consensusexternalapi.UTXOEntry + poolUnspentOutputs map[consensusexternalapi.DomainOutpoint]consensusexternalapi.UTXOEntry } // Populate UTXO Entries in the transaction, to allow chained txs. @@ -67,12 +69,8 @@ func (mpus *mempoolUTXOSet) addTx(tx *consensusexternalapi.DomainTransaction) er if _, exists := mpus.poolUnspentOutputs[outpoint]; exists { return errors.Errorf("outpoint %s already exists", outpoint) } - mpus.poolUnspentOutputs[outpoint] = &consensusexternalapi.UTXOEntry{ - Amount: txOut.Value, - ScriptPublicKey: txOut.ScriptPublicKey, - BlockBlueScore: unacceptedBlueScore, - IsCoinbase: false, - } + mpus.poolUnspentOutputs[outpoint] = + utxo.NewUTXOEntry(txOut.Value, txOut.ScriptPublicKey, false, unacceptedBlueScore) } return nil } diff --git a/domain/miningmanager/mempool/policy.go b/domain/miningmanager/mempool/policy.go index ddbae216f..4e679f33b 100644 --- a/domain/miningmanager/mempool/policy.go +++ b/domain/miningmanager/mempool/policy.go @@ -88,7 +88,7 @@ func checkInputsStandard(tx *consensusexternalapi.DomainTransaction) error { // they have already been checked prior to calling this // function. entry := txIn.UTXOEntry - originScriptPubKey := entry.ScriptPublicKey + originScriptPubKey := entry.ScriptPublicKey() switch txscript.GetScriptClass(originScriptPubKey) { case txscript.ScriptHashTy: numSigOps := txscript.GetPreciseSigOpCount( From 32a04d1811915117c4d3b6b07c9203e5e310b0e7 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 3 Dec 2020 08:30:01 -0800 Subject: [PATCH 108/351] Allow to configure consensus (closes #1067) * Allow to configure consensus with a JSON file * Define everywhere maxBlockParents as KType * Move consensus default to consensus_defaults.go --- .../flows/blockrelay/handle_relay_invs.go | 24 --- app/rpc/rpccontext/verbosedata.go | 6 +- domain/consensus/consensus.go | 7 + domain/consensus/factory.go | 20 ++- .../consensus/model/externalapi/blockinfo.go | 1 + .../interface_processes_coinbasemanager.go | 2 + .../blockvalidator/block_body_in_isolation.go | 8 +- .../blockvalidator/block_header_in_context.go | 5 +- .../block_header_in_isolation.go | 5 +- .../blockvalidator/blockvalidator.go | 31 ++-- .../coinbasemanager/coinbasemanager.go | 25 ++- .../coinbasemanager}/payload.go | 17 +- .../calculate_past_utxo.go | 3 +- .../consensus_state_manager.go | 26 ++- .../pick_virtual_parents.go | 11 +- .../verify_and_build_utxo.go | 3 +- .../difficultymanager/difficultymanager.go | 16 +- .../processes/transactionvalidator/mass.go | 5 +- .../transaction_in_isolation.go | 4 +- .../transaction_in_isolation_test.go | 2 +- .../transactionvalidator.go | 12 ++ .../utils/blocks/extract_blue_score.go | 22 --- domain/consensus/utils/constants/constants.go | 33 ---- domain/dagconfig/consensus_defaults.go | 24 +++ domain/dagconfig/params.go | 128 ++++++++++---- domain/domain.go | 4 +- domain/miningmanager/factory.go | 6 +- domain/miningmanager/mempool/mempool.go | 4 +- infrastructure/config/network.go | 163 +++++++++++++++++- 29 files changed, 428 insertions(+), 189 deletions(-) rename domain/consensus/{utils/coinbase => processes/coinbasemanager}/payload.go (77%) delete mode 100644 domain/consensus/utils/blocks/extract_blue_score.go create mode 100644 domain/dagconfig/consensus_defaults.go diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 19c4bda1b..ce27f9660 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -8,7 +8,6 @@ import ( "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter" @@ -225,29 +224,6 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS missingParentsError := &ruleerrors.ErrMissingParents{} if errors.As(err, missingParentsError) { - blueScore, err := blocks.ExtractBlueScore(block) - if err != nil { - return protocolerrors.Errorf(true, "received an orphan "+ - "block %s with malformed blue score", blockHash) - } - - const maxOrphanBlueScoreDiff = 10000 - virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent() - if err != nil { - return err - } - selectedTipBlueScore, err := blocks.ExtractBlueScore(virtualSelectedParent) - if err != nil { - return err - } - - if blueScore > selectedTipBlueScore+maxOrphanBlueScoreDiff { - log.Infof("Orphan block %s has blue score %d and the selected tip blue score is "+ - "%d. Ignoring orphans with a blue score difference from the selected tip greater than %d", - blockHash, blueScore, selectedTipBlueScore, maxOrphanBlueScoreDiff) - return nil - } - // Add the orphan to the orphan pool flow.AddOrphan(block) diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 5af013237..e9c1f4062 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -6,8 +6,6 @@ import ( "math/big" "strconv" - "github.com/kaspanet/kaspad/domain/consensus/utils/blocks" - "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" @@ -27,7 +25,7 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ hash := consensushashing.BlockHash(block) blockHeader := block.Header - blueScore, err := blocks.ExtractBlueScore(block) + blockInfo, err := ctx.Domain.Consensus().GetBlockInfo(hash) if err != nil { return nil, err } @@ -44,7 +42,7 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ Time: blockHeader.TimeInMilliseconds, Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits, ctx.Config.ActiveNetParams), - BlueScore: blueScore, + BlueScore: blockInfo.BlueScore, } txIDs := make([]string, len(block.Transactions)) diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index fa07ae484..a5bcfed91 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -129,6 +129,13 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap return blockInfo, nil } + ghostdagData, err := s.ghostdagDataStore.Get(s.databaseContext, blockHash) + if err != nil { + return nil, err + } + + blockInfo.BlueScore = ghostdagData.BlueScore + isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash) if err != nil { return nil, err diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 222fe0016..1e1aacddc 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -22,7 +22,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore" "github.com/kaspanet/kaspad/domain/consensus/datastructures/reachabilitydatastore" "github.com/kaspanet/kaspad/domain/consensus/datastructures/utxodiffstore" - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/processes/blockbuilder" @@ -97,7 +96,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager, dagTopologyManager, ghostdagDataStore, - model.KType(dagParams.K)) + dagParams.K) dagTraversalManager := dagtraversalmanager.New( dbManager, dagTopologyManager, @@ -111,6 +110,10 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore) transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity, dagParams.EnableNonNativeSubnetworks, + dagParams.MassPerTxByte, + dagParams.MassPerScriptPubKeyByte, + dagParams.MassPerSigOp, + dagParams.MaxCoinbasePayloadLength, dbManager, pastMedianTimeManager, ghostdagDataStore) @@ -123,9 +126,13 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTraversalManager, dagParams.PowMax, dagParams.DifficultyAdjustmentWindowSize, - dagParams.TargetTimePerBlock) + dagParams.TargetTimePerBlock, + dagParams.GenesisHash) coinbaseManager := coinbasemanager.New( dbManager, + dagParams.SubsidyReductionInterval, + dagParams.BaseSubsidy, + dagParams.CoinbasePayloadScriptPublicKeyMaxLength, ghostdagDataStore, acceptanceDataStore) headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore) @@ -143,6 +150,9 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagParams.EnableNonNativeSubnetworks, dagParams.DisableDifficultyAdjustment, dagParams.DifficultyAdjustmentWindowSize, + dagParams.MaxBlockSize, + dagParams.MergeSetSizeLimit, + dagParams.MaxBlockParents, dbManager, difficultyManager, @@ -164,7 +174,11 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager, dagParams.FinalityDepth(), dagParams.PruningDepth(), + dagParams.MaxMassAcceptedByBlock, + dagParams.MaxBlockParents, + dagParams.MergeSetSizeLimit, genesisHash, + ghostdagManager, dagTopologyManager, dagTraversalManager, diff --git a/domain/consensus/model/externalapi/blockinfo.go b/domain/consensus/model/externalapi/blockinfo.go index 5b16cdf5a..8df85f63f 100644 --- a/domain/consensus/model/externalapi/blockinfo.go +++ b/domain/consensus/model/externalapi/blockinfo.go @@ -4,6 +4,7 @@ package externalapi type BlockInfo struct { Exists bool BlockStatus BlockStatus + BlueScore uint64 IsBlockInHeaderPruningPointFuture bool } diff --git a/domain/consensus/model/interface_processes_coinbasemanager.go b/domain/consensus/model/interface_processes_coinbasemanager.go index 1f023d702..aa29dca66 100644 --- a/domain/consensus/model/interface_processes_coinbasemanager.go +++ b/domain/consensus/model/interface_processes_coinbasemanager.go @@ -7,4 +7,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type CoinbaseManager interface { ExpectedCoinbaseTransaction(blockHash *externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) + ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64, + coinbaseData *externalapi.DomainCoinbaseData, err error) } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 4f0dbd9e7..0e74e5f4a 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -3,9 +3,7 @@ package blockvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/coinbase" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" @@ -85,7 +83,7 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa } func (v *blockValidator) checkCoinbase(block *externalapi.DomainBlock) error { - _, _, err := coinbase.ExtractCoinbaseDataAndBlueScore(block.Transactions[transactionhelper.CoinbaseTransactionIndex]) + _, _, err := v.coinbaseManager.ExtractCoinbaseDataAndBlueScore(block.Transactions[transactionhelper.CoinbaseTransactionIndex]) if err != nil { return err } @@ -214,9 +212,9 @@ func (v *blockValidator) checkBlockSize(block *externalapi.DomainBlock) error { for _, tx := range block.Transactions { sizeBefore := size size += estimatedsize.TransactionEstimatedSerializedSize(tx) - if size > constants.MaxBlockSize || size < sizeBefore { + if size > v.maxBlockSize || size < sizeBefore { return errors.Wrapf(ruleerrors.ErrBlockSizeTooHigh, "block excceeded the size limit of %d", - constants.MaxBlockSize) + v.maxBlockSize) } } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 168ca800a..42f5403a6 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -4,7 +4,6 @@ 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/domain/consensus/utils/constants" "github.com/pkg/errors" ) @@ -118,9 +117,9 @@ func (v *blockValidator) checkMergeSizeLimit(hash *externalapi.DomainHash) error mergeSetSize := len(ghostdagData.MergeSetReds) + len(ghostdagData.MergeSetBlues) - if mergeSetSize > constants.MergeSetSizeLimit { + if uint64(mergeSetSize) > v.mergeSetSizeLimit { return errors.Wrapf(ruleerrors.ErrViolatingMergeLimit, - "The block merges %d blocks > %d merge set size limit", mergeSetSize, constants.MergeSetSizeLimit) + "The block merges %d blocks > %d merge set size limit", mergeSetSize, v.mergeSetSizeLimit) } return nil diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 9a1347688..a63f910ff 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -4,7 +4,6 @@ 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/domain/consensus/utils/constants" "github.com/pkg/errors" ) @@ -30,9 +29,9 @@ func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader return errors.Wrapf(ruleerrors.ErrNoParents, "block has no parents") } - if len(header.ParentHashes) > constants.MaxBlockParents { + if uint64(len(header.ParentHashes)) > uint64(v.maxBlockParents) { return errors.Wrapf(ruleerrors.ErrTooManyParents, "block header has %d parents, but the maximum allowed amount "+ - "is %d", len(header.ParentHashes), constants.MaxBlockParents) + "is %d", len(header.ParentHashes), v.maxBlockParents) } return nil } diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 7c3fa4e10..07a55855d 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -18,6 +18,9 @@ type blockValidator struct { disableDifficultyAdjustment bool powMaxBits uint32 difficultyAdjustmentWindowSize uint64 + maxBlockSize uint64 + mergeSetSizeLimit uint64 + maxBlockParents model.KType databaseContext model.DBReader difficultyManager model.DifficultyManager @@ -43,6 +46,10 @@ func New(powMax *big.Int, enableNonNativeSubnetworks bool, disableDifficultyAdjustment bool, difficultyAdjustmentWindowSize uint64, + maxBlockSize uint64, + mergeSetSizeLimit uint64, + maxBlockParents model.KType, + databaseContext model.DBReader, difficultyManager model.DifficultyManager, @@ -68,16 +75,20 @@ func New(powMax *big.Int, disableDifficultyAdjustment: disableDifficultyAdjustment, powMaxBits: util.BigToCompact(powMax), difficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, - databaseContext: databaseContext, - difficultyManager: difficultyManager, - pastMedianTimeManager: pastMedianTimeManager, - transactionValidator: transactionValidator, - ghostdagManager: ghostdagManager, - dagTopologyManager: dagTopologyManager, - dagTraversalManager: dagTraversalManager, - coinbaseManager: coinbaseManager, - mergeDepthManager: mergeDepthManager, - pruningStore: pruningStore, + maxBlockSize: maxBlockSize, + mergeSetSizeLimit: mergeSetSizeLimit, + maxBlockParents: maxBlockParents, + + databaseContext: databaseContext, + difficultyManager: difficultyManager, + pastMedianTimeManager: pastMedianTimeManager, + transactionValidator: transactionValidator, + ghostdagManager: ghostdagManager, + dagTopologyManager: dagTopologyManager, + dagTraversalManager: dagTraversalManager, + coinbaseManager: coinbaseManager, + mergeDepthManager: mergeDepthManager, + pruningStore: pruningStore, blockStore: blockStore, ghostdagDataStore: ghostdagDataStore, diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index e30bbe044..0799d91b3 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -3,14 +3,15 @@ package coinbasemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/coinbase" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" ) type coinbaseManager struct { - subsidyReductionInterval uint64 + subsidyReductionInterval uint64 + baseSubsidy uint64 + coinbasePayloadScriptPublicKeyMaxLength uint64 databaseContext model.DBReader ghostdagDataStore model.GHOSTDAGDataStore @@ -42,7 +43,7 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma } } - payload, err := coinbase.SerializeCoinbasePayload(ghostdagData.BlueScore, coinbaseData) + payload, err := c.serializeCoinbasePayload(ghostdagData.BlueScore, coinbaseData) if err != nil { return nil, err } @@ -85,7 +86,7 @@ func (c coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.Domai } // the ScriptPubKey for the coinbase is parsed from the coinbase payload - _, coinbaseData, err := coinbase.ExtractCoinbaseDataAndBlueScore(blockAcceptanceData.TransactionAcceptanceData[0].Transaction) + _, coinbaseData, err := c.ExtractCoinbaseDataAndBlueScore(blockAcceptanceData.TransactionAcceptanceData[0].Transaction) if err != nil { return nil, false, err } @@ -110,7 +111,7 @@ func (c coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.Domai // approximately every 4 years. func (c coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (uint64, error) { if c.subsidyReductionInterval == 0 { - return constants.BaseSubsidy, nil + return c.baseSubsidy, nil } ghostdagData, err := c.ghostdagDataStore.Get(c.databaseContext, blockHash) @@ -119,17 +120,27 @@ func (c coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (ui } // Equivalent to: baseSubsidy / 2^(blueScore/subsidyHalvingInterval) - return constants.BaseSubsidy >> uint(ghostdagData.BlueScore/c.subsidyReductionInterval), nil + return c.baseSubsidy >> uint(ghostdagData.BlueScore/c.subsidyReductionInterval), nil } // New instantiates a new CoinbaseManager func New( databaseContext model.DBReader, + + subsidyReductionInterval uint64, + baseSubsidy uint64, + coinbasePayloadScriptPublicKeyMaxLength uint64, + ghostdagDataStore model.GHOSTDAGDataStore, acceptanceDataStore model.AcceptanceDataStore) model.CoinbaseManager { return &coinbaseManager{ - databaseContext: databaseContext, + databaseContext: databaseContext, + + subsidyReductionInterval: subsidyReductionInterval, + baseSubsidy: baseSubsidy, + coinbasePayloadScriptPublicKeyMaxLength: coinbasePayloadScriptPublicKeyMaxLength, + ghostdagDataStore: ghostdagDataStore, acceptanceDataStore: acceptanceDataStore, } diff --git a/domain/consensus/utils/coinbase/payload.go b/domain/consensus/processes/coinbasemanager/payload.go similarity index 77% rename from domain/consensus/utils/coinbase/payload.go rename to domain/consensus/processes/coinbasemanager/payload.go index e1a677006..a6c989dae 100644 --- a/domain/consensus/utils/coinbase/payload.go +++ b/domain/consensus/processes/coinbasemanager/payload.go @@ -1,4 +1,4 @@ -package coinbase +package coinbasemanager import ( "encoding/binary" @@ -6,7 +6,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/pkg/errors" ) @@ -15,12 +14,12 @@ var byteOrder = binary.LittleEndian const uint64Len = 8 const lengthOfscriptPubKeyLength = 1 -// SerializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data. -func SerializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) { +// serializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data. +func (c coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) { scriptPubKeyLength := len(coinbaseData.ScriptPublicKey) - if scriptPubKeyLength > constants.CoinbasePayloadScriptPublicKeyMaxLength { + if uint64(scriptPubKeyLength) > c.coinbasePayloadScriptPublicKeyMaxLength { return nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+ - "longer than the max allowed length of %d", constants.CoinbasePayloadScriptPublicKeyMaxLength) + "longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength) } payload := make([]byte, uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength+len(coinbaseData.ExtraData)) @@ -35,7 +34,7 @@ func SerializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.Domain } // ExtractCoinbaseDataAndBlueScore deserializes the coinbase payload to its component (scriptPubKey and extra data). -func ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64, +func (c coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData, err error) { minLength := uint64Len + lengthOfscriptPubKeyLength @@ -47,9 +46,9 @@ func ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) blueScore = byteOrder.Uint64(coinbaseTx.Payload[:uint64Len]) scriptPubKeyLength := coinbaseTx.Payload[uint64Len] - if scriptPubKeyLength > constants.CoinbasePayloadScriptPublicKeyMaxLength { + if uint64(scriptPubKeyLength) > c.coinbasePayloadScriptPublicKeyMaxLength { return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+ - "longer than the max allowed length of %d", constants.CoinbasePayloadScriptPublicKeyMaxLength) + "longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength) } if len(coinbaseTx.Payload) < minLength+int(scriptPubKeyLength) { diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index d5577b000..4799fd5cc 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -2,7 +2,6 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/pkg/errors" @@ -242,7 +241,7 @@ func (csm *consensusStateManager) checkTransactionMass( // We could potentially overflow the accumulator so check for // overflow as well. - if accumulatedMassAfter < transaction.Mass || accumulatedMassAfter > constants.MaxMassAcceptedByBlock { + if accumulatedMassAfter < transaction.Mass || accumulatedMassAfter > csm.maxMassAcceptedByBlock { return false, 0 } diff --git a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go index c7f9342af..01cb3b320 100644 --- a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go @@ -7,10 +7,13 @@ import ( // consensusStateManager manages the node's consensus state type consensusStateManager struct { - finalityDepth uint64 - pruningDepth uint64 - genesisHash *externalapi.DomainHash - databaseContext model.DBManager + finalityDepth uint64 + pruningDepth uint64 + maxMassAcceptedByBlock uint64 + maxBlockParents model.KType + mergeSetSizeLimit uint64 + genesisHash *externalapi.DomainHash + databaseContext model.DBManager ghostdagManager model.GHOSTDAGManager dagTopologyManager model.DAGTopologyManager @@ -41,7 +44,11 @@ func New( databaseContext model.DBManager, finalityDepth uint64, pruningDepth uint64, + maxMassAcceptedByBlock uint64, + maxBlockParents model.KType, + mergeSetSizeLimit uint64, genesisHash *externalapi.DomainHash, + ghostdagManager model.GHOSTDAGManager, dagTopologyManager model.DAGTopologyManager, dagTraversalManager model.DAGTraversalManager, @@ -64,10 +71,13 @@ func New( headerTipsStore model.HeaderTipsStore) (model.ConsensusStateManager, error) { csm := &consensusStateManager{ - finalityDepth: finalityDepth, - pruningDepth: pruningDepth, - genesisHash: genesisHash, - databaseContext: databaseContext, + finalityDepth: finalityDepth, + pruningDepth: pruningDepth, + maxMassAcceptedByBlock: maxMassAcceptedByBlock, + maxBlockParents: maxBlockParents, + mergeSetSizeLimit: mergeSetSizeLimit, + genesisHash: genesisHash, + databaseContext: databaseContext, ghostdagManager: ghostdagManager, dagTopologyManager: dagTopologyManager, diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index bf86175da..bce7a8f6b 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -5,7 +5,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/hashset" ) @@ -34,9 +33,9 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH selectedVirtualParents := hashset.NewFromSlice(virtualSelectedParent) - mergeSetSize := 1 // starts counting from 1 because selectedParent is already in the mergeSet + mergeSetSize := uint64(1) // starts counting from 1 because selectedParent is already in the mergeSet - for candidatesHeap.Len() > 0 && len(selectedVirtualParents) < constants.MaxBlockParents { + for candidatesHeap.Len() > 0 && uint64(len(selectedVirtualParents)) < uint64(csm.maxBlockParents) { candidate := candidatesHeap.Pop() log.Tracef("Attempting to add %s to the virtual parents", candidate) @@ -48,7 +47,7 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH } log.Tracef("The merge set would increase by %d with block %s", mergeSetIncrease, candidate) - if mergeSetSize+mergeSetIncrease > constants.MergeSetSizeLimit { + if mergeSetSize+mergeSetIncrease > csm.mergeSetSizeLimit { log.Tracef("Cannot add block %s since that would violate the merge set size limit", candidate) continue } @@ -130,7 +129,7 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( } func (csm *consensusStateManager) mergeSetIncrease( - candidate *externalapi.DomainHash, selectedVirtualParents hashset.HashSet) (int, error) { + candidate *externalapi.DomainHash, selectedVirtualParents hashset.HashSet) (uint64, error) { log.Tracef("mergeSetIncrease start") defer log.Tracef("mergeSetIncrease end") @@ -141,7 +140,7 @@ func (csm *consensusStateManager) mergeSetIncrease( if err != nil { return 0, err } - mergeSetIncrease := 1 // starts with 1 for the candidate itself + mergeSetIncrease := uint64(1) // starts with 1 for the candidate itself for queue.Len() > 0 { current := queue.Pop() diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 369145187..8a8853b3b 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -5,7 +5,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - "github.com/kaspanet/kaspad/domain/consensus/utils/coinbase" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" @@ -157,7 +156,7 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa log.Tracef("Extracting coinbase data for coinbase transaction %s in block %s", consensushashing.TransactionID(coinbaseTransaction), blockHash) - _, coinbaseData, err := coinbase.ExtractCoinbaseDataAndBlueScore(coinbaseTransaction) + _, coinbaseData, err := csm.coinbaseManager.ExtractCoinbaseDataAndBlueScore(coinbaseTransaction) if err != nil { return err } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index adf5edc2b..45bbadd1a 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -18,6 +18,7 @@ type difficultyManager struct { headerStore model.BlockHeaderStore dagTopologyManager model.DAGTopologyManager dagTraversalManager model.DAGTraversalManager + genesisHash *externalapi.DomainHash powMax *big.Int difficultyAdjustmentWindowSize uint64 targetTimePerBlock time.Duration @@ -34,6 +35,7 @@ func New( powMax *big.Int, difficultyAdjustmentWindowSize uint64, targetTimePerBlock time.Duration, + genesisHash *externalapi.DomainHash, ) model.DifficultyManager { return &difficultyManager{ databaseContext: databaseContext, @@ -45,9 +47,19 @@ func New( powMax: powMax, difficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, targetTimePerBlock: targetTimePerBlock, + genesisHash: genesisHash, } } +func (dm *difficultyManager) genesisBits() (uint32, error) { + header, err := dm.headerStore.BlockHeader(dm.databaseContext, dm.genesisHash) + if err != nil { + return 0, err + } + + return header.Bits, nil +} + // RequiredDifficulty returns the difficulty required for some block func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error) { @@ -57,7 +69,7 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas } // Genesis block if len(parents) == 0 { - return util.BigToCompact(dm.powMax), nil + return dm.genesisBits() } // find bluestParent @@ -83,7 +95,7 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas // Not enough blocks for building a difficulty window. if bluestGhostDAG.BlueScore < dm.difficultyAdjustmentWindowSize+1 { - return util.BigToCompact(dm.powMax), nil + return dm.genesisBits() } // Fetch window of dag.difficultyAdjustmentWindowSize + 1 so we can have dag.difficultyAdjustmentWindowSize block intervals diff --git a/domain/consensus/processes/transactionvalidator/mass.go b/domain/consensus/processes/transactionvalidator/mass.go index 6b5d15daf..e18454ea3 100644 --- a/domain/consensus/processes/transactionvalidator/mass.go +++ b/domain/consensus/processes/transactionvalidator/mass.go @@ -3,7 +3,6 @@ package transactionvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" @@ -17,7 +16,7 @@ func (v *transactionValidator) transactionMassStandalonePart(tx *externalapi.Dom totalScriptPubKeySize += uint64(len(output.ScriptPublicKey)) } - return size*constants.MassPerTxByte + totalScriptPubKeySize*constants.MassPerScriptPubKeyByte + return size*v.massPerTxByte + totalScriptPubKeySize*v.massPerScriptPubKeyByte } func (v *transactionValidator) transactionMass(tx *externalapi.DomainTransaction) (uint64, error) { @@ -44,5 +43,5 @@ func (v *transactionValidator) transactionMass(tx *externalapi.DomainTransaction return 0, ruleerrors.NewErrMissingTxOut(missingOutpoints) } - return standaloneMass + sigOpsCount*constants.MassPerSigOp, nil + return standaloneMass + sigOpsCount*v.massPerSigOp, nil } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index 684604824..021d427b9 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -116,10 +116,10 @@ func (v *transactionValidator) checkCoinbaseLength(tx *externalapi.DomainTransac // Coinbase payload length must not exceed the max length. payloadLen := len(tx.Payload) - if payloadLen > constants.MaxCoinbasePayloadLength { + if uint64(payloadLen) > v.maxCoinbasePayloadLength { return errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase transaction payload length "+ "of %d is out of range (max: %d)", - payloadLen, constants.MaxCoinbasePayloadLength) + payloadLen, v.maxCoinbasePayloadLength) } return nil diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go index 3c2051c96..912d8aa29 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -79,7 +79,7 @@ func TestValidateTransactionInIsolation(t *testing.T) { 1, 1, subnetworks.SubnetworkIDNative, - &txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, make([]byte, constants.MaxCoinbasePayloadLength+1)}, + &txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, make([]byte, params.MaxCoinbasePayloadLength+1)}, nil, ruleerrors.ErrBadCoinbasePayloadLen}, {"non-zero gas in Kaspa", 1, 1, 0, diff --git a/domain/consensus/processes/transactionvalidator/transactionvalidator.go b/domain/consensus/processes/transactionvalidator/transactionvalidator.go index 9500bb556..3c3f3eb49 100644 --- a/domain/consensus/processes/transactionvalidator/transactionvalidator.go +++ b/domain/consensus/processes/transactionvalidator/transactionvalidator.go @@ -15,18 +15,30 @@ type transactionValidator struct { pastMedianTimeManager model.PastMedianTimeManager ghostdagDataStore model.GHOSTDAGDataStore enableNonNativeSubnetworks bool + massPerTxByte uint64 + massPerScriptPubKeyByte uint64 + massPerSigOp uint64 + maxCoinbasePayloadLength uint64 sigCache *txscript.SigCache } // New instantiates a new TransactionValidator func New(blockCoinbaseMaturity uint64, enableNonNativeSubnetworks bool, + massPerTxByte uint64, + massPerScriptPubKeyByte uint64, + massPerSigOp uint64, + maxCoinbasePayloadLength uint64, databaseContext model.DBReader, pastMedianTimeManager model.PastMedianTimeManager, ghostdagDataStore model.GHOSTDAGDataStore) model.TransactionValidator { return &transactionValidator{ blockCoinbaseMaturity: blockCoinbaseMaturity, enableNonNativeSubnetworks: enableNonNativeSubnetworks, + massPerTxByte: massPerTxByte, + massPerScriptPubKeyByte: massPerScriptPubKeyByte, + massPerSigOp: massPerSigOp, + maxCoinbasePayloadLength: maxCoinbasePayloadLength, databaseContext: databaseContext, pastMedianTimeManager: pastMedianTimeManager, ghostdagDataStore: ghostdagDataStore, diff --git a/domain/consensus/utils/blocks/extract_blue_score.go b/domain/consensus/utils/blocks/extract_blue_score.go deleted file mode 100644 index 61045fd9a..000000000 --- a/domain/consensus/utils/blocks/extract_blue_score.go +++ /dev/null @@ -1,22 +0,0 @@ -package blocks - -import ( - "errors" - - "github.com/kaspanet/kaspad/domain/consensus/utils/coinbase" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" -) - -// ExtractBlueScore extracts the block's blue score out of it's coinbase transaction's payload -func ExtractBlueScore(block *externalapi.DomainBlock) (uint64, error) { - if len(block.Transactions) < transactionhelper.CoinbaseTransactionIndex+1 { - return 0, errors.New("Block has no coinbase transaction") - } - - coinbaseTransaction := block.Transactions[transactionhelper.CoinbaseTransactionIndex] - - blueScore, _, err := coinbase.ExtractCoinbaseDataAndBlueScore(coinbaseTransaction) - return blueScore, err -} diff --git a/domain/consensus/utils/constants/constants.go b/domain/consensus/utils/constants/constants.go index 87cf247ee..09e432baa 100644 --- a/domain/consensus/utils/constants/constants.go +++ b/domain/consensus/utils/constants/constants.go @@ -16,39 +16,6 @@ const ( // MaxSompi is the maximum transaction amount allowed in sompi. MaxSompi = 21_000_000 * SompiPerKaspa - // MaxCoinbasePayloadLength is the maximum length in bites allowed for a block's coinbase's payload - MaxCoinbasePayloadLength = 150 - - // MaxBlockSize is the maximum size in bytes a block is allowed - MaxBlockSize = 1_000_000 - - // MaxBlockParents is the maximum number of blocks a block is allowed to point to - MaxBlockParents = 10 - - // MassPerTxByte is the number of grams that any byte - // adds to a transaction. - MassPerTxByte = 1 - - // MassPerScriptPubKeyByte is the number of grams that any - // scriptPubKey byte adds to a transaction. - MassPerScriptPubKeyByte = 10 - - // MassPerSigOp is the number of grams that any - // signature operation adds to a transaction. - MassPerSigOp = 10000 - - // MergeSetSizeLimit is the maximum number of blocks in a block's merge set - MergeSetSizeLimit = 1000 - - // MaxMassAcceptedByBlock is the maximum total transaction mass a block may accept. - MaxMassAcceptedByBlock = 10000000 - - // BaseSubsidy is the starting subsidy amount for mined blocks. - BaseSubsidy = 50 * SompiPerKaspa - - // CoinbasePayloadScriptPublicKeyMaxLength is the maximum allowed script public key in the coinbase's payload - CoinbasePayloadScriptPublicKeyMaxLength = 150 - // MaxTxInSequenceNum is the maximum sequence number the sequence field // of a transaction input can be. MaxTxInSequenceNum uint64 = math.MaxUint64 diff --git a/domain/dagconfig/consensus_defaults.go b/domain/dagconfig/consensus_defaults.go new file mode 100644 index 000000000..91a00673a --- /dev/null +++ b/domain/dagconfig/consensus_defaults.go @@ -0,0 +1,24 @@ +package dagconfig + +import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "time" +) + +const ( + defaultMaxCoinbasePayloadLength = 150 + defaultMaxBlockSize = 1_000_000 + defaultMaxBlockParents = 10 + defaultMassPerTxByte = 1 + defaultMassPerScriptPubKeyByte = 10 + defaultMassPerSigOp = 10000 + defaultMergeSetSizeLimit = 1000 + defaultMaxMassAcceptedByBlock = 10000000 + defaultBaseSubsidy = 50 * constants.SompiPerKaspa + defaultCoinbasePayloadScriptPublicKeyMaxLength = 150 + defaultGHOSTDAGK = 18 + defaultDifficultyAdjustmentWindowSize = 2640 + defaultTimestampDeviationTolerance = 132 + defaultFinalityDuration = 24 * time.Hour + defaultTargetTimePerBlock = 1 * time.Second +) diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 7a6f2b8e8..70a2c8596 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -5,11 +5,10 @@ package dagconfig import ( + "github.com/kaspanet/kaspad/domain/consensus/model" "math/big" "time" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/app/appmessage" @@ -45,14 +44,6 @@ var ( devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) ) -const ( - ghostdagK = 18 - difficultyAdjustmentWindowSize = 2640 - timestampDeviationTolerance = 132 - finalityDuration = 24 * time.Hour - targetTimePerBlock = 1 * time.Second -) - // KType defines the size of GHOSTDAG consensus algorithm K parameter. type KType uint8 @@ -62,7 +53,7 @@ type KType uint8 type Params struct { // K defines the K parameter for GHOSTDAG consensus algorithm. // See ghostdag.go for further details. - K KType + K model.KType // Name defines a human-readable identifier for the network. Name string @@ -150,6 +141,39 @@ type Params struct { // SkipProofOfWork indicates whether proof of work should be checked. SkipProofOfWork bool + + // MaxCoinbasePayloadLength is the maximum length in bytes allowed for a block's coinbase's payload + MaxCoinbasePayloadLength uint64 + + // MaxBlockSize is the maximum size in bytes a block is allowed + MaxBlockSize uint64 + + // MaxBlockParents is the maximum number of blocks a block is allowed to point to + MaxBlockParents model.KType + + // MassPerTxByte is the number of grams that any byte + // adds to a transaction. + MassPerTxByte uint64 + + // MassPerScriptPubKeyByte is the number of grams that any + // scriptPubKey byte adds to a transaction. + MassPerScriptPubKeyByte uint64 + + // MassPerSigOp is the number of grams that any + // signature operation adds to a transaction. + MassPerSigOp uint64 + + // MergeSetSizeLimit is the maximum number of blocks in a block's merge set + MergeSetSizeLimit uint64 + + // MaxMassAcceptedByBlock is the maximum total transaction mass a block may accept. + MaxMassAcceptedByBlock uint64 + + // CoinbasePayloadScriptPublicKeyMaxLength is the maximum allowed script public key in the coinbase's payload + CoinbasePayloadScriptPublicKeyMaxLength uint64 + + // BaseSubsidy is the starting subsidy amount for mined blocks. + BaseSubsidy uint64 } // NormalizeRPCServerAddress returns addr with the current network default @@ -165,12 +189,12 @@ func (p *Params) FinalityDepth() uint64 { // PruningDepth returns the pruning duration represented in blocks func (p *Params) PruningDepth() uint64 { - return 2*p.FinalityDepth() + 4*constants.MergeSetSizeLimit*uint64(p.K) + 2*uint64(p.K) + 2 + return 2*p.FinalityDepth() + 4*p.MergeSetSizeLimit*uint64(p.K) + 2*uint64(p.K) + 2 } // MainnetParams defines the network parameters for the main Kaspa network. var MainnetParams = Params{ - K: ghostdagK, + K: defaultGHOSTDAGK, Name: "kaspa-mainnet", Net: appmessage.Mainnet, RPCPort: "16110", @@ -183,10 +207,10 @@ var MainnetParams = Params{ PowMax: mainPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, - TargetTimePerBlock: targetTimePerBlock, - FinalityDuration: finalityDuration, - DifficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, - TimestampDeviationTolerance: timestampDeviationTolerance, + TargetTimePerBlock: defaultTargetTimePerBlock, + FinalityDuration: defaultFinalityDuration, + DifficultyAdjustmentWindowSize: defaultDifficultyAdjustmentWindowSize, + TimestampDeviationTolerance: defaultTimestampDeviationTolerance, // Consensus rule change deployments. // @@ -212,11 +236,22 @@ var MainnetParams = Params{ EnableNonNativeSubnetworks: false, DisableDifficultyAdjustment: false, + + MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, + MaxBlockSize: defaultMaxBlockSize, + MaxBlockParents: defaultMaxBlockParents, + MassPerTxByte: defaultMassPerTxByte, + MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, + MassPerSigOp: defaultMassPerSigOp, + MergeSetSizeLimit: defaultMergeSetSizeLimit, + MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, + BaseSubsidy: defaultBaseSubsidy, + CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } // TestnetParams defines the network parameters for the test Kaspa network. var TestnetParams = Params{ - K: ghostdagK, + K: defaultGHOSTDAGK, Name: "kaspa-testnet", Net: appmessage.Testnet, RPCPort: "16210", @@ -229,10 +264,10 @@ var TestnetParams = Params{ PowMax: testnetPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, - TargetTimePerBlock: targetTimePerBlock, - FinalityDuration: finalityDuration, - DifficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, - TimestampDeviationTolerance: timestampDeviationTolerance, + TargetTimePerBlock: defaultTargetTimePerBlock, + FinalityDuration: defaultFinalityDuration, + DifficultyAdjustmentWindowSize: defaultDifficultyAdjustmentWindowSize, + TimestampDeviationTolerance: defaultTimestampDeviationTolerance, // Consensus rule change deployments. // @@ -258,6 +293,17 @@ var TestnetParams = Params{ EnableNonNativeSubnetworks: false, DisableDifficultyAdjustment: false, + + MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, + MaxBlockSize: defaultMaxBlockSize, + MaxBlockParents: defaultMaxBlockParents, + MassPerTxByte: defaultMassPerTxByte, + MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, + MassPerSigOp: defaultMassPerSigOp, + MergeSetSizeLimit: defaultMergeSetSizeLimit, + MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, + BaseSubsidy: defaultBaseSubsidy, + CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } // SimnetParams defines the network parameters for the simulation test Kaspa @@ -268,7 +314,7 @@ var TestnetParams = Params{ // following normal discovery rules. This is important as otherwise it would // just turn into another public testnet. var SimnetParams = Params{ - K: ghostdagK, + K: defaultGHOSTDAGK, Name: "kaspa-simnet", Net: appmessage.Simnet, RPCPort: "16510", @@ -283,8 +329,8 @@ var SimnetParams = Params{ SubsidyReductionInterval: 210000, TargetTimePerBlock: time.Millisecond, FinalityDuration: time.Minute, - DifficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, - TimestampDeviationTolerance: timestampDeviationTolerance, + DifficultyAdjustmentWindowSize: defaultDifficultyAdjustmentWindowSize, + TimestampDeviationTolerance: defaultTimestampDeviationTolerance, // Consensus rule change deployments. // @@ -308,11 +354,22 @@ var SimnetParams = Params{ EnableNonNativeSubnetworks: false, DisableDifficultyAdjustment: true, + + MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, + MaxBlockSize: defaultMaxBlockSize, + MaxBlockParents: defaultMaxBlockParents, + MassPerTxByte: defaultMassPerTxByte, + MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, + MassPerSigOp: defaultMassPerSigOp, + MergeSetSizeLimit: defaultMergeSetSizeLimit, + MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, + BaseSubsidy: defaultBaseSubsidy, + CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } // DevnetParams defines the network parameters for the development Kaspa network. var DevnetParams = Params{ - K: ghostdagK, + K: defaultGHOSTDAGK, Name: "kaspa-devnet", Net: appmessage.Devnet, RPCPort: "16610", @@ -325,10 +382,10 @@ var DevnetParams = Params{ PowMax: devnetPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, - TargetTimePerBlock: targetTimePerBlock, - FinalityDuration: finalityDuration, - DifficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, - TimestampDeviationTolerance: timestampDeviationTolerance, + TargetTimePerBlock: defaultTargetTimePerBlock, + FinalityDuration: defaultFinalityDuration, + DifficultyAdjustmentWindowSize: defaultDifficultyAdjustmentWindowSize, + TimestampDeviationTolerance: defaultTimestampDeviationTolerance, // Consensus rule change deployments. // @@ -354,6 +411,17 @@ var DevnetParams = Params{ EnableNonNativeSubnetworks: false, DisableDifficultyAdjustment: false, + + MaxCoinbasePayloadLength: defaultMaxCoinbasePayloadLength, + MaxBlockSize: defaultMaxBlockSize, + MaxBlockParents: defaultMaxBlockParents, + MassPerTxByte: defaultMassPerTxByte, + MassPerScriptPubKeyByte: defaultMassPerScriptPubKeyByte, + MassPerSigOp: defaultMassPerSigOp, + MergeSetSizeLimit: defaultMergeSetSizeLimit, + MaxMassAcceptedByBlock: defaultMaxMassAcceptedByBlock, + BaseSubsidy: defaultBaseSubsidy, + CoinbasePayloadScriptPublicKeyMaxLength: defaultCoinbasePayloadScriptPublicKeyMaxLength, } var ( diff --git a/domain/domain.go b/domain/domain.go index 1565a9ef2..844a96fee 100644 --- a/domain/domain.go +++ b/domain/domain.go @@ -3,7 +3,6 @@ package domain import ( "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/domain/miningmanager" infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database" @@ -37,7 +36,8 @@ func New(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (Domai } miningManagerFactory := miningmanager.NewFactory() - miningManager := miningManagerFactory.NewMiningManager(consensusInstance, constants.MaxMassAcceptedByBlock) + miningManager := miningManagerFactory.NewMiningManager(consensusInstance, dagParams.MaxMassAcceptedByBlock, + dagParams.RelayNonStdTxs) return &domain{ consensus: consensusInstance, diff --git a/domain/miningmanager/factory.go b/domain/miningmanager/factory.go index 30ad455e2..53ccfae9a 100644 --- a/domain/miningmanager/factory.go +++ b/domain/miningmanager/factory.go @@ -8,14 +8,14 @@ import ( // Factory instantiates new mining managers type Factory interface { - NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64) MiningManager + NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64, acceptNonStd bool) MiningManager } type factory struct{} // NewMiningManager instantiate a new mining manager -func (f *factory) NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64) MiningManager { - mempool := mempoolpkg.New(consensus) +func (f *factory) NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64, acceptNonStd bool) MiningManager { + mempool := mempoolpkg.New(consensus, acceptNonStd) blockTemplateBuilder := blocktemplatebuilder.New(consensus, mempool, blockMaxMass) return &miningManager{ diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index e35b79589..0cba5cb1b 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -90,10 +90,10 @@ type mempool struct { // New returns a new memory pool for validating and storing standalone // transactions until they are mined into a block. -func New(consensus consensusexternalapi.Consensus) miningmanagermodel.Mempool { +func New(consensus consensusexternalapi.Consensus, acceptNonStd bool) miningmanagermodel.Mempool { policy := policy{ MaxTxVersion: constants.TransactionVersion, - AcceptNonStd: false, + AcceptNonStd: acceptNonStd, MaxOrphanTxs: 5, MaxOrphanTxSize: 100000, MinRelayTxFee: 1000, // 1 sompi per byte diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index e5bcd4767..b6b4828ed 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -1,21 +1,53 @@ package config import ( + "encoding/json" "fmt" "github.com/jessevdk/go-flags" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/math" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" + "math/big" "os" + "time" ) // NetworkFlags holds the network configuration, that is which network is selected. type NetworkFlags struct { - Testnet bool `long:"testnet" description:"Use the test network"` - Simnet bool `long:"simnet" description:"Use the simulation test network"` - Devnet bool `long:"devnet" description:"Use the development test network"` + Testnet bool `long:"testnet" description:"Use the test network"` + Simnet bool `long:"simnet" description:"Use the simulation test network"` + Devnet bool `long:"devnet" description:"Use the development test network"` + OverrideDAGParamsFile string `long:"override-dag-params-file" description:"Overrides DAG params (allowed only on devnet)"` + ActiveNetParams *dagconfig.Params } +type overrideDAGParamsConfig struct { + K *model.KType `json:"k"` + MaxBlockParents *model.KType `json:"maxBlockParents"` + MergeSetSizeLimit *uint64 `json:"mergeSetSizeLimit"` + MaxMassAcceptedByBlock *uint64 `json:"maxMassAcceptedByBlock"` + MaxBlockSize *uint64 `json:"maxBlockSize"` + MaxCoinbasePayloadLength *uint64 `json:"maxCoinbasePayloadLength"` + MassPerTxByte *uint64 `json:"massPerTxByte"` + MassPerScriptPubKeyByte *uint64 `json:"massPerScriptPubKeyByte"` + MassPerSigOp *uint64 `json:"massPerSigOp"` + CoinbasePayloadScriptPublicKeyMaxLength *uint64 `json:"coinbasePayloadScriptPublicKeyMaxLength"` + PowMax *string `json:"powMax"` + BlockCoinbaseMaturity *uint64 `json:"blockCoinbaseMaturity"` + SubsidyReductionInterval *uint64 `json:"subsidyReductionInterval"` + TargetTimePerBlockInMilliSeconds *int64 `json:"targetTimePerBlockInMilliSeconds"` + FinalityDuration *int64 `json:"finalityDuration"` + TimestampDeviationTolerance *uint64 `json:"timestampDeviationTolerance"` + DifficultyAdjustmentWindowSize *uint64 `json:"difficultyAdjustmentWindowSize"` + RelayNonStdTxs *bool `json:"relayNonStdTxs"` + AcceptUnroutable *bool `json:"acceptUnroutable"` + EnableNonNativeSubnetworks *bool `json:"enableNonNativeSubnetworks"` + DisableDifficultyAdjustment *bool `json:"disableDifficultyAdjustment"` + SkipProofOfWork *bool `json:"skipProofOfWork"` +} + // ResolveNetwork parses the network command line argument and sets NetParams accordingly. // It returns error if more than one network was selected, nil otherwise. func (networkFlags *NetworkFlags) ResolveNetwork(parser *flags.Parser) error { @@ -58,3 +90,128 @@ func (networkFlags *NetworkFlags) ResolveNetwork(parser *flags.Parser) error { func (networkFlags *NetworkFlags) NetParams() *dagconfig.Params { return networkFlags.ActiveNetParams } + +func (networkFlags *NetworkFlags) overrideDAGParams() error { + + if networkFlags.OverrideDAGParamsFile == "" { + return nil + } + + if !networkFlags.Devnet { + return errors.Errorf("override-dag-params-file is allowed only when using devnet") + } + + overrideDAGParamsFile, err := os.Open(networkFlags.OverrideDAGParamsFile) + if err != nil { + return err + } + defer overrideDAGParamsFile.Close() + + decoder := json.NewDecoder(overrideDAGParamsFile) + config := &overrideDAGParamsConfig{} + err = decoder.Decode(config) + if err != nil { + return err + } + + if config.K != nil { + networkFlags.ActiveNetParams.K = *config.K + } + + if config.MaxBlockParents != nil { + networkFlags.ActiveNetParams.MaxBlockParents = *config.MaxBlockParents + } + + if config.MergeSetSizeLimit != nil { + networkFlags.ActiveNetParams.MergeSetSizeLimit = *config.MergeSetSizeLimit + } + + if config.MaxMassAcceptedByBlock != nil { + networkFlags.ActiveNetParams.MaxMassAcceptedByBlock = *config.MaxMassAcceptedByBlock + } + + if config.MaxBlockSize != nil { + networkFlags.ActiveNetParams.MaxBlockSize = *config.MaxBlockSize + } + + if config.MaxCoinbasePayloadLength != nil { + networkFlags.ActiveNetParams.MaxCoinbasePayloadLength = *config.MaxCoinbasePayloadLength + } + + if config.MassPerTxByte != nil { + networkFlags.ActiveNetParams.MassPerTxByte = *config.MassPerTxByte + } + + if config.MassPerScriptPubKeyByte != nil { + networkFlags.ActiveNetParams.MassPerScriptPubKeyByte = *config.MassPerScriptPubKeyByte + } + + if config.MassPerSigOp != nil { + networkFlags.ActiveNetParams.MassPerSigOp = *config.MassPerSigOp + } + + if config.CoinbasePayloadScriptPublicKeyMaxLength != nil { + networkFlags.ActiveNetParams.CoinbasePayloadScriptPublicKeyMaxLength = *config.CoinbasePayloadScriptPublicKeyMaxLength + } + + if config.PowMax != nil { + powMax, ok := big.NewInt(0).SetString(*config.PowMax, 16) + if !ok { + return errors.Errorf("couldn't convert %s to big int", *config.PowMax) + } + + genesisTarget := math.CompactToBig(networkFlags.ActiveNetParams.GenesisBlock.Header.Bits) + if powMax.Cmp(genesisTarget) > 0 { + return errors.Errorf("powMax (%s) is smaller than genesis's target (%s)", powMax.Text(16), + genesisTarget.Text(16)) + } + networkFlags.ActiveNetParams.PowMax = powMax + } + + if config.BlockCoinbaseMaturity != nil { + networkFlags.ActiveNetParams.BlockCoinbaseMaturity = *config.BlockCoinbaseMaturity + } + + if config.SubsidyReductionInterval != nil { + networkFlags.ActiveNetParams.SubsidyReductionInterval = *config.SubsidyReductionInterval + } + + if config.TargetTimePerBlockInMilliSeconds != nil { + networkFlags.ActiveNetParams.TargetTimePerBlock = time.Duration(*config.TargetTimePerBlockInMilliSeconds) * + time.Millisecond + } + + if config.FinalityDuration != nil { + networkFlags.ActiveNetParams.FinalityDuration = time.Duration(*config.FinalityDuration) * time.Millisecond + } + + if config.TimestampDeviationTolerance != nil { + networkFlags.ActiveNetParams.TimestampDeviationTolerance = *config.TimestampDeviationTolerance + } + + if config.DifficultyAdjustmentWindowSize != nil { + networkFlags.ActiveNetParams.DifficultyAdjustmentWindowSize = *config.DifficultyAdjustmentWindowSize + } + + if config.TimestampDeviationTolerance != nil { + networkFlags.ActiveNetParams.TimestampDeviationTolerance = *config.TimestampDeviationTolerance + } + + if config.RelayNonStdTxs != nil { + networkFlags.ActiveNetParams.RelayNonStdTxs = *config.RelayNonStdTxs + } + + if config.AcceptUnroutable != nil { + networkFlags.ActiveNetParams.AcceptUnroutable = *config.AcceptUnroutable + } + + if config.EnableNonNativeSubnetworks != nil { + networkFlags.ActiveNetParams.EnableNonNativeSubnetworks = *config.EnableNonNativeSubnetworks + } + + if config.SkipProofOfWork != nil { + networkFlags.ActiveNetParams.SkipProofOfWork = *config.SkipProofOfWork + } + + return nil +} From 05979de705def3c0030bc6d4f5ca1ff2fadbcdc5 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 6 Dec 2020 00:54:34 -0800 Subject: [PATCH 109/351] [NOD-1586] Return routes.Disconnect (#1180) --- infrastructure/network/netadapter/standalone/routes.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/infrastructure/network/netadapter/standalone/routes.go b/infrastructure/network/netadapter/standalone/routes.go index fe277d2f8..0f1dc830a 100644 --- a/infrastructure/network/netadapter/standalone/routes.go +++ b/infrastructure/network/netadapter/standalone/routes.go @@ -62,3 +62,8 @@ func (r *Routes) WaitForDisconnect(timeout time.Duration) error { } } } + +// Disconnect closes the connection behind the routes, thus closing all routes +func (r *Routes) Disconnect() { + r.netConnection.Disconnect() +} From f97b8f7580df392eda38547e873165d72226dabb Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 6 Dec 2020 10:57:57 +0200 Subject: [PATCH 110/351] [NOD-1587] Add DAGParams to TestConsensus (#1181) --- domain/consensus/model/testapi/test_consensus.go | 2 ++ domain/consensus/test_consensus.go | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index f745d48d0..9bf365e9e 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -3,12 +3,14 @@ package testapi import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/dagconfig" ) // TestConsensus wraps the Consensus interface with some methods that are needed by tests only type TestConsensus interface { externalapi.Consensus + DAGParams() *dagconfig.Params DatabaseContext() model.DBReader BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 927739f13..9088e005a 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -5,10 +5,12 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/dagconfig" ) type testConsensus struct { *consensus + dagParams *dagconfig.Params testBlockBuilder testapi.TestBlockBuilder testReachabilityManager testapi.TestReachabilityManager @@ -16,6 +18,10 @@ type testConsensus struct { testTransactionValidator testapi.TestTransactionValidator } +func (tc *testConsensus) DAGParams() *dagconfig.Params { + return tc.dagParams +} + func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) ( *externalapi.DomainBlock, model.UTXODiff, error) { From 33eaf9edac8e2ae24abb0dfdc7743b1e7641d254 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 6 Dec 2020 12:35:14 +0200 Subject: [PATCH 111/351] [NOD-1548] Re-add test difficulty + Make GHOSTDAGData immutable + don't clone in store (#1178) * [NOD-1548] Readd TestDifficulty * [NOD-1548] Make GHOSTDAGData immutable + don't clone in store Co-authored-by: Ori Newman --- domain/consensus/consensus.go | 4 +- .../serialization/block_ghostdag_data.go | 31 +-- .../ghostdagdatastore/ghostdagdatastore.go | 22 +- domain/consensus/factory.go | 19 +- domain/consensus/finality_test.go | 6 +- domain/consensus/model/ghostdag.go | 32 +-- ...erface_datastructures_ghostdagdatastore.go | 4 +- .../interface_processes_ghostdagmanager.go | 4 +- .../blockbuilder/test_block_builder.go | 4 +- .../blockprocessor/validateandinsertblock.go | 2 +- .../blockvalidator/block_body_in_context.go | 2 +- .../blockvalidator/block_header_in_context.go | 2 +- .../coinbasemanager/coinbasemanager.go | 8 +- .../add_block_to_virtual.go | 4 +- .../calculate_past_utxo.go | 10 +- .../consensusstatemanager/multisets.go | 14 +- .../pick_virtual_parents.go | 2 +- .../resolve_block_status.go | 6 +- .../dagtraversalmanager/block_heap.go | 2 +- .../dagtraversalmanager.go | 18 +- .../processes/dagtraversalmanager/window.go | 6 +- .../difficultymanager/difficultymanager.go | 7 +- .../difficultymanager_test.go | 203 ++++++++++++++++++ .../processes/ghostdag2/ghostdagimpl.go | 30 ++- .../processes/ghostdagmanager/compare.go | 8 +- .../processes/ghostdagmanager/ghostdag.go | 52 ++--- .../ghostdagmanager/ghostdag_data.go | 51 +++++ .../ghostdagmanager/ghostdag_test.go | 47 ++-- .../mergedepthmanager/merge_depth_manager.go | 8 +- .../pastmediantimemanager.go | 5 +- .../pruningmanager/pruningmanager.go | 8 +- .../reachabilitymanager.go | 10 +- .../processes/reachabilitymanager/tree.go | 2 +- .../processes/syncmanager/antipast.go | 6 +- .../processes/syncmanager/blocklocator.go | 8 +- .../processes/syncmanager/syncinfo.go | 2 +- .../transaction_in_context.go | 10 +- 37 files changed, 445 insertions(+), 214 deletions(-) create mode 100644 domain/consensus/processes/difficultymanager/difficultymanager_test.go create mode 100644 domain/consensus/processes/ghostdagmanager/ghostdag_data.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index a5bcfed91..6db33d9df 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -134,7 +134,7 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap return nil, err } - blockInfo.BlueScore = ghostdagData.BlueScore + blockInfo.BlueScore = ghostdagData.BlueScore() isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash) if err != nil { @@ -196,7 +196,7 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) if err != nil { return nil, err } - return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent) + return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent()) } func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { diff --git a/domain/consensus/database/serialization/block_ghostdag_data.go b/domain/consensus/database/serialization/block_ghostdag_data.go index 1765104ba..2b4a2544d 100644 --- a/domain/consensus/database/serialization/block_ghostdag_data.go +++ b/domain/consensus/database/serialization/block_ghostdag_data.go @@ -3,26 +3,27 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" ) // BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData -func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) *DbBlockGhostdagData { +func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) *DbBlockGhostdagData { var selectedParent *DbHash - if blockGHOSTDAGData.SelectedParent != nil { - selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent) + if blockGHOSTDAGData.SelectedParent() != nil { + selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent()) } return &DbBlockGhostdagData{ - BlueScore: blockGHOSTDAGData.BlueScore, + BlueScore: blockGHOSTDAGData.BlueScore(), SelectedParent: selectedParent, - MergeSetBlues: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues), - MergeSetReds: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds), - BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes), + MergeSetBlues: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues()), + MergeSetReds: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds()), + BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes()), } } // DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData -func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (*model.BlockGHOSTDAGData, error) { +func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (model.BlockGHOSTDAGData, error) { var selectedParent *externalapi.DomainHash if dbBlockGHOSTDAGData.SelectedParent != nil { var err error @@ -47,11 +48,11 @@ func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdag return nil, err } - return &model.BlockGHOSTDAGData{ - BlueScore: dbBlockGHOSTDAGData.BlueScore, - SelectedParent: selectedParent, - MergeSetBlues: mergetSetBlues, - MergeSetReds: mergetSetReds, - BluesAnticoneSizes: bluesAnticoneSizes, - }, nil + return ghostdagmanager.NewBlockGHOSTDAGData( + dbBlockGHOSTDAGData.BlueScore, + selectedParent, + mergetSetBlues, + mergetSetReds, + bluesAnticoneSizes, + ), nil } diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index aaa096a16..c42a01402 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -13,21 +13,21 @@ var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data")) // ghostdagDataStore represents a store of BlockGHOSTDAGData type ghostdagDataStore struct { - staging map[externalapi.DomainHash]*model.BlockGHOSTDAGData + staging map[externalapi.DomainHash]model.BlockGHOSTDAGData cache *lrucache.LRUCache } // New instantiates a new GHOSTDAGDataStore func New(cacheSize int) model.GHOSTDAGDataStore { return &ghostdagDataStore{ - staging: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), + staging: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData), cache: lrucache.New(cacheSize), } } // Stage stages the given blockGHOSTDAGData for the given blockHash -func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { - gds.staging[*blockHash] = blockGHOSTDAGData.Clone() +func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) { + gds.staging[*blockHash] = blockGHOSTDAGData } func (gds *ghostdagDataStore) IsStaged() bool { @@ -35,7 +35,7 @@ func (gds *ghostdagDataStore) IsStaged() bool { } func (gds *ghostdagDataStore) Discard() { - gds.staging = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) + gds.staging = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) } func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { @@ -56,13 +56,13 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { } // Get gets the blockGHOSTDAGData associated with the given blockHash -func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { +func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) { if blockGHOSTDAGData, ok := gds.staging[*blockHash]; ok { - return blockGHOSTDAGData.Clone(), nil + return blockGHOSTDAGData, nil } if blockGHOSTDAGData, ok := gds.cache.Get(blockHash); ok { - return blockGHOSTDAGData.(*model.BlockGHOSTDAGData).Clone(), nil + return blockGHOSTDAGData.(model.BlockGHOSTDAGData), nil } blockGHOSTDAGDataBytes, err := dbContext.Get(gds.hashAsKey(blockHash)) @@ -75,18 +75,18 @@ func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externala return nil, err } gds.cache.Add(blockHash, blockGHOSTDAGData) - return blockGHOSTDAGData.Clone(), nil + return blockGHOSTDAGData, nil } func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } -func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) ([]byte, error) { +func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) ([]byte, error) { return proto.Marshal(serialization.BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData)) } -func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (*model.BlockGHOSTDAGData, error) { +func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (model.BlockGHOSTDAGData, error) { dbBlockGHOSTDAGData := &serialization.DbBlockGhostdagData{} err := proto.Unmarshal(blockGHOSTDAGDataBytes, dbBlockGHOSTDAGData) if err != nil { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 1e1aacddc..ca0db772f 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -63,24 +63,23 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager := consensusdatabase.New(db) // Data Structures - storeCacheSize := 200 - acceptanceDataStore := acceptancedatastore.New(storeCacheSize) - blockStore, err := blockstore.New(dbManager, storeCacheSize) + acceptanceDataStore := acceptancedatastore.New(200) + blockStore, err := blockstore.New(dbManager, 200) if err != nil { return nil, err } - blockHeaderStore, err := blockheaderstore.New(dbManager, storeCacheSize) + blockHeaderStore, err := blockheaderstore.New(dbManager, 10_000) if err != nil { return nil, err } - blockRelationStore := blockrelationstore.New(storeCacheSize) - blockStatusStore := blockstatusstore.New(storeCacheSize) - multisetStore := multisetstore.New(storeCacheSize) + blockRelationStore := blockrelationstore.New(200) + blockStatusStore := blockstatusstore.New(200) + multisetStore := multisetstore.New(200) pruningStore := pruningstore.New() - reachabilityDataStore := reachabilitydatastore.New(storeCacheSize) - utxoDiffStore := utxodiffstore.New(storeCacheSize) + reachabilityDataStore := reachabilitydatastore.New(200) + utxoDiffStore := utxodiffstore.New(200) consensusStateStore := consensusstatestore.New() - ghostdagDataStore := ghostdagdatastore.New(storeCacheSize) + ghostdagDataStore := ghostdagdatastore.New(10_000) headerTipsStore := headertipsstore.New() // Processes diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 3beff0f45..61b0c3c12 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -155,7 +155,7 @@ func TestFinality(t *testing.T) { t.Fatalf("TestFinality: Failed getting the ghost dag data of the sidechain tip: %v", err) } - if selectedTipGhostDagData.BlueScore > sideChainTipGhostDagData.BlueScore { + if selectedTipGhostDagData.BlueScore() > sideChainTipGhostDagData.BlueScore() { t.Fatalf("sideChainTip is not the bluest tip when it is expected to be") } @@ -308,7 +308,7 @@ func TestBoundedMergeDepth(t *testing.T) { } // Make sure it's actually blue found := false - for _, blue := range virtualGhotDagData.MergeSetBlues { + for _, blue := range virtualGhotDagData.MergeSetBlues() { if *blue == *kosherizingBlockHash { found = true break @@ -356,7 +356,7 @@ func TestBoundedMergeDepth(t *testing.T) { } // Make sure it's actually blue found = false - for _, blue := range virtualGhotDagData.MergeSetBlues { + for _, blue := range virtualGhotDagData.MergeSetBlues() { if *blue == *kosherizingBlockHash { found = true break diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go index d649c34aa..2f1b4370d 100644 --- a/domain/consensus/model/ghostdag.go +++ b/domain/consensus/model/ghostdag.go @@ -3,32 +3,12 @@ package model import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockGHOSTDAGData represents GHOSTDAG data for some block -type BlockGHOSTDAGData struct { - BlueScore uint64 - SelectedParent *externalapi.DomainHash - MergeSetBlues []*externalapi.DomainHash - MergeSetReds []*externalapi.DomainHash - BluesAnticoneSizes map[externalapi.DomainHash]KType -} - -// Clone returns a clone of BlockGHOSTDAGData -func (bgd *BlockGHOSTDAGData) Clone() *BlockGHOSTDAGData { - if bgd == nil { - return nil - } - - bluesAnticoneSizesClone := make(map[externalapi.DomainHash]KType, len(bgd.BluesAnticoneSizes)) - for hash, size := range bgd.BluesAnticoneSizes { - bluesAnticoneSizesClone[hash] = size - } - - return &BlockGHOSTDAGData{ - BlueScore: bgd.BlueScore, - SelectedParent: bgd.SelectedParent.Clone(), - MergeSetBlues: externalapi.CloneHashes(bgd.MergeSetBlues), - MergeSetReds: externalapi.CloneHashes(bgd.MergeSetReds), - BluesAnticoneSizes: bluesAnticoneSizesClone, - } +type BlockGHOSTDAGData interface { + BlueScore() uint64 + SelectedParent() *externalapi.DomainHash + MergeSetBlues() []*externalapi.DomainHash + MergeSetReds() []*externalapi.DomainHash + BluesAnticoneSizes() map[externalapi.DomainHash]KType } // KType defines the size of GHOSTDAG consensus algorithm K parameter. diff --git a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go index 13522feb1..4e20e3408 100644 --- a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go +++ b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // GHOSTDAGDataStore represents a store of BlockGHOSTDAGData type GHOSTDAGDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) + Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData BlockGHOSTDAGData) IsStaged() bool - Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error) + Get(dbContext DBReader, blockHash *externalapi.DomainHash) (BlockGHOSTDAGData, error) } diff --git a/domain/consensus/model/interface_processes_ghostdagmanager.go b/domain/consensus/model/interface_processes_ghostdagmanager.go index f7cbab390..1222d5565 100644 --- a/domain/consensus/model/interface_processes_ghostdagmanager.go +++ b/domain/consensus/model/interface_processes_ghostdagmanager.go @@ -6,6 +6,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type GHOSTDAGManager interface { GHOSTDAG(blockHash *externalapi.DomainHash) error ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) - Less(blockHashA *externalapi.DomainHash, ghostdagDataA *BlockGHOSTDAGData, - blockHashB *externalapi.DomainHash, ghostdagDataB *BlockGHOSTDAGData) bool + Less(blockHashA *externalapi.DomainHash, ghostdagDataA BlockGHOSTDAGData, + blockHashB *externalapi.DomainHash, ghostdagDataB BlockGHOSTDAGData) bool } diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 967a1e4d4..78e5a56ca 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -96,13 +96,13 @@ func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.Do return nil, nil, err } - selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent) + selectedParentStatus, err := bb.testConsensus.ConsensusStateManager().ResolveBlockStatus(ghostdagData.SelectedParent()) if err != nil { return nil, nil, err } if selectedParentStatus == externalapi.StatusDisqualifiedFromChain { return nil, nil, errors.Errorf("Error building block with selectedParent %s with status DisqualifiedFromChain", - ghostdagData.SelectedParent) + ghostdagData.SelectedParent()) } pastUTXO, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index c5b2de299..b8d8603ec 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -170,7 +170,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) 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) + virtualGhostDAGData.BlueScore(), syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount) })) if logClosureErr != nil { return logClosureErr diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index b2897fee2..6e577a6ce 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -39,7 +39,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi. // Ensure all transactions in the block are finalized. for _, tx := range block.Transactions { - if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore, blockTime) { + if !v.isFinalizedTransaction(tx, ghostdagData.BlueScore(), blockTime) { txID := consensushashing.TransactionID(tx) return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains unfinalized "+ "transaction %s", txID) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 42f5403a6..cc2aa156a 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -115,7 +115,7 @@ func (v *blockValidator) checkMergeSizeLimit(hash *externalapi.DomainHash) error return err } - mergeSetSize := len(ghostdagData.MergeSetReds) + len(ghostdagData.MergeSetBlues) + mergeSetSize := len(ghostdagData.MergeSetReds()) + len(ghostdagData.MergeSetBlues()) if uint64(mergeSetSize) > v.mergeSetSizeLimit { return errors.Wrapf(ruleerrors.ErrViolatingMergeLimit, diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index 0799d91b3..068b7fb48 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -31,8 +31,8 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma return nil, err } - txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues)) - for i, blue := range ghostdagData.MergeSetBlues { + txOuts := make([]*externalapi.DomainTransactionOutput, 0, len(ghostdagData.MergeSetBlues())) + for i, blue := range ghostdagData.MergeSetBlues() { txOut, hasReward, err := c.coinbaseOutputForBlueBlock(blue, acceptanceData[i]) if err != nil { return nil, err @@ -43,7 +43,7 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma } } - payload, err := c.serializeCoinbasePayload(ghostdagData.BlueScore, coinbaseData) + payload, err := c.serializeCoinbasePayload(ghostdagData.BlueScore(), coinbaseData) if err != nil { return nil, err } @@ -120,7 +120,7 @@ func (c coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (ui } // Equivalent to: baseSubsidy / 2^(blueScore/subsidyHalvingInterval) - return c.baseSubsidy >> uint(ghostdagData.BlueScore/c.subsidyReductionInterval), nil + return c.baseSubsidy >> uint(ghostdagData.BlueScore()/c.subsidyReductionInterval), nil } // New instantiates a new CoinbaseManager diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 1f60fed01..11b5d63c0 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -80,8 +80,8 @@ func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externa } log.Tracef("Selecting the next selected parent between "+ - "the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent) - nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent, blockHash) + "the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent()) + nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent(), blockHash) if err != nil { return false, err } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 4799fd5cc..1e3dbb1c2 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -30,8 +30,8 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * } log.Tracef("Restoring the past UTXO of block %s with selectedParent %s", - blockHash, blockGHOSTDAGData.SelectedParent) - selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent) + blockHash, blockGHOSTDAGData.SelectedParent()) + selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent()) if err != nil { return nil, nil, nil, err } @@ -108,13 +108,13 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH } func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash, - selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) ( + selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) ( model.AcceptanceData, model.MutableUTXODiff, error) { log.Tracef("applyBlueBlocks start for block %s", blockHash) defer log.Tracef("applyBlueBlocks end for block %s", blockHash) - blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues) + blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues()) if err != nil { return nil, nil, err } @@ -146,7 +146,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH transactionID, blueBlockHash) isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent, - accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore) + accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore()) if err != nil { return nil, nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index 7786b4992..bb3f1a91b 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -10,22 +10,22 @@ import ( ) func (csm *consensusStateManager) calculateMultiset( - acceptanceData model.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) { + acceptanceData model.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) { - log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent) - defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent) + log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) + defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) - if blockGHOSTDAGData.SelectedParent == nil { + if blockGHOSTDAGData.SelectedParent() == nil { log.Tracef("Selected parent is nil, which could only happen for the genesis. " + "The genesis, by definition, has an empty multiset") return multiset.New(), nil } - ms, err := csm.multisetStore.Get(csm.databaseContext, blockGHOSTDAGData.SelectedParent) + ms, err := csm.multisetStore.Get(csm.databaseContext, blockGHOSTDAGData.SelectedParent()) if err != nil { return nil, err } - log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent, ms.Hash()) + log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent(), ms.Hash()) for _, blockAcceptanceData := range acceptanceData { for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { @@ -40,7 +40,7 @@ func (csm *consensusStateManager) calculateMultiset( log.Tracef("Is transaction %s a coinbase transaction: %t", transactionID, isCoinbase) var err error - err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore, isCoinbase) + err = addTransactionToMultiset(ms, transaction, blockGHOSTDAGData.BlueScore(), isCoinbase) if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index bce7a8f6b..84af3bf63 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -214,7 +214,7 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( if err != nil { return nil, err } - for _, redBlock := range virtualGHOSTDAGData.MergeSetReds { + for _, redBlock := range virtualGHOSTDAGData.MergeSetReds() { log.Tracef("Check whether red block %s is kosherized", redBlock) isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 3a2447aaf..2aa6156b0 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -79,7 +79,7 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e if err != nil { return 0, err } - return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent) + return csm.blockStatusStore.Get(csm.databaseContext, lastUnverifiedBlockGHOSTDAGData.SelectedParent()) } func (csm *consensusStateManager) getUnverifiedChainBlocks( @@ -110,13 +110,13 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks( return nil, err } - if currentBlockGHOSTDAGData.SelectedParent == nil { + if currentBlockGHOSTDAGData.SelectedParent() == nil { log.Tracef("Genesis block reached. Returning all the "+ "unverified blocks prior to it: %s", unverifiedBlocks) return unverifiedBlocks, nil } - currentHash = currentBlockGHOSTDAGData.SelectedParent + currentHash = currentBlockGHOSTDAGData.SelectedParent() } } diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go index 6a1caaadd..40a0849ed 100644 --- a/domain/consensus/processes/dagtraversalmanager/block_heap.go +++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go @@ -9,7 +9,7 @@ import ( type blockHeapNode struct { hash *externalapi.DomainHash - ghostdagData *model.BlockGHOSTDAGData + ghostdagData model.BlockGHOSTDAGData } // baseHeap is an implementation for heap.Interface that sorts blocks by their height diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index bc157f78d..5a0329fe3 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -32,7 +32,7 @@ func (spi *selectedParentIterator) Next() bool { if err != nil { panic(fmt.Sprintf("ghostdagDataStore is missing ghostdagData for: %v. '%s' ", spi.current, err)) } - spi.current = ghostdagData.SelectedParent + spi.current = ghostdagData.SelectedParent() return spi.current != nil } @@ -75,17 +75,17 @@ func (dtm *dagTraversalManager) BlockAtDepth(highHash *externalapi.DomainHash, d } requiredBlueScore := uint64(0) - if highBlockGHOSTDAGData.BlueScore > depth { - requiredBlueScore = highBlockGHOSTDAGData.BlueScore - depth + if highBlockGHOSTDAGData.BlueScore() > depth { + requiredBlueScore = highBlockGHOSTDAGData.BlueScore() - depth } currentBlockGHOSTDAGData := highBlockGHOSTDAGData // If we used `BlockIterator` we'd need to do more calls to `ghostdagDataStore` so we can get the blueScore - for currentBlockGHOSTDAGData.BlueScore >= requiredBlueScore { - if currentBlockGHOSTDAGData.SelectedParent == nil { // genesis + for currentBlockGHOSTDAGData.BlueScore() >= requiredBlueScore { + if currentBlockGHOSTDAGData.SelectedParent() == nil { // genesis return currentBlockHash, nil } - currentBlockHash = currentBlockGHOSTDAGData.SelectedParent + currentBlockHash = currentBlockGHOSTDAGData.SelectedParent() currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockHash) if err != nil { return nil, err @@ -104,15 +104,15 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash currentBlockGHOSTDAGData := highBlockGHOSTDAGData iterator := dtm.SelectedParentIterator(highHash) for iterator.Next() { - selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent) + selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent()) if err != nil { return nil, err } - if selectedParentBlockGHOSTDAGData.BlueScore < blueScore { + if selectedParentBlockGHOSTDAGData.BlueScore() < blueScore { break } - currentHash = selectedParentBlockGHOSTDAGData.SelectedParent + currentHash = selectedParentBlockGHOSTDAGData.SelectedParent() currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData } diff --git a/domain/consensus/processes/dagtraversalmanager/window.go b/domain/consensus/processes/dagtraversalmanager/window.go index 8f4805984..25b8a3211 100644 --- a/domain/consensus/processes/dagtraversalmanager/window.go +++ b/domain/consensus/processes/dagtraversalmanager/window.go @@ -15,15 +15,15 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash return nil, err } - for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent != nil { - for _, blue := range currentGHOSTDAGData.MergeSetBlues { + for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent() != nil { + for _, blue := range currentGHOSTDAGData.MergeSetBlues() { window = append(window, blue) if uint64(len(window)) == windowSize { break } } - currentHash = currentGHOSTDAGData.SelectedParent + currentHash = currentGHOSTDAGData.SelectedParent() currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) if err != nil { return nil, err diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index 45bbadd1a..7a18faad6 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -1,12 +1,13 @@ package difficultymanager import ( + "math/big" + "time" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/bigintpool" - "math/big" - "time" ) // DifficultyManager provides a method to resolve the @@ -94,7 +95,7 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas } // Not enough blocks for building a difficulty window. - if bluestGhostDAG.BlueScore < dm.difficultyAdjustmentWindowSize+1 { + if bluestGhostDAG.BlueScore() < dm.difficultyAdjustmentWindowSize+1 { return dm.genesisBits() } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go new file mode 100644 index 000000000..8b8de6df3 --- /dev/null +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -0,0 +1,203 @@ +package difficultymanager_test + +import ( + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + + "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" + "github.com/kaspanet/kaspad/util" +) + +func TestDifficulty(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.K = 1 + params.DifficultyAdjustmentWindowSize = 264 + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, "TestDifficulty") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown() + + addBlock := func(blockTime int64, parents ...*externalapi.DomainHash) (*externalapi.DomainBlock, *externalapi.DomainHash) { + bluestParent, err := tc.GHOSTDAGManager().ChooseSelectedParent(parents...) + if err != nil { + t.Fatalf("ChooseSelectedParent: %+v", err) + } + + if blockTime == 0 { + header, err := tc.BlockHeaderStore().BlockHeader(tc.DatabaseContext(), bluestParent) + if err != nil { + t.Fatalf("BlockHeader: %+v", err) + } + + blockTime = header.TimeInMilliseconds + params.TargetTimePerBlock.Milliseconds() + } + + block, _, err := tc.BuildBlockWithParents(parents, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + block.Header.TimeInMilliseconds = blockTime + err = tc.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + return block, consensushashing.BlockHash(block) + } + + minimumTime := func(parents ...*externalapi.DomainHash) int64 { + var tempHash externalapi.DomainHash + tc.BlockRelationStore().StageBlockRelation(&tempHash, &model.BlockRelations{ + Parents: parents, + Children: nil, + }) + defer tc.BlockRelationStore().Discard() + + err = tc.GHOSTDAGManager().GHOSTDAG(&tempHash) + if err != nil { + t.Fatalf("GHOSTDAG: %+v", err) + } + defer tc.GHOSTDAGDataStore().Discard() + + pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(&tempHash) + if err != nil { + t.Fatalf("PastMedianTime: %+v", err) + } + + return pastMedianTime + 1 + } + + addBlockWithMinimumTime := func(parents ...*externalapi.DomainHash) (*externalapi.DomainBlock, *externalapi.DomainHash) { + minTime := minimumTime(parents...) + return addBlock(minTime, parents...) + } + + tipHash := params.GenesisHash + tip := params.GenesisBlock + for i := uint64(0); i < params.DifficultyAdjustmentWindowSize; i++ { + tip, tipHash = addBlock(0, tipHash) + if tip.Header.Bits != params.GenesisBlock.Header.Bits { + t.Fatalf("As long as the bluest parent's blue score is less then the difficulty adjustment " + + "window size, the difficulty should be the same as genesis'") + } + } + for i := uint64(0); i < params.DifficultyAdjustmentWindowSize+100; i++ { + tip, tipHash = addBlock(0, tipHash) + if tip.Header.Bits != params.GenesisBlock.Header.Bits { + t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change") + } + } + + blockInThePast, tipHash := addBlockWithMinimumTime(tipHash) + if blockInThePast.Header.Bits != tip.Header.Bits { + t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent") + } + tip = blockInThePast + + tip, tipHash = addBlock(0, tipHash) + if tip.Header.Bits != blockInThePast.Header.Bits { + t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent") + } + + tip, tipHash = addBlock(0, tipHash) + if compareBits(tip.Header.Bits, blockInThePast.Header.Bits) >= 0 { + t.Fatalf("tip.bits should be smaller than blockInThePast.bits because blockInThePast increased the " + + "block rate, so the difficulty should increase as well") + } + + var expectedBits uint32 + switch params.Name { + case "kaspa-testnet", "kaspa-devnet": + expectedBits = uint32(0x1e7f83df) + case "kaspa-mainnet", "kaspa-simnet": + expectedBits = uint32(0x207f83df) + } + + if tip.Header.Bits != expectedBits { + t.Errorf("tip.bits was expected to be %x but got %x", expectedBits, tip.Header.Bits) + } + + // Increase block rate to increase difficulty + for i := uint64(0); i < params.DifficultyAdjustmentWindowSize; i++ { + tip, tipHash = addBlockWithMinimumTime(tipHash) + tipGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), tipHash) + if err != nil { + t.Fatalf("GHOSTDAGDataStore: %+v", err) + } + + selectedParentHeader, err := tc.BlockHeaderStore().BlockHeader(tc.DatabaseContext(), + tipGHOSTDAGData.SelectedParent()) + if err != nil { + t.Fatalf("BlockHeader: %+v", err) + } + + if compareBits(tip.Header.Bits, selectedParentHeader.Bits) > 0 { + t.Fatalf("Because we're increasing the block rate, the difficulty can't decrease") + } + } + + // Add blocks until difficulty stabilizes + lastBits := tip.Header.Bits + sameBitsCount := uint64(0) + for sameBitsCount < params.DifficultyAdjustmentWindowSize+1 { + tip, tipHash = addBlock(0, tipHash) + if tip.Header.Bits == lastBits { + sameBitsCount++ + } else { + lastBits = tip.Header.Bits + sameBitsCount = 0 + } + } + + slowBlockTime := tip.Header.TimeInMilliseconds + params.TargetTimePerBlock.Milliseconds() + 1000 + slowBlock, tipHash := addBlock(slowBlockTime, tipHash) + if slowBlock.Header.Bits != tip.Header.Bits { + t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent") + } + + tip = slowBlock + + tip, tipHash = addBlock(0, tipHash) + if tip.Header.Bits != slowBlock.Header.Bits { + t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent") + } + tip, tipHash = addBlock(0, tipHash) + if compareBits(tip.Header.Bits, slowBlock.Header.Bits) <= 0 { + t.Fatalf("tip.bits should be smaller than slowBlock.bits because slowBlock decreased the block" + + " rate, so the difficulty should decrease as well") + } + + _, tipHash = addBlock(0, tipHash) + splitBlockHash := tipHash + for i := 0; i < 100; i++ { + _, tipHash = addBlock(0, tipHash) + } + blueTipHash := tipHash + + redChainTipHash := splitBlockHash + for i := 0; i < 10; i++ { + _, redChainTipHash = addBlockWithMinimumTime(redChainTipHash) + } + tipWithRedPast, _ := addBlock(0, redChainTipHash, blueTipHash) + tipWithoutRedPast, _ := addBlock(0, blueTipHash) + if tipWithoutRedPast.Header.Bits != tipWithRedPast.Header.Bits { + t.Fatalf("tipWithoutRedPast.bits should be the same as tipWithRedPast.bits because red blocks" + + " shouldn't affect the difficulty") + } + }) +} + +func compareBits(a uint32, b uint32) int { + aTarget := util.CompactToBig(a) + bTarget := util.CompactToBig(b) + return aTarget.Cmp(bTarget) +} diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index 867f52a8e..abaaf183e 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -1,9 +1,12 @@ package ghostdag2 import ( + "sort" + + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "sort" ) type ghostdagHelper struct { @@ -44,7 +47,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error if err != nil { return err } - blockScore := blockData.BlueScore + blockScore := blockData.BlueScore() if blockScore > maxNum { selectedParent = parent maxNum = blockScore @@ -91,13 +94,8 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error } myScore += uint64(len(mergeSetBlues)) - e := model.BlockGHOSTDAGData{ - BlueScore: myScore, - SelectedParent: selectedParent, - MergeSetBlues: mergeSetBlues, - MergeSetReds: mergeSetReds, - } - gh.dataStore.Stage(blockCandidate, &e) + e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, selectedParent, mergeSetBlues, mergeSetReds, nil) + gh.dataStore.Stage(blockCandidate, e) return nil } @@ -220,7 +218,7 @@ func (gh *ghostdagHelper) validateKCluster(chain *externalapi.DomainHash, checke if err != nil { return false, err } - if mergeSetReds := dataStore.MergeSetReds; contains(checkedBlock, mergeSetReds) { + if mergeSetReds := dataStore.MergeSetReds(); contains(checkedBlock, mergeSetReds) { return false, nil } } else { @@ -326,14 +324,14 @@ func (gh *ghostdagHelper) findBlueSet(blueSet *[]*externalapi.DomainHash, select if err != nil { return err } - mergeSetBlue := blockData.MergeSetBlues + mergeSetBlue := blockData.MergeSetBlues() for _, blue := range mergeSetBlue { if contains(blue, *blueSet) { continue } *blueSet = append(*blueSet, blue) } - selectedParent = blockData.SelectedParent + selectedParent = blockData.SelectedParent() } return nil } @@ -356,10 +354,10 @@ func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error { return false } - if blockLeft.BlueScore < blockRight.BlueScore { + if blockLeft.BlueScore() < blockRight.BlueScore() { return true } - if blockLeft.BlueScore == blockRight.BlueScore { + if blockLeft.BlueScore() == blockRight.BlueScore() { return ismoreHash(arr[j], arr[i]) } return false @@ -369,13 +367,13 @@ func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error { /* --------------------------------------------- */ -func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { +func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) { return gh.dataStore.Get(gh.dbAccess, blockHash) } func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) { panic("implement me") } -func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { +func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool { panic("implement me") } diff --git a/domain/consensus/processes/ghostdagmanager/compare.go b/domain/consensus/processes/ghostdagmanager/compare.go index b5c16f27e..76ad1844a 100644 --- a/domain/consensus/processes/ghostdagmanager/compare.go +++ b/domain/consensus/processes/ghostdagmanager/compare.go @@ -53,11 +53,11 @@ func (gm *ghostdagManager) ChooseSelectedParent(blockHashes ...*externalapi.Doma return selectedParent, nil } -func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, - blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { +func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, + blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool { - blockBlueScoreA := ghostdagDataA.BlueScore - blockBlueScoreB := ghostdagDataB.BlueScore + blockBlueScoreA := ghostdagDataA.BlueScore() + blockBlueScoreB := ghostdagDataB.BlueScore() if blockBlueScoreA == blockBlueScoreB { return hashes.Less(blockHashA, blockHashB) } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index c510959a5..8e24ea4c1 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -25,10 +25,10 @@ import ( // // For further details see the article https://eprint.iacr.org/2018/104.pdf func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { - newBlockData := &model.BlockGHOSTDAGData{ - MergeSetBlues: make([]*externalapi.DomainHash, 0), - MergeSetReds: make([]*externalapi.DomainHash, 0), - BluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType), + newBlockData := &blockGHOSTDAGData{ + mergeSetBlues: make([]*externalapi.DomainHash, 0), + mergeSetReds: make([]*externalapi.DomainHash, 0), + bluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType), } blockParents, err := gm.dagTopologyManager.Parents(blockHash) @@ -43,12 +43,12 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { return err } - newBlockData.SelectedParent = selectedParent - newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, selectedParent) - newBlockData.BluesAnticoneSizes[*selectedParent] = 0 + newBlockData.selectedParent = selectedParent + newBlockData.mergeSetBlues = append(newBlockData.mergeSetBlues, selectedParent) + newBlockData.bluesAnticoneSizes[*selectedParent] = 0 } - mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.SelectedParent, blockParents) + mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.selectedParent, blockParents) if err != nil { return err } @@ -61,25 +61,25 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { if isBlue { // No k-cluster violation found, we can now set the candidate block as blue - newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, blueCandidate) - newBlockData.BluesAnticoneSizes[*blueCandidate] = candidateAnticoneSize + newBlockData.mergeSetBlues = append(newBlockData.mergeSetBlues, blueCandidate) + newBlockData.bluesAnticoneSizes[*blueCandidate] = candidateAnticoneSize for blue, blueAnticoneSize := range candidateBluesAnticoneSizes { - newBlockData.BluesAnticoneSizes[blue] = blueAnticoneSize + 1 + newBlockData.bluesAnticoneSizes[blue] = blueAnticoneSize + 1 } } else { - newBlockData.MergeSetReds = append(newBlockData.MergeSetReds, blueCandidate) + newBlockData.mergeSetReds = append(newBlockData.mergeSetReds, blueCandidate) } } if !isGenesis { - selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.SelectedParent) + selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.selectedParent) if err != nil { return err } - newBlockData.BlueScore = selectedParentGHOSTDAGData.BlueScore + uint64(len(newBlockData.MergeSetBlues)) + newBlockData.blueScore = selectedParentGHOSTDAGData.BlueScore() + uint64(len(newBlockData.mergeSetBlues)) } else { // Genesis's blue score is defined to be 0. - newBlockData.BlueScore = 0 + newBlockData.blueScore = 0 } gm.ghostdagDataStore.Stage(blockHash, newBlockData) @@ -89,15 +89,15 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { type chainBlockData struct { hash *externalapi.DomainHash - blockData *model.BlockGHOSTDAGData + blockData model.BlockGHOSTDAGData } -func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGData, blueCandidate *externalapi.DomainHash) ( +func (gm *ghostdagManager) checkBlueCandidate(newBlockData *blockGHOSTDAGData, blueCandidate *externalapi.DomainHash) ( isBlue bool, candidateAnticoneSize model.KType, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, err error) { // The maximum length of node.blues can be K+1 because // it contains the selected parent. - if model.KType(len(newBlockData.MergeSetBlues)) == gm.k+1 { + if model.KType(len(newBlockData.mergeSetBlues)) == gm.k+1 { return false, 0, nil, nil } @@ -126,12 +126,12 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGD return false, 0, nil, nil } - selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, chainBlock.blockData.SelectedParent) + selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, chainBlock.blockData.SelectedParent()) if err != nil { return false, 0, nil, err } - chainBlock = chainBlockData{hash: chainBlock.blockData.SelectedParent, + chainBlock = chainBlockData{hash: chainBlock.blockData.SelectedParent(), blockData: selectedParentGHOSTDAGData, } } @@ -139,7 +139,7 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGD return true, candidateAnticoneSize, candidateBluesAnticoneSizes, nil } -func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.BlockGHOSTDAGData, +func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.BlockGHOSTDAGData, chainBlock chainBlockData, blueCandidate *externalapi.DomainHash, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, candidateAnticoneSize *model.KType) (isBlue, isRed bool, err error) { @@ -164,7 +164,7 @@ func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model. } } - for _, block := range chainBlock.blockData.MergeSetBlues { + for _, block := range chainBlock.blockData.MergeSetBlues() { // Skip blocks that exist in the past of blueCandidate. isAncestorOfBlueCandidate, err := gm.dagTopologyManager.IsAncestorOf(block, blueCandidate) if err != nil { @@ -204,16 +204,16 @@ func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model. // blueAnticoneSize returns the blue anticone size of 'block' from the worldview of 'context'. // Expects 'block' to be in the blue set of 'context' -func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context *model.BlockGHOSTDAGData) (model.KType, error) { +func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context model.BlockGHOSTDAGData) (model.KType, error) { for current := context; current != nil; { - if blueAnticoneSize, ok := current.BluesAnticoneSizes[*block]; ok { + if blueAnticoneSize, ok := current.BluesAnticoneSizes()[*block]; ok { return blueAnticoneSize, nil } - if current.SelectedParent == nil { + if current.SelectedParent() == nil { break } var err error - current, err = gm.ghostdagDataStore.Get(gm.databaseContext, current.SelectedParent) + current, err = gm.ghostdagDataStore.Get(gm.databaseContext, current.SelectedParent()) if err != nil { return 0, err } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go new file mode 100644 index 000000000..b708241be --- /dev/null +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go @@ -0,0 +1,51 @@ +package ghostdagmanager + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +type blockGHOSTDAGData struct { + blueScore uint64 + selectedParent *externalapi.DomainHash + mergeSetBlues []*externalapi.DomainHash + mergeSetReds []*externalapi.DomainHash + bluesAnticoneSizes map[externalapi.DomainHash]model.KType +} + +// NewBlockGHOSTDAGData creates a new instance of model.BlockGHOSTDAGData +func NewBlockGHOSTDAGData( + blueScore uint64, + selectedParent *externalapi.DomainHash, + mergeSetBlues []*externalapi.DomainHash, + mergeSetReds []*externalapi.DomainHash, + bluesAnticoneSizes map[externalapi.DomainHash]model.KType) model.BlockGHOSTDAGData { + + return &blockGHOSTDAGData{ + blueScore: blueScore, + selectedParent: selectedParent, + mergeSetBlues: mergeSetBlues, + mergeSetReds: mergeSetReds, + bluesAnticoneSizes: bluesAnticoneSizes, + } +} + +func (bgd *blockGHOSTDAGData) BlueScore() uint64 { + return bgd.blueScore +} + +func (bgd *blockGHOSTDAGData) SelectedParent() *externalapi.DomainHash { + return bgd.selectedParent +} + +func (bgd *blockGHOSTDAGData) MergeSetBlues() []*externalapi.DomainHash { + return bgd.mergeSetBlues +} + +func (bgd *blockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash { + return bgd.mergeSetReds +} + +func (bgd *blockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]model.KType { + return bgd.bluesAnticoneSizes +} diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index bd01b100e..6afcf6091 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -1,14 +1,17 @@ -package ghostdagmanager +package ghostdagmanager_test import ( "encoding/json" - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" "os" "path/filepath" "reflect" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" ) // TestGHOSTDAG iterates over several dag simulations, and checks @@ -47,15 +50,9 @@ func TestGHOSTDAG(t *testing.T) { } ghostdagDataStore := &GHOSTDAGDataStoreImpl{ - dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), - } - var blockGHOSTDAGDataGenesis = &model.BlockGHOSTDAGData{ - BlueScore: 0, - SelectedParent: nil, - MergeSetBlues: nil, - MergeSetReds: nil, - BluesAnticoneSizes: nil, + dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData), } + blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, nil, nil, nil, nil) var testsCounter int err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { @@ -87,7 +84,7 @@ func TestGHOSTDAG(t *testing.T) { //NOTE: FOR ADDING/REMOVING AN IMPLEMENTATION CHANGE BELOW: implementationFactories := []implManager{ - {New, "Original"}, + {ghostdagmanager.New, "Original"}, {ghostdag2.New, "Tal's impl"}, } @@ -110,30 +107,30 @@ func TestGHOSTDAG(t *testing.T) { factory.implName, info.Name(), testBlockData.ID, err) } - if testBlockData.Score != (ghostdagData.BlueScore) { + if testBlockData.Score != (ghostdagData.BlueScore()) { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue score %d but got %d.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore) + factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore()) } - if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent { + if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent() { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, string(ghostdagData.SelectedParent[:])) + factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, ghostdagData.SelectedParent()) } - if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues) { + if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues()) { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues)) + factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues())) } - if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds) { + if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds()) { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds)) + factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds())) } } dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash) dagTopology.parentsMap[genesisHash] = nil - ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) + ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis } @@ -172,10 +169,10 @@ func StringToByteArray(stringIDArr []string) []*externalapi.DomainHash { /* ---------------------- */ type GHOSTDAGDataStoreImpl struct { - dagMap map[externalapi.DomainHash]*model.BlockGHOSTDAGData + dagMap map[externalapi.DomainHash]model.BlockGHOSTDAGData } -func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { +func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) { ds.dagMap[*blockHash] = blockGHOSTDAGData } @@ -191,7 +188,7 @@ func (ds *GHOSTDAGDataStoreImpl) Commit(dbTx model.DBTransaction) error { panic("implement me") } -func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { +func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) { v, ok := ds.dagMap[*blockHash] if ok { return v, nil diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index cbf29f331..155dcd731 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -46,7 +46,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma } // Return nil on genesis - if ghostdagData.SelectedParent == nil { + if ghostdagData.SelectedParent() == nil { return nil } @@ -55,7 +55,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma return err } - for _, red := range ghostdagData.MergeSetReds { + for _, red := range ghostdagData.MergeSetReds() { doesRedHaveFinalityPointInPast, err := mdm.dagTopologyManager.IsAncestorOf(finalityPoint, red) if err != nil { return err @@ -85,9 +85,9 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter return nil, err } - nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues)) + nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues())) - for _, blue := range ghostdagData.MergeSetBlues { + for _, blue := range ghostdagData.MergeSetBlues() { notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(blockHash, blue) if err != nil { return nil, err diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go index a2d92dbbb..5d29206ce 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go @@ -1,10 +1,11 @@ package pastmediantimemanager import ( + "sort" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" - "sort" ) // pastMedianTimeManager provides a method to resolve the @@ -44,7 +45,7 @@ func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainH if err != nil { return 0, err } - selectedParentHash := blockGHOSTDAGData.SelectedParent + selectedParentHash := blockGHOSTDAGData.SelectedParent() // Genesis block if selectedParentHash == nil { diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 9dda97c9d..57ca1dd12 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -99,14 +99,14 @@ func (pm *pruningManager) FindNextPruningPoint() error { if err != nil { return err } - currentPBlueScore := currentPGhost.BlueScore + 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 virtual.BlueScore() <= currentPBlueScore+pm.finalityInterval { return nil } // This means the pruning point is still genesis. - if virtual.BlueScore <= pm.pruningDepth+pm.finalityInterval { + if virtual.BlueScore() <= pm.pruningDepth+pm.finalityInterval { return nil } @@ -121,7 +121,7 @@ func (pm *pruningManager) FindNextPruningPoint() error { } // Actually check if the pruning point changed - if (currentPBlueScore / pm.finalityInterval) < (candidatePGhost.BlueScore / pm.finalityInterval) { + if (currentPBlueScore / pm.finalityInterval) < (candidatePGhost.BlueScore() / pm.finalityInterval) { err = pm.savePruningPoint(candidatePHash) if err != nil { return err diff --git a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go index 9bafb96c4..577239571 100644 --- a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go @@ -45,7 +45,7 @@ func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error } // If this is the genesis node, simply initialize it and return - if ghostdagData.SelectedParent == nil { + if ghostdagData.SelectedParent() == nil { rt.stageReindexRoot(blockHash) return nil } @@ -56,16 +56,16 @@ func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error } // Insert the node into the selected parent's reachability tree - err = rt.addChild(ghostdagData.SelectedParent, blockHash, reindexRoot) + err = rt.addChild(ghostdagData.SelectedParent(), blockHash, reindexRoot) if err != nil { return err } // Add the block to the futureCoveringSets of all the blocks // in the merget set - mergeSet := make([]*externalapi.DomainHash, len(ghostdagData.MergeSetBlues)+len(ghostdagData.MergeSetReds)) - copy(mergeSet, ghostdagData.MergeSetBlues) - copy(mergeSet[len(ghostdagData.MergeSetBlues):], ghostdagData.MergeSetReds) + mergeSet := make([]*externalapi.DomainHash, len(ghostdagData.MergeSetBlues())+len(ghostdagData.MergeSetReds())) + copy(mergeSet, ghostdagData.MergeSetBlues()) + copy(mergeSet[len(ghostdagData.MergeSetBlues()):], ghostdagData.MergeSetReds()) for _, current := range mergeSet { err = rt.insertToFutureCoveringSet(current, blockHash) diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 8ea711939..1dea962ea 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -814,7 +814,7 @@ func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *ex return nil, false, err } - if newTreeNodeGHOSTDAGData.BlueScore-reindexRootChosenChildGHOSTDAGData.BlueScore < rt.reindexWindow { + if newTreeNodeGHOSTDAGData.BlueScore()-reindexRootChosenChildGHOSTDAGData.BlueScore() < rt.reindexWindow { return nil, false, nil } diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 973b9efbf..7cdf339c1 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -16,12 +16,12 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma if err != nil { return nil, err } - lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore + lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore() highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash) if err != nil { return nil, err } - highBlockBlueScore := highBlockGHOSTDAGData.BlueScore + highBlockBlueScore := highBlockGHOSTDAGData.BlueScore() if lowBlockBlueScore >= highBlockBlueScore { return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)", lowBlockBlueScore, highBlockBlueScore) @@ -37,7 +37,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma // fairly accurate because we presume that most DAG blocks are // blue. for highBlockBlueScore-lowBlockBlueScore+1 > maxHashesInAntiPastHashesBetween { - highHash = highBlockGHOSTDAGData.SelectedParent + highHash = highBlockGHOSTDAGData.SelectedParent() } // Collect every node in highHash's past (including itself) but diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index a808e10ac..770b22ee6 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -14,13 +14,13 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH if err != nil { return nil, err } - highHash = highBlockGHOSTDAGData.SelectedParent + highHash = highBlockGHOSTDAGData.SelectedParent() lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) if err != nil { return nil, err } - lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore + lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore() currentHash := highHash step := uint64(1) @@ -32,7 +32,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH if err != nil { return nil, err } - currentBlockBlueScore := currentBlockGHOSTDAGData.BlueScore + currentBlockBlueScore := currentBlockGHOSTDAGData.BlueScore() // Nothing more to add once the low node has been added. if currentBlockBlueScore <= lowBlockBlueScore { @@ -47,7 +47,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH // final node is lowNode. nextBlueScore := currentBlockBlueScore - step if currentBlockBlueScore < step { - nextBlueScore = lowBlockGHOSTDAGData.BlueScore + nextBlueScore = lowBlockGHOSTDAGData.BlueScore() } // Walk down currentHash's selected parent chain to the appropriate ancestor diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 5d502b114..62a3f2a7b 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -91,7 +91,7 @@ func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, err if err != nil { return nil, err } - return virtualGHOSTDAGData.SelectedParent, nil + return virtualGHOSTDAGData.SelectedParent(), nil } func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) { diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index 9f40f9998..57395bf42 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -59,7 +59,7 @@ func (v *transactionValidator) checkTransactionCoinbaseMaturity( return err } - txBlueScore := ghostdagData.BlueScore + txBlueScore := ghostdagData.BlueScore() var missingOutpoints []*externalapi.DomainOutpoint for _, input := range tx.Inputs { utxoEntry := input.UTXOEntry @@ -166,7 +166,7 @@ func (v *transactionValidator) checkTransactionSequenceLock(povBlockHash *extern return err } - if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore, medianTime) { + if !v.sequenceLockActive(sequenceLock, ghostdagData.BlueScore(), medianTime) { return errors.Wrapf(ruleerrors.ErrUnfinalizedTx, "block contains "+ "transaction whose input sequence "+ "locks are not met") @@ -270,16 +270,16 @@ func (v *transactionValidator) calcTxSequenceLockFromReferencedUTXOEntries( for { selectedParentGHOSTDAGData, err := v.ghostdagDataStore.Get(v.databaseContext, - baseGHOSTDAGData.SelectedParent) + baseGHOSTDAGData.SelectedParent()) if err != nil { return nil, err } - if selectedParentGHOSTDAGData.BlueScore <= inputBlueScore { + if selectedParentGHOSTDAGData.BlueScore() <= inputBlueScore { break } - baseHash = baseGHOSTDAGData.SelectedParent + baseHash = baseGHOSTDAGData.SelectedParent() baseGHOSTDAGData = selectedParentGHOSTDAGData } From c3902ed7a8ea4a46deb41b1db4fa07807d73729d Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 6 Dec 2020 14:45:21 +0200 Subject: [PATCH 112/351] Replace blue score with blue work in ghostdag (#1172) * Replace blueScore with blueWork in ghostDAG SelectedParent selection * Add blueWork to protopuf ghostdag data * Auto generate protobuf go code * Serialize/Deserialize blueWork when converting to protobuf * pass block header store to ghostdagmanager * Convert tal's ghostdag2 implementation to blueWork * Change finality test to check the blueWork instead of blueScore * Update ghostdag_test to pass blockHeaderStore to ghostdag, and test all networks genesis headers * Add sanity blueWork check to ghostdag_test --- .../serialization/block_ghostdag_data.go | 3 + .../database/serialization/dbobjects.pb.go | 232 ++++++------- .../database/serialization/dbobjects.proto | 9 +- domain/consensus/factory.go | 1 + domain/consensus/finality_test.go | 2 +- domain/consensus/model/ghostdag.go | 7 +- .../processes/ghostdag2/ghostdagimpl.go | 43 ++- .../processes/ghostdagmanager/compare.go | 13 +- .../processes/ghostdagmanager/ghostdag.go | 14 + .../ghostdagmanager/ghostdag_data.go | 8 + .../ghostdagmanager/ghostdag_test.go | 305 +++++++++++------- .../ghostdagmanager/ghostdagmanager.go | 3 + 12 files changed, 391 insertions(+), 249 deletions(-) diff --git a/domain/consensus/database/serialization/block_ghostdag_data.go b/domain/consensus/database/serialization/block_ghostdag_data.go index 2b4a2544d..29f9df9d6 100644 --- a/domain/consensus/database/serialization/block_ghostdag_data.go +++ b/domain/consensus/database/serialization/block_ghostdag_data.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" + "math/big" ) // BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData @@ -15,6 +16,7 @@ func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDA return &DbBlockGhostdagData{ BlueScore: blockGHOSTDAGData.BlueScore(), + BlueWork: blockGHOSTDAGData.BlueWork().Bytes(), SelectedParent: selectedParent, MergeSetBlues: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues()), MergeSetReds: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds()), @@ -50,6 +52,7 @@ func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdag return ghostdagmanager.NewBlockGHOSTDAGData( dbBlockGHOSTDAGData.BlueScore, + new(big.Int).SetBytes(dbBlockGHOSTDAGData.BlueWork), selectedParent, mergetSetBlues, mergetSetReds, diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index fa19c7c1e..731b42013 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -865,10 +865,11 @@ type DbBlockGhostdagData struct { unknownFields protoimpl.UnknownFields BlueScore uint64 `protobuf:"varint,1,opt,name=blueScore,proto3" json:"blueScore,omitempty"` - SelectedParent *DbHash `protobuf:"bytes,2,opt,name=selectedParent,proto3" json:"selectedParent,omitempty"` - MergeSetBlues []*DbHash `protobuf:"bytes,3,rep,name=mergeSetBlues,proto3" json:"mergeSetBlues,omitempty"` - MergeSetReds []*DbHash `protobuf:"bytes,4,rep,name=mergeSetReds,proto3" json:"mergeSetReds,omitempty"` - BluesAnticoneSizes []*DbBluesAnticoneSizes `protobuf:"bytes,5,rep,name=bluesAnticoneSizes,proto3" json:"bluesAnticoneSizes,omitempty"` + BlueWork []byte `protobuf:"bytes,2,opt,name=blueWork,proto3" json:"blueWork,omitempty"` + SelectedParent *DbHash `protobuf:"bytes,3,opt,name=selectedParent,proto3" json:"selectedParent,omitempty"` + MergeSetBlues []*DbHash `protobuf:"bytes,4,rep,name=mergeSetBlues,proto3" json:"mergeSetBlues,omitempty"` + MergeSetReds []*DbHash `protobuf:"bytes,5,rep,name=mergeSetReds,proto3" json:"mergeSetReds,omitempty"` + BluesAnticoneSizes []*DbBluesAnticoneSizes `protobuf:"bytes,6,rep,name=bluesAnticoneSizes,proto3" json:"bluesAnticoneSizes,omitempty"` } func (x *DbBlockGhostdagData) Reset() { @@ -910,6 +911,13 @@ func (x *DbBlockGhostdagData) GetBlueScore() uint64 { return 0 } +func (x *DbBlockGhostdagData) GetBlueWork() []byte { + if x != nil { + return x.BlueWork + } + return nil +} + func (x *DbBlockGhostdagData) GetSelectedParent() *DbHash { if x != nil { return x.SelectedParent @@ -1848,119 +1856,121 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xbf, 0x02, 0x0a, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, 0x73, 0x74, 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, - 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, 0x04, + 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x12, 0x3d, + 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x3b, 0x0a, + 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, 0x72, - 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, 0x75, - 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, - 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, 0x65, - 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, 0x6d, - 0x0a, 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, - 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, 0x74, - 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, 0x0a, - 0x0a, 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, - 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, - 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, 0x78, - 0x6f, 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, - 0x87, 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x38, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, - 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, 0x62, - 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, - 0x61, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x74, 0x72, - 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, - 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, - 0x6f, 0x64, 0x65, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x43, 0x0a, - 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, - 0x65, 0x74, 0x22, 0xbd, 0x01, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x31, 0x0a, - 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, - 0x12, 0x2d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0d, 0x6d, 0x65, 0x72, + 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0c, 0x6d, 0x65, + 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, - 0x41, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, - 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x44, - 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x3f, - 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, - 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, - 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, - 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x33, - 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, - 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, - 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, + 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, + 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, + 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, + 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, 0x6d, 0x0a, 0x14, 0x44, 0x62, + 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, + 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x62, 0x6c, 0x75, + 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6e, 0x74, + 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, 0x0a, 0x0a, 0x44, 0x62, 0x4d, + 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x75, 0x6c, 0x74, 0x69, + 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x75, 0x6c, 0x74, 0x69, + 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, + 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x14, + 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x75, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, + 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, + 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, + 0x9c, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, + 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x43, 0x0a, 0x11, 0x66, 0x75, 0x74, + 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x11, 0x66, 0x75, 0x74, + 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x22, 0xbd, + 0x01, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, + 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x40, + 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x65, 0x6e, 0x64, + 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x44, 0x69, 0x66, 0x66, 0x12, + 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, + 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x3f, 0x0a, 0x08, 0x74, 0x6f, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, + 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x44, + 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, + 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, + 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, + 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, + 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x24, + 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 65a84bcb7..2e2061bce 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -83,10 +83,11 @@ message DbBlockStatus { message DbBlockGhostdagData { uint64 blueScore = 1; - DbHash selectedParent = 2; - repeated DbHash mergeSetBlues = 3; - repeated DbHash mergeSetReds = 4; - repeated DbBluesAnticoneSizes bluesAnticoneSizes = 5; + bytes blueWork = 2; + DbHash selectedParent = 3; + repeated DbHash mergeSetBlues = 4; + repeated DbHash mergeSetReds = 5; + repeated DbBluesAnticoneSizes bluesAnticoneSizes = 6; } message DbBluesAnticoneSizes { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index ca0db772f..a528811ff 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -95,6 +95,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager, dagTopologyManager, ghostdagDataStore, + blockHeaderStore, dagParams.K) dagTraversalManager := dagtraversalmanager.New( dbManager, diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 61b0c3c12..856a02dce 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -155,7 +155,7 @@ func TestFinality(t *testing.T) { t.Fatalf("TestFinality: Failed getting the ghost dag data of the sidechain tip: %v", err) } - if selectedTipGhostDagData.BlueScore() > sideChainTipGhostDagData.BlueScore() { + if selectedTipGhostDagData.BlueWork().Cmp(sideChainTipGhostDagData.BlueWork()) == 1 { t.Fatalf("sideChainTip is not the bluest tip when it is expected to be") } diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go index 2f1b4370d..d4967df71 100644 --- a/domain/consensus/model/ghostdag.go +++ b/domain/consensus/model/ghostdag.go @@ -1,10 +1,15 @@ package model -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "math/big" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // BlockGHOSTDAGData represents GHOSTDAG data for some block type BlockGHOSTDAGData interface { BlueScore() uint64 + BlueWork() *big.Int SelectedParent() *externalapi.DomainHash MergeSetBlues() []*externalapi.DomainHash MergeSetReds() []*externalapi.DomainHash diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index abaaf183e..6a84f7b70 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -7,6 +7,8 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/util" + "math/big" ) type ghostdagHelper struct { @@ -14,6 +16,7 @@ type ghostdagHelper struct { dataStore model.GHOSTDAGDataStore dbAccess model.DBReader dagTopologyManager model.DAGTopologyManager + headerStore model.BlockHeaderStore } // New creates a new instance of this alternative ghostdag impl @@ -21,12 +24,14 @@ func New( databaseContext model.DBReader, dagTopologyManager model.DAGTopologyManager, ghostdagDataStore model.GHOSTDAGDataStore, + headerStore model.BlockHeaderStore, k model.KType) model.GHOSTDAGManager { return &ghostdagHelper{ dbAccess: databaseContext, dagTopologyManager: dagTopologyManager, dataStore: ghostdagDataStore, + headerStore: headerStore, k: k, } } @@ -34,8 +39,10 @@ func New( /* --------------------------------------------- */ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error { - var maxNum uint64 = 0 - var myScore uint64 = 0 + myWork := new(big.Int) + maxWork := new(big.Int) + var myScore uint64 + var spScore uint64 /* find the selectedParent */ blockParents, err := gh.dagTopologyManager.Parents(blockCandidate) if err != nil { @@ -47,16 +54,21 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error if err != nil { return err } + blockWork := blockData.BlueWork() blockScore := blockData.BlueScore() - if blockScore > maxNum { + if blockWork.Cmp(maxWork) == 1 { selectedParent = parent - maxNum = blockScore + maxWork = blockWork + spScore = blockScore } - if blockScore == maxNum && ismoreHash(parent, selectedParent) { + if blockWork.Cmp(maxWork) == 0 && ismoreHash(parent, selectedParent) { selectedParent = parent + maxWork = blockWork + spScore = blockScore } } - myScore = maxNum + myWork.Set(maxWork) + myScore = spScore /* Goal: iterate blockCandidate's mergeSet and divide it to : blue, blues, reds. */ var mergeSetBlues = make([]*externalapi.DomainHash, 0) @@ -70,7 +82,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error return err } - err = gh.sortByBlueScore(mergeSetArr) + err = gh.sortByBlueWork(mergeSetArr) if err != nil { return err } @@ -94,7 +106,16 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error } myScore += uint64(len(mergeSetBlues)) - e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, selectedParent, mergeSetBlues, mergeSetReds, nil) + // We add up all the *work*(not blueWork) that all our blues and selected parent did + for _, blue := range mergeSetBlues { + header, err := gh.headerStore.BlockHeader(gh.dbAccess, blue) + if err != nil { + return err + } + myWork.Add(myWork, util.CalcWork(header.Bits)) + } + + e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil) gh.dataStore.Stage(blockCandidate, e) return nil } @@ -337,7 +358,7 @@ func (gh *ghostdagHelper) findBlueSet(blueSet *[]*externalapi.DomainHash, select } /* ----------------sortByBlueScore------------------- */ -func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error { +func (gh *ghostdagHelper) sortByBlueWork(arr []*externalapi.DomainHash) error { var err error = nil sort.Slice(arr, func(i, j int) bool { @@ -354,10 +375,10 @@ func (gh *ghostdagHelper) sortByBlueScore(arr []*externalapi.DomainHash) error { return false } - if blockLeft.BlueScore() < blockRight.BlueScore() { + if blockLeft.BlueWork().Cmp(blockRight.BlueWork()) == -1 { return true } - if blockLeft.BlueScore() == blockRight.BlueScore() { + if blockLeft.BlueWork().Cmp(blockRight.BlueWork()) == 0 { return ismoreHash(arr[j], arr[i]) } return false diff --git a/domain/consensus/processes/ghostdagmanager/compare.go b/domain/consensus/processes/ghostdagmanager/compare.go index 76ad1844a..d5143513c 100644 --- a/domain/consensus/processes/ghostdagmanager/compare.go +++ b/domain/consensus/processes/ghostdagmanager/compare.go @@ -56,11 +56,14 @@ func (gm *ghostdagManager) ChooseSelectedParent(blockHashes ...*externalapi.Doma func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool { - blockBlueScoreA := ghostdagDataA.BlueScore() - blockBlueScoreB := ghostdagDataB.BlueScore() - if blockBlueScoreA == blockBlueScoreB { + switch ghostdagDataA.BlueWork().Cmp(ghostdagDataB.BlueWork()) { + case -1: + return true + case 1: + return false + case 0: return hashes.Less(blockHashA, blockHashB) + default: + panic("big.Int.Cmp is defined to always return -1/1/0 and nothing else") } - - return blockBlueScoreA < blockBlueScoreB } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index 8e24ea4c1..f82fceb36 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -3,7 +3,9 @@ package ghostdagmanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/util" "github.com/pkg/errors" + "math/big" ) // GHOSTDAG runs the GHOSTDAG protocol and calculates the block BlockGHOSTDAGData by the given parents. @@ -26,6 +28,7 @@ import ( // For further details see the article https://eprint.iacr.org/2018/104.pdf func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { newBlockData := &blockGHOSTDAGData{ + blueWork: new(big.Int), mergeSetBlues: make([]*externalapi.DomainHash, 0), mergeSetReds: make([]*externalapi.DomainHash, 0), bluesAnticoneSizes: make(map[externalapi.DomainHash]model.KType), @@ -77,9 +80,20 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { return err } newBlockData.blueScore = selectedParentGHOSTDAGData.BlueScore() + uint64(len(newBlockData.mergeSetBlues)) + // We inherit the bluework from the selected parent + newBlockData.blueWork.Set(selectedParentGHOSTDAGData.BlueWork()) + // Then we add up all the *work*(not blueWork) that all of newBlock merge set blues and selected parent did + for _, blue := range newBlockData.mergeSetBlues { + header, err := gm.headerStore.BlockHeader(gm.databaseContext, blue) + if err != nil { + return err + } + newBlockData.blueWork.Add(newBlockData.blueWork, util.CalcWork(header.Bits)) + } } else { // Genesis's blue score is defined to be 0. newBlockData.blueScore = 0 + newBlockData.blueWork.SetUint64(0) } gm.ghostdagDataStore.Stage(blockHash, newBlockData) diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go index b708241be..a488542c0 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go @@ -3,10 +3,12 @@ package ghostdagmanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "math/big" ) type blockGHOSTDAGData struct { blueScore uint64 + blueWork *big.Int selectedParent *externalapi.DomainHash mergeSetBlues []*externalapi.DomainHash mergeSetReds []*externalapi.DomainHash @@ -16,6 +18,7 @@ type blockGHOSTDAGData struct { // NewBlockGHOSTDAGData creates a new instance of model.BlockGHOSTDAGData func NewBlockGHOSTDAGData( blueScore uint64, + blueWork *big.Int, selectedParent *externalapi.DomainHash, mergeSetBlues []*externalapi.DomainHash, mergeSetReds []*externalapi.DomainHash, @@ -23,6 +26,7 @@ func NewBlockGHOSTDAGData( return &blockGHOSTDAGData{ blueScore: blueScore, + blueWork: blueWork, selectedParent: selectedParent, mergeSetBlues: mergeSetBlues, mergeSetReds: mergeSetReds, @@ -34,6 +38,10 @@ func (bgd *blockGHOSTDAGData) BlueScore() uint64 { return bgd.blueScore } +func (bgd *blockGHOSTDAGData) BlueWork() *big.Int { + return bgd.blueWork +} + func (bgd *blockGHOSTDAGData) SelectedParent() *externalapi.DomainHash { return bgd.selectedParent } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index 6afcf6091..49208549a 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -2,147 +2,173 @@ package ghostdagmanager_test import ( "encoding/json" + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" + "github.com/kaspanet/kaspad/util" + "math/big" "os" "path/filepath" "reflect" "testing" - "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" ) +type block struct { + ID string `json:"ID"` + Score uint64 `json:"ExpectedScore"` + SelectedParent string `json:"ExpectedSelectedParent"` + MergeSetReds []string `json:"ExpectedReds"` + MergeSetBlues []string `json:"ExpectedBlues"` + Parents []string `json:"Parents"` +} + +// json struct: +type testDag struct { + K model.KType `json:"K"` + GenesisID string `json:"GenesisID"` + ExpectedMergeSetReds []string `json:"ExpectedReds"` + Blocks []block `json:"Blocks"` +} + +type implManager struct { + function func( + databaseContext model.DBReader, + dagTopologyManager model.DAGTopologyManager, + ghostdagDataStore model.GHOSTDAGDataStore, + headerStore model.BlockHeaderStore, + k model.KType) model.GHOSTDAGManager + implName string +} + // TestGHOSTDAG iterates over several dag simulations, and checks // that the blue score, blue set and selected parent of each // block are calculated as expected. func TestGHOSTDAG(t *testing.T) { - - type block struct { - ID string `json:"ID"` - Score uint64 `json:"ExpectedScore"` - SelectedParent string `json:"ExpectedSelectedParent"` - MergeSetReds []string `json:"ExpectedReds"` - MergeSetBlues []string `json:"ExpectedBlues"` - Parents []string `json:"Parents"` + //NOTE: FOR ADDING/REMOVING AN IMPLEMENTATION CHANGE BELOW: + implementationFactories := []implManager{ + {ghostdagmanager.New, "Original"}, + {ghostdag2.New, "Tal's impl"}, } + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - // json struct: - type testDag struct { - K model.KType `json:"K"` - GenesisID string `json:"GenesisID"` - ExpectedMergeSetReds []string `json:"ExpectedReds"` - Blocks []block `json:"Blocks"` - } - - type implManager struct { - function func( - databaseContext model.DBReader, - dagTopologyManager model.DAGTopologyManager, - ghostdagDataStore model.GHOSTDAGDataStore, - k model.KType) model.GHOSTDAGManager - implName string - } - - dagTopology := &DAGTopologyManagerImpl{ - parentsMap: make(map[externalapi.DomainHash][]*externalapi.DomainHash), - } - - ghostdagDataStore := &GHOSTDAGDataStoreImpl{ - dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData), - } - blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, nil, nil, nil, nil) - - var testsCounter int - err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } - jsonFile, err := os.Open(path) - if err != nil { - t.Fatalf("TestGHOSTDAG : failed opening the json file %s: %v", info.Name(), err) - } - defer jsonFile.Close() - var test testDag - decoder := json.NewDecoder(jsonFile) - decoder.DisallowUnknownFields() - err = decoder.Decode(&test) - if err != nil { - t.Fatalf("TestGHOSTDAG:failed decoding json: %v", err) + dagTopology := &DAGTopologyManagerImpl{ + parentsMap: make(map[externalapi.DomainHash][]*externalapi.DomainHash), } - var genesisHash externalapi.DomainHash - copy(genesisHash[:], test.GenesisID) - - dagTopology.parentsMap[genesisHash] = nil - - ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis - - //NOTE: FOR ADDING/REMOVING AN IMPLEMENTATION CHANGE BELOW: - implementationFactories := []implManager{ - {ghostdagmanager.New, "Original"}, - {ghostdag2.New, "Tal's impl"}, + ghostdagDataStore := &GHOSTDAGDataStoreImpl{ + dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData), } - for _, factory := range implementationFactories { + blockHeadersStore := &blockHeadersStore{ + dagMap: make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader), + } - g := factory.function(nil, dagTopology, ghostdagDataStore, model.KType(test.K)) - for _, testBlockData := range test.Blocks { - - blockID := StringToByte(testBlockData.ID) - dagTopology.parentsMap[*blockID] = StringToByteArray(testBlockData.Parents) - - err := g.GHOSTDAG(blockID) - if err != nil { - t.Fatalf("Test failed: \n Impl: %s,FileName: %s \n error on GHOSTDAG - block %s: %s.", - factory.implName, info.Name(), testBlockData.ID, err) - } - ghostdagData, err := ghostdagDataStore.Get(nil, blockID) - if err != nil { - t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: ghostdagDataStore error: %v.", - factory.implName, info.Name(), testBlockData.ID, err) - } - - if testBlockData.Score != (ghostdagData.BlueScore()) { - t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue score %d but got %d.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore()) - } - - if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent() { - t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, ghostdagData.SelectedParent()) - } - - if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues()) { - t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues())) - } - - if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds()) { - t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds())) - } + blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil) + genesisHeader := params.GenesisBlock.Header + genesisWork := util.CalcWork(genesisHeader.Bits) + var testsCounter int + err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err } - dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash) - dagTopology.parentsMap[genesisHash] = nil - ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) - ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis - } + if info.IsDir() { + return nil + } + jsonFile, err := os.Open(path) + if err != nil { + t.Fatalf("TestGHOSTDAG : failed opening the json file %s: %v", info.Name(), err) + } + defer jsonFile.Close() + var test testDag + decoder := json.NewDecoder(jsonFile) + decoder.DisallowUnknownFields() + err = decoder.Decode(&test) + if err != nil { + t.Fatalf("TestGHOSTDAG:failed decoding json: %v", err) + } + params.K = test.K - testsCounter++ - return nil + var genesisHash externalapi.DomainHash + copy(genesisHash[:], test.GenesisID) + + dagTopology.parentsMap[genesisHash] = nil + + ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis + blockHeadersStore.dagMap[genesisHash] = genesisHeader + + for _, factory := range implementationFactories { + + g := factory.function(nil, dagTopology, ghostdagDataStore, blockHeadersStore, test.K) + for _, testBlockData := range test.Blocks { + + blockID := StringToByte(testBlockData.ID) + dagTopology.parentsMap[*blockID] = StringToByteArray(testBlockData.Parents) + blockHeadersStore.dagMap[*blockID] = &externalapi.DomainBlockHeader{ + ParentHashes: StringToByteArray(testBlockData.Parents), + Bits: genesisHeader.Bits, + } + + err := g.GHOSTDAG(blockID) + if err != nil { + t.Fatalf("Test failed: \n Impl: %s,FileName: %s \n error on GHOSTDAG - block %s: %s.", + factory.implName, info.Name(), testBlockData.ID, err) + } + ghostdagData, err := ghostdagDataStore.Get(nil, blockID) + if err != nil { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: ghostdagDataStore error: %v.", + factory.implName, info.Name(), testBlockData.ID, err) + } + + // because the difficulty is constant and equal to genesis the work should be blueScore*genesisWork. + expectedWork := new(big.Int).Mul(genesisWork, new(big.Int).SetUint64(testBlockData.Score)) + if expectedWork.Cmp(ghostdagData.BlueWork()) != 0 { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue work %d but got %d.", + factory.implName, info.Name(), testBlockData.ID, expectedWork, ghostdagData.BlueWork()) + } + if testBlockData.Score != (ghostdagData.BlueScore()) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected blue score %d but got %d.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore()) + } + + if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent() { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, string(ghostdagData.SelectedParent()[:])) + } + + if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues()) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues())) + } + + if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds()) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds())) + } + } + dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash) + dagTopology.parentsMap[genesisHash] = nil + ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) + ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis + blockHeadersStore.dagMap = make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader) + blockHeadersStore.dagMap[genesisHash] = genesisHeader + } + + testsCounter++ + return nil + }) + if err != nil { + t.Fatal(err) + } + if testsCounter != 3 { + t.Fatalf("Expected 3 test files, ran %d instead", testsCounter) + } }) - if err != nil { - t.Fatal(err) - } - if testsCounter != 3 { - t.Fatalf("Expected 3 test files, ran %d instead", testsCounter) - } } func hashesToStrings(arr []*externalapi.DomainHash) []string { @@ -268,3 +294,50 @@ func (dt *DAGTopologyManagerImpl) IsInSelectedParentChainOf(blockHashA *external func (dt *DAGTopologyManagerImpl) SetParents(blockHash *externalapi.DomainHash, parentHashes []*externalapi.DomainHash) error { panic("unimplemented") } + +type blockHeadersStore struct { + dagMap map[externalapi.DomainHash]*externalapi.DomainBlockHeader +} + +func (b *blockHeadersStore) Discard() { panic("unimplemented") } + +func (b *blockHeadersStore) Commit(_ model.DBTransaction) error { panic("unimplemented") } + +func (b *blockHeadersStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) { + b.dagMap[*blockHash] = blockHeader +} + +func (b *blockHeadersStore) IsStaged() bool { panic("unimplemented") } + +func (b *blockHeadersStore) BlockHeader(_ model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { + header, ok := b.dagMap[*blockHash] + if ok { + return header, nil + } + return nil, errors.New("Header isn't in the store") +} + +func (b *blockHeadersStore) HasBlockHeader(_ model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { + _, ok := b.dagMap[*blockHash] + return ok, nil +} + +func (b *blockHeadersStore) BlockHeaders(_ model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) { + res := make([]*externalapi.DomainBlockHeader, 0, len(blockHashes)) + for _, hash := range blockHashes { + header, err := b.BlockHeader(nil, hash) + if err != nil { + return nil, err + } + res = append(res, header) + } + return res, nil +} + +func (b *blockHeadersStore) Delete(blockHash *externalapi.DomainHash) { + delete(b.dagMap, *blockHash) +} + +func (b blockHeadersStore) Count() uint64 { + return uint64(len(b.dagMap)) +} diff --git a/domain/consensus/processes/ghostdagmanager/ghostdagmanager.go b/domain/consensus/processes/ghostdagmanager/ghostdagmanager.go index 821bdb81c..c47dfebc5 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdagmanager.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdagmanager.go @@ -9,6 +9,7 @@ type ghostdagManager struct { databaseContext model.DBReader dagTopologyManager model.DAGTopologyManager ghostdagDataStore model.GHOSTDAGDataStore + headerStore model.BlockHeaderStore k model.KType } @@ -17,12 +18,14 @@ func New( databaseContext model.DBReader, dagTopologyManager model.DAGTopologyManager, ghostdagDataStore model.GHOSTDAGDataStore, + headerStore model.BlockHeaderStore, k model.KType) model.GHOSTDAGManager { return &ghostdagManager{ databaseContext: databaseContext, dagTopologyManager: dagTopologyManager, ghostdagDataStore: ghostdagDataStore, + headerStore: headerStore, k: k, } } From 4886425caf9c72b274503ed524f580dd9faca002 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 6 Dec 2020 16:02:48 +0200 Subject: [PATCH 113/351] [NOD-1589] Re-enable DisableDifficultyAdjustment (#1182) * [NOD-1589] Re-enable DisableDifficultyAdjustment * [NOD-1589] Remove simnet from TestDifficulty * [NOD-1589] Update comment --- domain/consensus/factory.go | 3 +- .../blockvalidator/blockvalidator.go | 38 ++++++++----------- .../difficultymanager/difficultymanager.go | 14 +++---- .../difficultymanager_test.go | 5 ++- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index a528811ff..c37db65f0 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -126,6 +126,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTraversalManager, dagParams.PowMax, dagParams.DifficultyAdjustmentWindowSize, + dagParams.DisableDifficultyAdjustment, dagParams.TargetTimePerBlock, dagParams.GenesisHash) coinbaseManager := coinbasemanager.New( @@ -148,8 +149,6 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagParams.SkipProofOfWork, genesisHash, dagParams.EnableNonNativeSubnetworks, - dagParams.DisableDifficultyAdjustment, - dagParams.DifficultyAdjustmentWindowSize, dagParams.MaxBlockSize, dagParams.MergeSetSizeLimit, dagParams.MaxBlockParents, diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 07a55855d..2403a67fc 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -11,16 +11,14 @@ import ( // blockValidator exposes a set of validation classes, after which // it's possible to determine whether either a block is valid type blockValidator struct { - powMax *big.Int - skipPoW bool - genesisHash *externalapi.DomainHash - enableNonNativeSubnetworks bool - disableDifficultyAdjustment bool - powMaxBits uint32 - difficultyAdjustmentWindowSize uint64 - maxBlockSize uint64 - mergeSetSizeLimit uint64 - maxBlockParents model.KType + powMax *big.Int + skipPoW bool + genesisHash *externalapi.DomainHash + enableNonNativeSubnetworks bool + powMaxBits uint32 + maxBlockSize uint64 + mergeSetSizeLimit uint64 + maxBlockParents model.KType databaseContext model.DBReader difficultyManager model.DifficultyManager @@ -44,8 +42,6 @@ func New(powMax *big.Int, skipPoW bool, genesisHash *externalapi.DomainHash, enableNonNativeSubnetworks bool, - disableDifficultyAdjustment bool, - difficultyAdjustmentWindowSize uint64, maxBlockSize uint64, mergeSetSizeLimit uint64, maxBlockParents model.KType, @@ -68,16 +64,14 @@ func New(powMax *big.Int, blockStatusStore model.BlockStatusStore) model.BlockValidator { return &blockValidator{ - powMax: powMax, - skipPoW: skipPoW, - genesisHash: genesisHash, - enableNonNativeSubnetworks: enableNonNativeSubnetworks, - disableDifficultyAdjustment: disableDifficultyAdjustment, - powMaxBits: util.BigToCompact(powMax), - difficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, - maxBlockSize: maxBlockSize, - mergeSetSizeLimit: mergeSetSizeLimit, - maxBlockParents: maxBlockParents, + powMax: powMax, + skipPoW: skipPoW, + genesisHash: genesisHash, + enableNonNativeSubnetworks: enableNonNativeSubnetworks, + powMaxBits: util.BigToCompact(powMax), + maxBlockSize: maxBlockSize, + mergeSetSizeLimit: mergeSetSizeLimit, + maxBlockParents: maxBlockParents, databaseContext: databaseContext, difficultyManager: difficultyManager, diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index 7a18faad6..058225bc9 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -22,12 +22,12 @@ type difficultyManager struct { genesisHash *externalapi.DomainHash powMax *big.Int difficultyAdjustmentWindowSize uint64 + disableDifficultyAdjustment bool targetTimePerBlock time.Duration } // New instantiates a new DifficultyManager -func New( - databaseContext model.DBReader, +func New(databaseContext model.DBReader, ghostdagManager model.GHOSTDAGManager, ghostdagStore model.GHOSTDAGDataStore, headerStore model.BlockHeaderStore, @@ -35,9 +35,9 @@ func New( dagTraversalManager model.DAGTraversalManager, powMax *big.Int, difficultyAdjustmentWindowSize uint64, + disableDifficultyAdjustment bool, targetTimePerBlock time.Duration, - genesisHash *externalapi.DomainHash, -) model.DifficultyManager { + genesisHash *externalapi.DomainHash) model.DifficultyManager { return &difficultyManager{ databaseContext: databaseContext, ghostdagManager: ghostdagManager, @@ -47,6 +47,7 @@ func New( dagTraversalManager: dagTraversalManager, powMax: powMax, difficultyAdjustmentWindowSize: difficultyAdjustmentWindowSize, + disableDifficultyAdjustment: disableDifficultyAdjustment, targetTimePerBlock: targetTimePerBlock, genesisHash: genesisHash, } @@ -63,13 +64,12 @@ func (dm *difficultyManager) genesisBits() (uint32, error) { // RequiredDifficulty returns the difficulty required for some block func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHash) (uint32, error) { - parents, err := dm.dagTopologyManager.Parents(blockHash) if err != nil { return 0, err } - // Genesis block - if len(parents) == 0 { + // Genesis block or network that doesn't have difficulty adjustment (such as simnet) + if len(parents) == 0 || dm.disableDifficultyAdjustment { return dm.genesisBits() } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index 8b8de6df3..b938cab6c 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -15,6 +15,9 @@ import ( func TestDifficulty(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + if params.DisableDifficultyAdjustment { + return + } params.K = 1 params.DifficultyAdjustmentWindowSize = 264 @@ -118,7 +121,7 @@ func TestDifficulty(t *testing.T) { switch params.Name { case "kaspa-testnet", "kaspa-devnet": expectedBits = uint32(0x1e7f83df) - case "kaspa-mainnet", "kaspa-simnet": + case "kaspa-mainnet": expectedBits = uint32(0x207f83df) } From 7f899b0d0955f01eb59e8889ce0aeca4b34ce0d3 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 6 Dec 2020 16:23:56 +0200 Subject: [PATCH 114/351] [NOD-1579] Improve the IBD mechanism (#1174) * [NOD-1579] Remove selected tip hash messages. * [NOD-1579] Start moving IBD stuff into blockrelay. * [NOD-1579] Rename relaytransactions to transactionrelay. * [NOD-1579] Move IBD files into blockrelay. * [NOD-1579] Remove flow stuff from ibd.go. * [NOD-1579] Bring back IsInIBD(). * [NOD-1579] Simplify block relay flow. * [NOD-1579] Check orphan pool for missing parents to avoid unnecessary processing. * [NOD-1579] Implement processOrphan. * [NOD-1579] Implement addToOrphanSetAndRequestMissingParents. * [NOD-1579] Fix TestIBD. * [NOD-1579] Implement isBlockInOrphanResolutionRange. * [NOD-1579] Implement limited block locators. * [NOD-1579] Add some comments. * [NOD-1579] Specifically check for StatusHeaderOnly in blockrelay. * [NOD-1579] Simplify runIBDIfNotRunning. * [NOD-1579] Don't run IBD if it is already running. * [NOD-1579] Fix a comment. * [NOD-1579] Rename mode to syncInfo. * [NOD-1579] Simplify validateAndInsertBlock. * [NOD-1579] Fix bad SyncStateSynced condition. * [NOD-1579] Implement validateAgainstSyncStateAndResolveInsertMode. * [NOD-1579] Use insertModeHeader. * [NOD-1579] Add logs to TrySetIBDRunning and UnsetIBDRunning. * [NOD-1579] Implement and use dequeueIncomingMessageAndSkipInvs. * [NOD-1579] Fix a log. * [NOD-1579] Fix a bug in createBlockLocator. * [NOD-1579] Rename a variable. * [NOD-1579] Fix a slew of bugs in missingBlockBodyHashes and selectedChildIterator. * [NOD-1579] Fix bad chunk size in syncMissingBlockBodies. * [NOD-1579] Remove maxOrphanBlueScoreDiff. * [NOD-1579] Fix merge errors. * [NOD-1579] Remove a debug log. * [NOD-1579] Add logs. * [NOD-1579] Make various go quality tools happy. * [NOD-1579] Fix a typo in a variable name. * [NOD-1579] Fix full blocks over header-only blocks not failing the missing-parents validation. * [NOD-1579] Add an error log about a condition that should never happen. * [NOD-1579] Check all antiPast hashes instead of just the lowHash's anticone to filter for header-only blocks. * [NOD-1579] Remove the nil stuff from GetBlockLocator. * [NOD-1579] Remove superfluous condition in handleRelayInvsFlow.start(). * [NOD-1579] Return a boolean from requestBlock instead of comparing to nil. * [NOD-1579] Fix a bad log.Debugf. * [NOD-1579] Remove a redundant check. * [NOD-1579] Change an info log to a warning log. * [NOD-1579] Move OnNewBlock out of relayBlock. * [NOD-1579] Remove redundant exists check from runIBDIfNotRunning. * [NOD-1579] Fix bad call to OnNewBlock. * [NOD-1579] Remove an impossible check. * [NOD-1579] Added a log. * [NOD-1579] Rename insertModeBlockWithoutUpdatingVirtual to insertModeBlockBody. * [NOD-1579] Add a check for duplicate headers. * [NOD-1579] Added a comment. * [NOD-1579] Tighten a stop condition. * [NOD-1579] Simplify a log. * [NOD-1579] Clarify a log. * [NOD-1579] Move a log. --- app/appmessage/message.go | 4 - app/appmessage/p2p_msgibdblock_test.go | 2 +- app/appmessage/p2p_msgrequestblocklocator.go | 12 +- .../p2p_msgrequestblocklocator_test.go | 2 +- app/appmessage/p2p_msgrequestibdblocks.go | 4 - app/appmessage/p2p_msgrequestselectedtip.go | 21 - .../p2p_msgrequestselectedtip_test.go | 20 - app/appmessage/p2p_msgselectedtip.go | 28 - app/appmessage/p2p_msgselectedtip_test.go | 18 - app/appmessage/p2p_msgversion.go | 6 +- app/appmessage/p2p_msgversion_test.go | 8 +- app/appmessage/rpc_get_connected_peer_info.go | 2 - app/protocol/flowcontext/blocks.go | 26 +- app/protocol/flowcontext/flow_context.go | 10 +- app/protocol/flowcontext/ibd.go | 130 - app/protocol/flowcontext/orphans.go | 2 +- app/protocol/flowcontext/transactions.go | 6 +- .../flows/blockrelay/block_locator.go | 29 + .../handle_ibd_block_requests.go | 5 +- .../blockrelay/handle_relay_block_requests.go | 3 +- .../flows/blockrelay/handle_relay_invs.go | 244 +- .../handle_request_block_locator.go | 15 +- .../handle_request_headers.go | 2 +- .../handle_request_headers_test.go | 2 +- ...dle_request_ibd_root_utxo_set_and_block.go | 2 +- app/protocol/flows/{ibd => blockrelay}/ibd.go | 492 ++- app/protocol/flows/handshake/handshake.go | 7 - app/protocol/flows/handshake/sendversion.go | 13 +- app/protocol/flows/ibd/log.go | 9 - .../handle_request_selected_tip.go | 66 - .../ibd/selectedtip/request_selected_tip.go | 78 - .../handle_relayed_transactions.go | 2 +- .../handle_requested_transactions.go | 2 +- .../shared_requested_transactions.go | 2 +- app/protocol/manager.go | 6 - app/protocol/peer/peer.go | 71 +- app/protocol/protocol.go | 98 +- .../rpchandlers/get_connected_peer_info.go | 3 - domain/consensus/consensus.go | 4 +- domain/consensus/factory.go | 2 +- .../consensus/model/externalapi/consensus.go | 2 +- domain/consensus/model/externalapi/sync.go | 27 +- .../model/interface_processes_syncmanager.go | 2 +- .../blockprocessor/blockprocessor.go | 7 +- .../blockprocessor/validateandinsertblock.go | 188 +- .../processes/blockvalidator/proof_of_work.go | 25 +- .../dagtopologymanager/dagtopologymanager.go | 2 - .../selected_child_iterator.go | 4 +- .../processes/syncmanager/antipast.go | 49 +- .../processes/syncmanager/blocklocator.go | 35 +- .../processes/syncmanager/syncinfo.go | 47 +- .../processes/syncmanager/syncmanager.go | 4 +- domain/consensus/ruleerrors/rule_error.go | 2 - infrastructure/logger/logger.go | 4 - .../grpcserver/protowire/messages.pb.go | 3239 ++++++++--------- .../grpcserver/protowire/messages.proto | 17 +- .../protowire/p2p_request_block_locator.go | 2 + .../protowire/p2p_request_ibd_blocks.go | 10 - .../protowire/p2p_request_selected_tip.go | 11 - .../grpcserver/protowire/p2p_selected_tip.go | 19 - .../grpcserver/protowire/p2p_version.go | 7 - .../protowire/rpc_get_connected_peer_info.go | 4 - .../server/grpcserver/protowire/wire.go | 14 - .../standalone/minimal_net_adapter.go | 1 - testing/integration/ibd_test.go | 5 +- 65 files changed, 2217 insertions(+), 2968 deletions(-) delete mode 100644 app/appmessage/p2p_msgrequestselectedtip.go delete mode 100644 app/appmessage/p2p_msgrequestselectedtip_test.go delete mode 100644 app/appmessage/p2p_msgselectedtip.go delete mode 100644 app/appmessage/p2p_msgselectedtip_test.go delete mode 100644 app/protocol/flowcontext/ibd.go create mode 100644 app/protocol/flows/blockrelay/block_locator.go rename app/protocol/flows/{ibd => blockrelay}/handle_ibd_block_requests.go (90%) rename app/protocol/flows/{ibd => blockrelay}/handle_request_block_locator.go (86%) rename app/protocol/flows/{ibd => blockrelay}/handle_request_headers.go (99%) rename app/protocol/flows/{ibd => blockrelay}/handle_request_headers_test.go (95%) rename app/protocol/flows/{ibd => blockrelay}/handle_request_ibd_root_utxo_set_and_block.go (99%) rename app/protocol/flows/{ibd => blockrelay}/ibd.go (56%) delete mode 100644 app/protocol/flows/ibd/log.go delete mode 100644 app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go delete mode 100644 app/protocol/flows/ibd/selectedtip/request_selected_tip.go rename app/protocol/flows/{relaytransactions => transactionrelay}/handle_relayed_transactions.go (99%) rename app/protocol/flows/{relaytransactions => transactionrelay}/handle_requested_transactions.go (98%) rename app/protocol/flows/{relaytransactions => transactionrelay}/shared_requested_transactions.go (97%) delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_selected_tip.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_selected_tip.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index f4f66016d..7b12147d6 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -41,8 +41,6 @@ const ( CmdPong CmdRequestBlockLocator CmdBlockLocator - CmdSelectedTip - CmdRequestSelectedTip CmdInvRelayBlock CmdRequestRelayBlocks CmdInvTransaction @@ -123,8 +121,6 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdPong: "Pong", CmdRequestBlockLocator: "RequestBlockLocator", CmdBlockLocator: "BlockLocator", - CmdSelectedTip: "SelectedTip", - CmdRequestSelectedTip: "RequestSelectedTip", CmdInvRelayBlock: "InvRelayBlock", CmdRequestRelayBlocks: "RequestRelayBlocks", CmdInvTransaction: "InvTransaction", diff --git a/app/appmessage/p2p_msgibdblock_test.go b/app/appmessage/p2p_msgibdblock_test.go index 5998aa737..c72e1de09 100644 --- a/app/appmessage/p2p_msgibdblock_test.go +++ b/app/appmessage/p2p_msgibdblock_test.go @@ -25,7 +25,7 @@ func TestIBDBlock(t *testing.T) { bh := NewBlockHeader(1, parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce) // Ensure the command is expected value. - wantCmd := MessageCommand(17) + wantCmd := MessageCommand(15) msg := NewMsgIBDBlock(NewMsgBlock(bh)) if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgIBDBlock: wrong command - got %v want %v", diff --git a/app/appmessage/p2p_msgrequestblocklocator.go b/app/appmessage/p2p_msgrequestblocklocator.go index d1cd2f702..5956bf3ac 100644 --- a/app/appmessage/p2p_msgrequestblocklocator.go +++ b/app/appmessage/p2p_msgrequestblocklocator.go @@ -5,13 +5,14 @@ import ( ) // MsgRequestBlockLocator implements the Message interface and represents a kaspa -// RequestBlockLocator message. It is used to request a block locator between high -// and low hash. +// RequestBlockLocator message. It is used to request a block locator between low +// and high hash. // The locator is returned via a locator message (MsgBlockLocator). type MsgRequestBlockLocator struct { baseMessage - HighHash *externalapi.DomainHash LowHash *externalapi.DomainHash + HighHash *externalapi.DomainHash + Limit uint32 } // Command returns the protocol command string for the message. This is part @@ -23,9 +24,10 @@ func (msg *MsgRequestBlockLocator) Command() MessageCommand { // NewMsgRequestBlockLocator returns a new RequestBlockLocator message that conforms to the // Message interface using the passed parameters and defaults for the remaining // fields. -func NewMsgRequestBlockLocator(highHash, lowHash *externalapi.DomainHash) *MsgRequestBlockLocator { +func NewMsgRequestBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) *MsgRequestBlockLocator { return &MsgRequestBlockLocator{ - HighHash: highHash, LowHash: lowHash, + HighHash: highHash, + Limit: limit, } } diff --git a/app/appmessage/p2p_msgrequestblocklocator_test.go b/app/appmessage/p2p_msgrequestblocklocator_test.go index 9498d7d62..925f3922b 100644 --- a/app/appmessage/p2p_msgrequestblocklocator_test.go +++ b/app/appmessage/p2p_msgrequestblocklocator_test.go @@ -18,7 +18,7 @@ func TestRequestBlockLocator(t *testing.T) { // Ensure the command is expected value. wantCmd := MessageCommand(9) - msg := NewMsgRequestBlockLocator(highHash, &externalapi.DomainHash{}) + msg := NewMsgRequestBlockLocator(highHash, &externalapi.DomainHash{}, 0) if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgRequestBlockLocator: wrong command - got %v want %v", cmd, wantCmd) diff --git a/app/appmessage/p2p_msgrequestibdblocks.go b/app/appmessage/p2p_msgrequestibdblocks.go index 848490716..078a00dde 100644 --- a/app/appmessage/p2p_msgrequestibdblocks.go +++ b/app/appmessage/p2p_msgrequestibdblocks.go @@ -4,10 +4,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// MaxRequestIBDBlocksHashes is the maximum number of hashes that can -// be in a single RequestIBDBlocks message. -const MaxRequestIBDBlocksHashes = MaxInvPerMsg - // MsgRequestIBDBlocks implements the Message interface and represents a kaspa // RequestIBDBlocks message. It is used to request blocks as part of the IBD // protocol. diff --git a/app/appmessage/p2p_msgrequestselectedtip.go b/app/appmessage/p2p_msgrequestselectedtip.go deleted file mode 100644 index e52a28e6d..000000000 --- a/app/appmessage/p2p_msgrequestselectedtip.go +++ /dev/null @@ -1,21 +0,0 @@ -package appmessage - -// MsgRequestSelectedTip implements the Message interface and represents a kaspa -// RequestSelectedTip message. It is used to request the selected tip of another peer. -// -// This message has no payload. -type MsgRequestSelectedTip struct { - baseMessage -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgRequestSelectedTip) Command() MessageCommand { - return CmdRequestSelectedTip -} - -// NewMsgRequestSelectedTip returns a new kaspa RequestSelectedTip message that conforms to the -// Message interface. -func NewMsgRequestSelectedTip() *MsgRequestSelectedTip { - return &MsgRequestSelectedTip{} -} diff --git a/app/appmessage/p2p_msgrequestselectedtip_test.go b/app/appmessage/p2p_msgrequestselectedtip_test.go deleted file mode 100644 index 1191cdf50..000000000 --- a/app/appmessage/p2p_msgrequestselectedtip_test.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package appmessage - -import ( - "testing" -) - -// TestRequestSelectedTip tests the MsgRequestSelectedTip API. -func TestRequestSelectedTip(t *testing.T) { - // Ensure the command is expected value. - wantCmd := MessageCommand(12) - msg := NewMsgRequestSelectedTip() - if cmd := msg.Command(); cmd != wantCmd { - t.Errorf("NewMsgRequestSelectedTip: wrong command - got %v want %v", - cmd, wantCmd) - } -} diff --git a/app/appmessage/p2p_msgselectedtip.go b/app/appmessage/p2p_msgselectedtip.go deleted file mode 100644 index db0cd4213..000000000 --- a/app/appmessage/p2p_msgselectedtip.go +++ /dev/null @@ -1,28 +0,0 @@ -package appmessage - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// MsgSelectedTip implements the Message interface and represents a kaspa -// selectedtip message. It is used to answer getseltip messages and tell -// the asking peer what is the selected tip of this peer. -type MsgSelectedTip struct { - baseMessage - // The selected tip hash of the generator of the message. - SelectedTipHash *externalapi.DomainHash -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgSelectedTip) Command() MessageCommand { - return CmdSelectedTip -} - -// NewMsgSelectedTip returns a new kaspa selectedtip message that conforms to the -// Message interface. -func NewMsgSelectedTip(selectedTipHash *externalapi.DomainHash) *MsgSelectedTip { - return &MsgSelectedTip{ - SelectedTipHash: selectedTipHash, - } -} diff --git a/app/appmessage/p2p_msgselectedtip_test.go b/app/appmessage/p2p_msgselectedtip_test.go deleted file mode 100644 index 35ca71498..000000000 --- a/app/appmessage/p2p_msgselectedtip_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package appmessage - -import ( - "testing" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// TestSelectedTip tests the MsgSelectedTip API. -func TestSelectedTip(t *testing.T) { - // Ensure the command is expected value. - wantCmd := MessageCommand(11) - msg := NewMsgSelectedTip(&externalapi.DomainHash{}) - if cmd := msg.Command(); cmd != wantCmd { - t.Errorf("NewMsgSelectedTip: wrong command - got %v want %v", - cmd, wantCmd) - } -} diff --git a/app/appmessage/p2p_msgversion.go b/app/appmessage/p2p_msgversion.go index fc1fee48c..56f899497 100644 --- a/app/appmessage/p2p_msgversion.go +++ b/app/appmessage/p2p_msgversion.go @@ -53,9 +53,6 @@ type MsgVersion struct { // on the appmessage. This has a max length of MaxUserAgentLen. UserAgent string - // The selected tip hash of the generator of the version message. - SelectedTipHash *externalapi.DomainHash - // Don't announce transactions to peer. DisableRelayTx bool @@ -85,7 +82,7 @@ func (msg *MsgVersion) Command() MessageCommand { // Message interface using the passed parameters and defaults for the remaining // fields. func NewMsgVersion(addr *NetAddress, id *id.ID, network string, - selectedTipHash *externalapi.DomainHash, subnetworkID *externalapi.DomainSubnetworkID) *MsgVersion { + subnetworkID *externalapi.DomainSubnetworkID) *MsgVersion { // Limit the timestamp to one millisecond precision since the protocol // doesn't support better. @@ -97,7 +94,6 @@ func NewMsgVersion(addr *NetAddress, id *id.ID, network string, Address: addr, ID: id, UserAgent: DefaultUserAgent, - SelectedTipHash: selectedTipHash, DisableRelayTx: false, SubnetworkID: subnetworkID, } diff --git a/app/appmessage/p2p_msgversion_test.go b/app/appmessage/p2p_msgversion_test.go index 936f911e7..f03e61e8d 100644 --- a/app/appmessage/p2p_msgversion_test.go +++ b/app/appmessage/p2p_msgversion_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/davecgh/go-spew/spew" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/id" ) @@ -19,7 +18,6 @@ func TestVersion(t *testing.T) { pver := ProtocolVersion // Create version message data. - selectedTipHash := &externalapi.DomainHash{12, 34} tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 16111} me := NewNetAddress(tcpAddrMe, SFNodeNetwork) generatedID, err := id.GenerateID() @@ -28,7 +26,7 @@ func TestVersion(t *testing.T) { } // Ensure we get the correct data back out. - msg := NewMsgVersion(me, generatedID, "mainnet", selectedTipHash, nil) + msg := NewMsgVersion(me, generatedID, "mainnet", nil) if msg.ProtocolVersion != pver { t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v", msg.ProtocolVersion, pver) @@ -45,10 +43,6 @@ func TestVersion(t *testing.T) { t.Errorf("NewMsgVersion: wrong user agent - got %v, want %v", msg.UserAgent, DefaultUserAgent) } - if *msg.SelectedTipHash != *selectedTipHash { - t.Errorf("NewMsgVersion: wrong selected tip hash - got %s, want %s", - msg.SelectedTipHash, selectedTipHash) - } if msg.DisableRelayTx { t.Errorf("NewMsgVersion: disable relay tx is not false by "+ "default - got %v, want %v", msg.DisableRelayTx, false) diff --git a/app/appmessage/rpc_get_connected_peer_info.go b/app/appmessage/rpc_get_connected_peer_info.go index c6d937029..3bb4cbc38 100644 --- a/app/appmessage/rpc_get_connected_peer_info.go +++ b/app/appmessage/rpc_get_connected_peer_info.go @@ -41,8 +41,6 @@ type GetConnectedPeerInfoMessage struct { ID string Address string LastPingDuration int64 - SelectedTipHash string - IsSyncNode bool IsOutbound bool TimeOffset int64 UserAgent string diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 592c1b53c..78d4ef6eb 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -53,7 +53,7 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded( f.updateTransactionsToRebroadcast(block) // Don't relay transactions when in IBD. - if atomic.LoadUint32(&f.isInIBD) != 0 { + if f.IsIBDRunning() { return nil } @@ -103,3 +103,27 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { } return f.Broadcast(appmessage.NewMsgInvBlock(consensushashing.BlockHash(block))) } + +// IsIBDRunning returns true if IBD is currently marked as running +func (f *FlowContext) IsIBDRunning() bool { + return atomic.LoadUint32(&f.isInIBD) != 0 +} + +// TrySetIBDRunning attempts to set `isInIBD`. Returns false +// if it is already set +func (f *FlowContext) TrySetIBDRunning() bool { + succeeded := atomic.CompareAndSwapUint32(&f.isInIBD, 0, 1) + if succeeded { + log.Infof("IBD started") + } + return succeeded +} + +// UnsetIBDRunning unsets isInIBD +func (f *FlowContext) UnsetIBDRunning() { + succeeded := atomic.CompareAndSwapUint32(&f.isInIBD, 1, 0) + if !succeeded { + panic("attempted to unset isInIBD when it was not set to begin with") + } + log.Infof("IBD finished") +} diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index c88906a02..0394e9a87 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -9,7 +9,7 @@ import ( "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/app/protocol/flows/blockrelay" - "github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions" + "github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/infrastructure/config" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" @@ -41,13 +41,11 @@ type FlowContext struct { transactionsToRebroadcastLock sync.Mutex transactionsToRebroadcast map[externalapi.DomainTransactionID]*externalapi.DomainTransaction lastRebroadcastTime time.Time - sharedRequestedTransactions *relaytransactions.SharedRequestedTransactions + sharedRequestedTransactions *transactionrelay.SharedRequestedTransactions sharedRequestedBlocks *blockrelay.SharedRequestedBlocks - isInIBD uint32 - startIBDMutex sync.Mutex - ibdPeer *peerpkg.Peer + isInIBD uint32 peers map[id.ID]*peerpkg.Peer peersMutex sync.RWMutex @@ -66,7 +64,7 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage domain: domain, addressManager: addressManager, connectionManager: connectionManager, - sharedRequestedTransactions: relaytransactions.NewSharedRequestedTransactions(), + sharedRequestedTransactions: transactionrelay.NewSharedRequestedTransactions(), sharedRequestedBlocks: blockrelay.NewSharedRequestedBlocks(), peers: make(map[id.ID]*peerpkg.Peer), transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction), diff --git a/app/protocol/flowcontext/ibd.go b/app/protocol/flowcontext/ibd.go deleted file mode 100644 index e7d8a7b92..000000000 --- a/app/protocol/flowcontext/ibd.go +++ /dev/null @@ -1,130 +0,0 @@ -package flowcontext - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "sync/atomic" - "time" - - "github.com/kaspanet/kaspad/util/mstime" - - peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" -) - -// StartIBDIfRequired selects a peer and starts IBD against it -// if required -func (f *FlowContext) StartIBDIfRequired() error { - f.startIBDMutex.Lock() - defer f.startIBDMutex.Unlock() - - if f.IsInIBD() { - return nil - } - - syncInfo, err := f.domain.Consensus().GetSyncInfo() - if err != nil { - return err - } - - if syncInfo.State == externalapi.SyncStateRelay { - return nil - } - - peer, err := f.selectPeerForIBD(syncInfo) - if err != nil { - return err - } - if peer == nil { - spawn("StartIBDIfRequired-requestSelectedTipsIfRequired", f.requestSelectedTipsIfRequired) - return nil - } - - atomic.StoreUint32(&f.isInIBD, 1) - f.ibdPeer = peer - spawn("StartIBDIfRequired-peer.StartIBD", peer.StartIBD) - - return nil -} - -// IsInIBD is true if IBD is currently running -func (f *FlowContext) IsInIBD() bool { - return atomic.LoadUint32(&f.isInIBD) != 0 -} - -// selectPeerForIBD returns the first peer whose selected tip -// hash is not in our DAG -func (f *FlowContext) selectPeerForIBD(syncInfo *externalapi.SyncInfo) (*peerpkg.Peer, error) { - f.peersMutex.RLock() - defer f.peersMutex.RUnlock() - - for _, peer := range f.peers { - peerSelectedTipHash := peer.SelectedTipHash() - - if f.IsOrphan(peerSelectedTipHash) { - continue - } - - blockInfo, err := f.domain.Consensus().GetBlockInfo(peerSelectedTipHash) - if err != nil { - return nil, err - } - if syncInfo.State == externalapi.SyncStateHeadersFirst { - if !blockInfo.Exists { - return peer, nil - } - } else { - if blockInfo.Exists && blockInfo.BlockStatus == externalapi.StatusHeaderOnly && - blockInfo.IsBlockInHeaderPruningPointFuture { - return peer, nil - } - } - } - return nil, nil -} - -func (f *FlowContext) requestSelectedTipsIfRequired() { - dagTimeCurrent, err := f.shouldRequestSelectedTips() - if err != nil { - panic(err) - } - if dagTimeCurrent { - return - } - f.requestSelectedTips() -} - -func (f *FlowContext) shouldRequestSelectedTips() (bool, error) { - const minDurationToRequestSelectedTips = time.Minute - virtualSelectedParent, err := f.domain.Consensus().GetVirtualSelectedParent() - if err != nil { - return false, err - } - virtualSelectedParentTime := mstime.UnixMilliseconds(virtualSelectedParent.Header.TimeInMilliseconds) - return mstime.Now().Sub(virtualSelectedParentTime) > minDurationToRequestSelectedTips, nil -} - -func (f *FlowContext) requestSelectedTips() { - f.peersMutex.RLock() - defer f.peersMutex.RUnlock() - - for _, peer := range f.peers { - peer.RequestSelectedTipIfRequired() - } -} - -// FinishIBD finishes the current IBD flow and starts a new one if required. -func (f *FlowContext) FinishIBD() error { - f.ibdPeer = nil - - atomic.StoreUint32(&f.isInIBD, 0) - - return f.StartIBDIfRequired() -} - -// IBDPeer returns the currently active IBD peer. -// Returns nil if we aren't currently in IBD -func (f *FlowContext) IBDPeer() *peerpkg.Peer { - if !f.IsInIBD() { - return nil - } - return f.ibdPeer -} diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 6e70c68be..8200bbefe 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -52,7 +52,7 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*ext if err != nil { return nil, err } - if !orphanBlockParentInfo.Exists { + if !orphanBlockParentInfo.Exists || orphanBlockParentInfo.BlockStatus == externalapi.StatusHeaderOnly { log.Tracef("Cannot unorphan block %s. It's missing at "+ "least the following parent: %s", orphanHash, orphanBlockParentHash) diff --git a/app/protocol/flowcontext/transactions.go b/app/protocol/flowcontext/transactions.go index 491248a55..3e891773f 100644 --- a/app/protocol/flowcontext/transactions.go +++ b/app/protocol/flowcontext/transactions.go @@ -4,7 +4,7 @@ import ( "time" "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions" + "github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" ) @@ -54,9 +54,9 @@ func (f *FlowContext) txIDsToRebroadcast() []*externalapi.DomainTransactionID { return txIDs } -// SharedRequestedTransactions returns a *relaytransactions.SharedRequestedTransactions for sharing +// SharedRequestedTransactions returns a *transactionrelay.SharedRequestedTransactions for sharing // data about requested transactions between different peers. -func (f *FlowContext) SharedRequestedTransactions() *relaytransactions.SharedRequestedTransactions { +func (f *FlowContext) SharedRequestedTransactions() *transactionrelay.SharedRequestedTransactions { return f.sharedRequestedTransactions } diff --git a/app/protocol/flows/blockrelay/block_locator.go b/app/protocol/flows/blockrelay/block_locator.go new file mode 100644 index 000000000..1a03fe5b2 --- /dev/null +++ b/app/protocol/flows/blockrelay/block_locator.go @@ -0,0 +1,29 @@ +package blockrelay + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/common" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +func (flow *handleRelayInvsFlow) sendGetBlockLocator(lowHash *externalapi.DomainHash, + highHash *externalapi.DomainHash, limit uint32) error { + + msgGetBlockLocator := appmessage.NewMsgRequestBlockLocator(lowHash, highHash, limit) + return flow.outgoingRoute.Enqueue(msgGetBlockLocator) +} + +func (flow *handleRelayInvsFlow) receiveBlockLocator() (blockLocatorHashes []*externalapi.DomainHash, err error) { + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return nil, err + } + msgBlockLocator, ok := message.(*appmessage.MsgBlockLocator) + if !ok { + return nil, + protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdBlockLocator, message.Command()) + } + return msgBlockLocator.BlockLocatorHashes, nil +} diff --git a/app/protocol/flows/ibd/handle_ibd_block_requests.go b/app/protocol/flows/blockrelay/handle_ibd_block_requests.go similarity index 90% rename from app/protocol/flows/ibd/handle_ibd_block_requests.go rename to app/protocol/flows/blockrelay/handle_ibd_block_requests.go index 794b66a5f..e70e49eee 100644 --- a/app/protocol/flows/ibd/handle_ibd_block_requests.go +++ b/app/protocol/flows/blockrelay/handle_ibd_block_requests.go @@ -1,9 +1,10 @@ -package ibd +package blockrelay import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" ) @@ -30,7 +31,7 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute if err != nil { return err } - if !blockInfo.Exists { + if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly { return protocolerrors.Errorf(true, "block %s not found", hash) } block, err := context.Domain().Consensus().GetBlock(hash) diff --git a/app/protocol/flows/blockrelay/handle_relay_block_requests.go b/app/protocol/flows/blockrelay/handle_relay_block_requests.go index 910a2ff0b..d64cf47cc 100644 --- a/app/protocol/flows/blockrelay/handle_relay_block_requests.go +++ b/app/protocol/flows/blockrelay/handle_relay_block_requests.go @@ -5,6 +5,7 @@ import ( peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" ) @@ -31,7 +32,7 @@ func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute * if err != nil { return err } - if !blockInfo.Exists { + if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly { return protocolerrors.Errorf(true, "block %s not found", hash) } block, err := context.Domain().Consensus().GetBlock(hash) diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index ce27f9660..3d0546d02 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -9,24 +9,30 @@ 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/infrastructure/config" "github.com/kaspanet/kaspad/infrastructure/network/netadapter" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" - mathUtil "github.com/kaspanet/kaspad/util/math" "github.com/pkg/errors" ) +// orphanResolutionRange is the maximum amount of blockLocator hashes +// to search for known blocks. See isBlockInOrphanResolutionRange for +// further details +var orphanResolutionRange uint32 = 5 + // RelayInvsContext is the interface for the context needed for the HandleRelayInvs flow. type RelayInvsContext interface { Domain() domain.Domain + Config() *config.Config NetAdapter() *netadapter.NetAdapter OnNewBlock(block *externalapi.DomainBlock) error SharedRequestedBlocks() *SharedRequestedBlocks - StartIBDIfRequired() error - IsInIBD() bool Broadcast(message appmessage.Message) error AddOrphan(orphanBlock *externalapi.DomainBlock) IsOrphan(blockHash *externalapi.DomainHash) bool + IsIBDRunning() bool + TrySetIBDRunning() bool + UnsetIBDRunning() } type handleRelayInvsFlow struct { @@ -79,24 +85,45 @@ func (flow *handleRelayInvsFlow) start() error { continue } - err = flow.StartIBDIfRequired() - if err != nil { - return err - } - if flow.IsInIBD() { + // Block relay is disabled during IBD + if flow.IsIBDRunning() { log.Debugf("Got block %s while in IBD. continuing...", inv.Hash) - // Block relay is disabled during IBD continue } - requestQueue := newHashesQueueSet() - requestQueue.enqueueIfNotExists(inv.Hash) + log.Debugf("Requesting block %s", inv.Hash) + block, exists, err := flow.requestBlock(inv.Hash) + if err != nil { + return err + } + if exists { + log.Debugf("Aborting requesting block %s because it already exists", inv.Hash) + continue + } - for requestQueue.len() > 0 { - err := flow.requestBlocks(requestQueue) + log.Debugf("Processing block %s", inv.Hash) + missingParents, err := flow.processBlock(block) + if err != nil { + return err + } + if len(missingParents) > 0 { + log.Debugf("Block %s contains orphans: %s", inv.Hash, missingParents) + err := flow.processOrphan(block, missingParents) if err != nil { return err } + continue + } + + log.Debugf("Relaying block %s", inv.Hash) + err = flow.relayBlock(block) + if err != nil { + return err + } + log.Infof("Accepted block %s via relay", inv.Hash) + err = flow.OnNewBlock(block) + if err != nil { + return err } } } @@ -121,73 +148,34 @@ func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) return inv, nil } -func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) error { - onEnd := logger.LogAndMeasureExecutionTime(log, "handleRelayInvsFlow.requestBlocks") - defer onEnd() - - numHashesToRequest := mathUtil.MinInt(appmessage.MaxRequestRelayBlocksHashes, requestQueue.len()) - hashesToRequest := requestQueue.dequeue(numHashesToRequest) - - requestedBlocksSet := map[externalapi.DomainHash]struct{}{} - var filteredHashesToRequest []*externalapi.DomainHash - for _, hash := range hashesToRequest { - exists := flow.SharedRequestedBlocks().addIfNotExists(hash) - if exists { - continue - } - - // The block can become known from another peer in the process of orphan resolution - blockInfo, err := flow.Domain().Consensus().GetBlockInfo(hash) - if err != nil { - return err - } - if blockInfo.Exists { - continue - } - - requestedBlocksSet[*hash] = struct{}{} - filteredHashesToRequest = append(filteredHashesToRequest, hash) - } - - // Exit early if we've filtered out all the hashes - if len(filteredHashesToRequest) == 0 { - log.Debugf("requestBlocks - no hashes to request. Returning..") - return nil +func (flow *handleRelayInvsFlow) requestBlock(requestHash *externalapi.DomainHash) (*externalapi.DomainBlock, bool, error) { + exists := flow.SharedRequestedBlocks().addIfNotExists(requestHash) + if exists { + return nil, true, nil } // In case the function returns earlier than expected, we want to make sure flow.SharedRequestedBlocks() is // clean from any pending blocks. - defer flow.SharedRequestedBlocks().removeSet(requestedBlocksSet) + defer flow.SharedRequestedBlocks().remove(requestHash) - getRelayBlocksMsg := appmessage.NewMsgRequestRelayBlocks(filteredHashesToRequest) + getRelayBlocksMsg := appmessage.NewMsgRequestRelayBlocks([]*externalapi.DomainHash{requestHash}) err := flow.outgoingRoute.Enqueue(getRelayBlocksMsg) if err != nil { - return err + return nil, false, err } - for _, expectedHash := range filteredHashesToRequest { - log.Debugf("Waiting for block %s", expectedHash) - msgBlock, err := flow.readMsgBlock() - if err != nil { - return err - } - - block := appmessage.MsgBlockToDomainBlock(msgBlock) - blockHash := consensushashing.BlockHash(block) - log.Criticalf("got block %s", blockHash) - - if *blockHash != *expectedHash { - return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash) - } - - err = flow.processAndRelayBlock(requestQueue, requestedBlocksSet, block) - if err != nil { - return err - } - - flow.SharedRequestedBlocks().remove(blockHash) + msgBlock, err := flow.readMsgBlock() + if err != nil { + return nil, false, err } - return nil + + block := appmessage.MsgBlockToDomainBlock(msgBlock) + blockHash := consensushashing.BlockHash(block) + if *blockHash != *requestHash { + return nil, false, protocolerrors.Errorf(true, "got unrequested block %s", blockHash) + } + + return block, false, nil } // readMsgBlock returns the next msgBlock in msgChan, and populates invsQueue with any inv messages that meanwhile arrive. @@ -211,52 +199,92 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock, } } -func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueSet, requestedBlocksSet map[externalapi.DomainHash]struct{}, block *externalapi.DomainBlock) error { +func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) { blockHash := consensushashing.BlockHash(block) - log.Debugf("processAndRelayBlock start for block %s", blockHash) - defer log.Debugf("processAndRelayBlock end for block %s", blockHash) - err := flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { if !errors.As(err, &ruleerrors.RuleError{}) { - return errors.Wrapf(err, "failed to process block %s", blockHash) + return nil, errors.Wrapf(err, "failed to process block %s", blockHash) } missingParentsError := &ruleerrors.ErrMissingParents{} if errors.As(err, missingParentsError) { - // Add the orphan to the orphan pool - flow.AddOrphan(block) - - // Request the parents for the orphan block from the peer that sent it. - for _, missingAncestor := range missingParentsError.MissingParentHashes { - if _, ok := requestedBlocksSet[*missingAncestor]; ok { - log.Debugf("ancestor %s already exists in requestedBlocksSet", missingAncestor) - continue - } - requestQueue.enqueueIfNotExists(missingAncestor) - } - return nil + return missingParentsError.MissingParentHashes, nil } - log.Infof("Rejected block %s from %s: %s", blockHash, flow.peer, err) + log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err) - return protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash) + return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash) } - - err = flow.Broadcast(appmessage.NewMsgInvBlock(blockHash)) - if err != nil { - return err - } - - log.Debugf("Accepted block %s via relay", blockHash) - - err = flow.StartIBDIfRequired() - if err != nil { - return err - } - err = flow.OnNewBlock(block) - if err != nil { - return err - } - - return nil + return nil, nil +} + +func (flow *handleRelayInvsFlow) relayBlock(block *externalapi.DomainBlock) error { + blockHash := consensushashing.BlockHash(block) + return flow.Broadcast(appmessage.NewMsgInvBlock(blockHash)) +} + +func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock, missingParents []*externalapi.DomainHash) error { + blockHash := consensushashing.BlockHash(block) + + // Return if the block has been orphaned from elsewhere already + if flow.IsOrphan(blockHash) { + log.Debugf("Skipping orphan processing for block %s because it is already an orphan", blockHash) + return nil + } + + // Add the block to the orphan set if it's within orphan resolution range + isBlockInOrphanResolutionRange, err := flow.isBlockInOrphanResolutionRange(blockHash) + if err != nil { + return err + } + if isBlockInOrphanResolutionRange { + log.Debugf("Block %s is within orphan resolution range. "+ + "Adding it to the orphan set and requesting its missing parents", blockHash) + flow.addToOrphanSetAndRequestMissingParents(block, missingParents) + return nil + } + + // Start IBD unless we already are in IBD + log.Debugf("Block %s is out of orphan resolution range. "+ + "Attempting to start IBD against it.", blockHash) + return flow.runIBDIfNotRunning(blockHash) +} + +// isBlockInOrphanResolutionRange finds out whether the given blockHash should be +// retrieved via the unorphaning mechanism or via IBD. This method sends a +// getBlockLocator request to the peer with a limit of orphanResolutionRange. +// In the response, if we know none of the hashes, we should retrieve the given +// blockHash via IBD. Otherwise, via unorphaning. +func (flow *handleRelayInvsFlow) isBlockInOrphanResolutionRange(blockHash *externalapi.DomainHash) (bool, error) { + lowHash := flow.Config().ActiveNetParams.GenesisHash + err := flow.sendGetBlockLocator(lowHash, blockHash, orphanResolutionRange) + if err != nil { + return false, err + } + + blockLocatorHashes, err := flow.receiveBlockLocator() + if err != nil { + return false, err + } + for _, blockLocatorHash := range blockLocatorHashes { + blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockLocatorHash) + if err != nil { + return false, err + } + if blockInfo.Exists && blockInfo.BlockStatus != externalapi.StatusHeaderOnly { + return true, nil + } + } + return false, nil +} + +func (flow *handleRelayInvsFlow) addToOrphanSetAndRequestMissingParents( + block *externalapi.DomainBlock, missingParents []*externalapi.DomainHash) { + + flow.AddOrphan(block) + invMessages := make([]*appmessage.MsgInvRelayBlock, len(missingParents)) + for i, missingParent := range missingParents { + invMessages[i] = appmessage.NewMsgInvBlock(missingParent) + } + flow.invsQueue = append(invMessages, flow.invsQueue...) } diff --git a/app/protocol/flows/ibd/handle_request_block_locator.go b/app/protocol/flows/blockrelay/handle_request_block_locator.go similarity index 86% rename from app/protocol/flows/ibd/handle_request_block_locator.go rename to app/protocol/flows/blockrelay/handle_request_block_locator.go index acfccf4f5..9fe8970aa 100644 --- a/app/protocol/flows/ibd/handle_request_block_locator.go +++ b/app/protocol/flows/blockrelay/handle_request_block_locator.go @@ -1,4 +1,4 @@ -package ibd +package blockrelay import ( "github.com/kaspanet/kaspad/app/appmessage" @@ -32,13 +32,16 @@ func HandleRequestBlockLocator(context RequestBlockLocatorContext, incomingRoute func (flow *handleRequestBlockLocatorFlow) start() error { for { - lowHash, highHash, err := flow.receiveGetBlockLocator() + lowHash, highHash, limit, err := flow.receiveGetBlockLocator() if err != nil { return err } - locator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash) + locator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash, limit) if err != nil || len(locator) == 0 { + if err != nil { + log.Debugf("Received error from CreateBlockLocator: %s", err) + } return protocolerrors.Errorf(true, "couldn't build a block "+ "locator between blocks %s and %s", lowHash, highHash) } @@ -51,15 +54,15 @@ func (flow *handleRequestBlockLocatorFlow) start() error { } func (flow *handleRequestBlockLocatorFlow) receiveGetBlockLocator() (lowHash *externalapi.DomainHash, - highHash *externalapi.DomainHash, err error) { + highHash *externalapi.DomainHash, limit uint32, err error) { message, err := flow.incomingRoute.Dequeue() if err != nil { - return nil, nil, err + return nil, nil, 0, err } msgGetBlockLocator := message.(*appmessage.MsgRequestBlockLocator) - return msgGetBlockLocator.LowHash, msgGetBlockLocator.HighHash, nil + return msgGetBlockLocator.LowHash, msgGetBlockLocator.HighHash, msgGetBlockLocator.Limit, nil } func (flow *handleRequestBlockLocatorFlow) sendBlockLocator(locator externalapi.BlockLocator) error { diff --git a/app/protocol/flows/ibd/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go similarity index 99% rename from app/protocol/flows/ibd/handle_request_headers.go rename to app/protocol/flows/blockrelay/handle_request_headers.go index d8b6d29e3..6600461d8 100644 --- a/app/protocol/flows/ibd/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -1,4 +1,4 @@ -package ibd +package blockrelay import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" diff --git a/app/protocol/flows/ibd/handle_request_headers_test.go b/app/protocol/flows/blockrelay/handle_request_headers_test.go similarity index 95% rename from app/protocol/flows/ibd/handle_request_headers_test.go rename to app/protocol/flows/blockrelay/handle_request_headers_test.go index 63573cdc3..704cad76b 100644 --- a/app/protocol/flows/ibd/handle_request_headers_test.go +++ b/app/protocol/flows/blockrelay/handle_request_headers_test.go @@ -1,4 +1,4 @@ -package ibd +package blockrelay import ( "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" diff --git a/app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go similarity index 99% rename from app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go rename to app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go index 8298e7e52..659272e85 100644 --- a/app/protocol/flows/ibd/handle_request_ibd_root_utxo_set_and_block.go +++ b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go @@ -1,4 +1,4 @@ -package ibd +package blockrelay import ( "errors" diff --git a/app/protocol/flows/ibd/ibd.go b/app/protocol/flows/blockrelay/ibd.go similarity index 56% rename from app/protocol/flows/ibd/ibd.go rename to app/protocol/flows/blockrelay/ibd.go index 912698ac3..e5fc983c8 100644 --- a/app/protocol/flows/ibd/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -1,126 +1,255 @@ -package ibd +package blockrelay import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/common" - peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" - "github.com/kaspanet/kaspad/domain" "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/config" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" + "time" ) -// HandleIBDContext is the interface for the context needed for the HandleIBD flow. -type HandleIBDContext interface { - Domain() domain.Domain - Config() *config.Config - OnNewBlock(block *externalapi.DomainBlock) error - FinishIBD() error -} - -type handleIBDFlow struct { - HandleIBDContext - incomingRoute, outgoingRoute *router.Route - peer *peerpkg.Peer -} - -// HandleIBD waits for IBD start and handles it when IBD is triggered for this peer -func HandleIBD(context HandleIBDContext, incomingRoute *router.Route, outgoingRoute *router.Route, - peer *peerpkg.Peer) error { - - flow := &handleIBDFlow{ - HandleIBDContext: context, - incomingRoute: incomingRoute, - outgoingRoute: outgoingRoute, - peer: peer, +func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.DomainHash) error { + wasIBDNotRunning := flow.TrySetIBDRunning() + if !wasIBDNotRunning { + log.Debugf("IBD is already running") + return nil } - return flow.start() -} + defer flow.UnsetIBDRunning() -func (flow *handleIBDFlow) start() error { - for { - err := flow.runIBD() - if err != nil { - return err - } - } -} + log.Debugf("IBD started with peer %s and highHash %s", flow.peer, highHash) -func (flow *handleIBDFlow) runIBD() error { - flow.peer.WaitForIBDStart() - err := flow.ibdLoop() + // Fetch all the headers if we don't already have them + log.Debugf("Downloading headers up to %s", highHash) + err := flow.syncHeaders(highHash) if err != nil { - finishIBDErr := flow.FinishIBD() - if finishIBDErr != nil { - return finishIBDErr - } return err } - return flow.FinishIBD() -} + log.Debugf("Finished downloading headers up to %s", highHash) -func (flow *handleIBDFlow) ibdLoop() error { - for { - syncInfo, err := flow.Domain().Consensus().GetSyncInfo() + // Fetch the UTXO set if we don't already have it + log.Debugf("Downloading the IBD root UTXO set under highHash %s", highHash) + syncInfo, err := flow.Domain().Consensus().GetSyncInfo() + if err != nil { + return err + } + if syncInfo.State == externalapi.SyncStateAwaitingUTXOSet { + found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash) if err != nil { return err } - - switch syncInfo.State { - case externalapi.SyncStateHeadersFirst: - err := flow.syncHeaders() - if err != nil { - return err - } - case externalapi.SyncStateMissingUTXOSet: - found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash) - if err != nil { - return err - } - - if !found { - return nil - } - case externalapi.SyncStateMissingBlockBodies: - err := flow.syncMissingBlockBodies() - if err != nil { - return err - } - case externalapi.SyncStateRelay: + if !found { + log.Infof("Cannot download the IBD root UTXO set under highHash %s", highHash) return nil - default: - return errors.Errorf("unexpected state %s", syncInfo.State) } } -} + log.Debugf("Finished downloading the IBD root UTXO set under highHash %s", highHash) -func (flow *handleIBDFlow) syncHeaders() error { - peerSelectedTipHash := flow.peer.SelectedTipHash() - log.Debugf("Trying to find highest shared chain block with peer %s with selected tip %s", flow.peer, peerSelectedTipHash) - highestSharedBlockHash, err := flow.findHighestSharedBlockHash(peerSelectedTipHash) + // Fetch the block bodies + log.Debugf("Downloading block bodies up to %s", highHash) + err = flow.syncMissingBlockBodies(highHash) if err != nil { return err } + log.Debugf("Finished downloading block bodies up to %s", highHash) + return nil +} + +func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) error { + log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) + highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) + if err != nil { + return err + } log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) - return flow.downloadHeaders(highestSharedBlockHash, peerSelectedTipHash) + return flow.downloadHeaders(highestSharedBlockHash, highHash) } -func (flow *handleIBDFlow) syncMissingBlockBodies() error { - hashes, err := flow.Domain().Consensus().GetMissingBlockBodyHashes(flow.peer.SelectedTipHash()) +func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(highHash *externalapi.DomainHash) ( + lowHash *externalapi.DomainHash, err error) { + + lowHash = flow.Config().ActiveNetParams.GenesisHash + currentHighHash := highHash + + for { + err := flow.sendGetBlockLocator(lowHash, currentHighHash, 0) + if err != nil { + return nil, err + } + + blockLocatorHashes, err := flow.receiveBlockLocator() + if err != nil { + return nil, err + } + + // We check whether the locator's highest hash is in the local DAG. + // If it is, return it. If it isn't, we need to narrow our + // getBlockLocator request and try again. + locatorHighHash := blockLocatorHashes[0] + locatorHighHashInfo, err := flow.Domain().Consensus().GetBlockInfo(locatorHighHash) + if err != nil { + return nil, err + } + if locatorHighHashInfo.Exists { + return locatorHighHash, nil + } + + lowHash, currentHighHash, err = flow.Domain().Consensus().FindNextBlockLocatorBoundaries(blockLocatorHashes) + if err != nil { + return nil, err + } + } +} + +func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash, + highHash *externalapi.DomainHash) error { + + err := flow.sendRequestHeaders(highestSharedBlockHash, highHash) if err != nil { return err } - for offset := 0; offset < len(hashes); offset += appmessage.MaxRequestIBDBlocksHashes { + blocksReceived := 0 + for { + msgBlockHeader, doneIBD, err := flow.receiveHeader() + if err != nil { + return err + } + if doneIBD { + return nil + } + + err = flow.processHeader(msgBlockHeader) + if err != nil { + return err + } + + blocksReceived++ + if blocksReceived%ibdBatchSize == 0 { + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextHeaders()) + if err != nil { + return err + } + } + } +} + +func (flow *handleRelayInvsFlow) sendRequestHeaders(highestSharedBlockHash *externalapi.DomainHash, + peerSelectedTipHash *externalapi.DomainHash) error { + + msgGetBlockInvs := appmessage.NewMsgRequstHeaders(highestSharedBlockHash, peerSelectedTipHash) + return flow.outgoingRoute.Enqueue(msgGetBlockInvs) +} + +func (flow *handleRelayInvsFlow) receiveHeader() (msgIBDBlock *appmessage.MsgBlockHeader, doneIBD bool, err error) { + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return nil, false, err + } + switch message := message.(type) { + case *appmessage.MsgBlockHeader: + return message, false, nil + case *appmessage.MsgDoneHeaders: + return nil, true, nil + default: + return nil, false, + protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s or %s, got: %s", appmessage.CmdHeader, appmessage.CmdDoneHeaders, message.Command()) + } +} + +func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHeader) error { + header := appmessage.BlockHeaderToDomainBlockHeader(msgBlockHeader) + block := &externalapi.DomainBlock{ + Header: header, + Transactions: nil, + } + + blockHash := consensushashing.BlockHash(block) + blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockHash) + if err != nil { + return err + } + if blockInfo.Exists { + log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash) + return nil + } + 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) + } + log.Infof("Rejected block header %s from %s during IBD: %s", blockHash, flow.peer, err) + + return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) + } + return nil +} + +func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (bool, error) { + err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash)) + if err != nil { + return false, err + } + + utxoSet, block, found, err := flow.receiveIBDRootUTXOSetAndBlock() + if err != nil { + return false, err + } + + if !found { + 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) + if err != nil { + return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set") + } + + return true, nil +} + +func (flow *handleRelayInvsFlow) receiveIBDRootUTXOSetAndBlock() ([]byte, *externalapi.DomainBlock, bool, error) { + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return nil, nil, false, err + } + + switch message := message.(type) { + case *appmessage.MsgIBDRootUTXOSetAndBlock: + return message.UTXOSet, + appmessage.MsgBlockToDomainBlock(message.Block), true, nil + case *appmessage.MsgIBDRootNotFound: + return nil, nil, false, nil + default: + return nil, nil, false, + protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s or %s, got: %s", + appmessage.CmdIBDRootUTXOSetAndBlock, appmessage.CmdIBDRootNotFound, message.Command(), + ) + } +} + +func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.DomainHash) error { + hashes, err := flow.Domain().Consensus().GetMissingBlockBodyHashes(highHash) + if err != nil { + return err + } + + for offset := 0; offset < len(hashes); offset += ibdBatchSize { var hashesToRequest []*externalapi.DomainHash - if offset+appmessage.MaxRequestIBDBlocksHashes < len(hashes) { - hashesToRequest = hashes[offset : offset+appmessage.MaxRequestIBDBlocksHashes] + if offset+ibdBatchSize < len(hashes) { + hashesToRequest = hashes[offset : offset+ibdBatchSize] } else { hashesToRequest = hashes[offset:] } @@ -131,7 +260,7 @@ func (flow *handleIBDFlow) syncMissingBlockBodies() error { } for _, expectedHash := range hashesToRequest { - message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) if err != nil { return err } @@ -162,194 +291,17 @@ func (flow *handleIBDFlow) syncMissingBlockBodies() error { return nil } -func (flow *handleIBDFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (bool, error) { - err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash)) - if err != nil { - return false, err - } - - utxoSet, block, found, err := flow.receiveIBDRootUTXOSetAndBlock() - if err != nil { - return false, err - } - - if !found { - 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) - if err != nil { - return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set") - } - - return true, nil -} - -func (flow *handleIBDFlow) receiveIBDRootUTXOSetAndBlock() ([]byte, *externalapi.DomainBlock, bool, error) { - message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) - if err != nil { - return nil, nil, false, err - } - - switch message := message.(type) { - case *appmessage.MsgIBDRootUTXOSetAndBlock: - return message.UTXOSet, - appmessage.MsgBlockToDomainBlock(message.Block), true, nil - case *appmessage.MsgIBDRootNotFound: - return nil, nil, false, nil - default: - return nil, nil, false, - protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s or %s, got: %s", - appmessage.CmdIBDRootUTXOSetAndBlock, appmessage.CmdIBDRootNotFound, message.Command(), - ) - } -} - -func (flow *handleIBDFlow) findHighestSharedBlockHash(peerSelectedTipHash *externalapi.DomainHash) (lowHash *externalapi.DomainHash, - err error) { - - lowHash = flow.Config().ActiveNetParams.GenesisHash - highHash := peerSelectedTipHash - +// dequeueIncomingMessageAndSkipInvs is a convenience method to be used during +// IBD. Inv messages are expected to arrive at any given moment, but should be +// ignored while we're in IBD +func (flow *handleRelayInvsFlow) dequeueIncomingMessageAndSkipInvs(timeout time.Duration) (appmessage.Message, error) { for { - err := flow.sendGetBlockLocator(lowHash, highHash) + message, err := flow.incomingRoute.DequeueWithTimeout(timeout) if err != nil { return nil, err } - - blockLocatorHashes, err := flow.receiveBlockLocator() - if err != nil { - return nil, err - } - - // We check whether the locator's highest hash is in the local DAG. - // If it is, return it. If it isn't, we need to narrow our - // getBlockLocator request and try again. - locatorHighHash := blockLocatorHashes[0] - locatorHighHashInfo, err := flow.Domain().Consensus().GetBlockInfo(locatorHighHash) - if err != nil { - return nil, err - } - if locatorHighHashInfo.Exists { - return locatorHighHash, nil - } - - highHash, lowHash, err = flow.Domain().Consensus().FindNextBlockLocatorBoundaries(blockLocatorHashes) - if err != nil { - return nil, err + if _, ok := message.(*appmessage.MsgInvRelayBlock); !ok { + return message, nil } } } - -func (flow *handleIBDFlow) sendGetBlockLocator(lowHash *externalapi.DomainHash, highHash *externalapi.DomainHash) error { - - msgGetBlockLocator := appmessage.NewMsgRequestBlockLocator(highHash, lowHash) - return flow.outgoingRoute.Enqueue(msgGetBlockLocator) -} - -func (flow *handleIBDFlow) receiveBlockLocator() (blockLocatorHashes []*externalapi.DomainHash, err error) { - message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) - if err != nil { - return nil, err - } - msgBlockLocator, ok := message.(*appmessage.MsgBlockLocator) - if !ok { - return nil, - protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdBlockLocator, message.Command()) - } - return msgBlockLocator.BlockLocatorHashes, nil -} - -func (flow *handleIBDFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash, - peerSelectedTipHash *externalapi.DomainHash) error { - - err := flow.sendRequestHeaders(highestSharedBlockHash, peerSelectedTipHash) - if err != nil { - return err - } - - blocksReceived := 0 - for { - msgBlockHeader, doneIBD, err := flow.receiveHeader() - if err != nil { - return err - } - - if doneIBD { - return nil - } - - err = flow.processHeader(msgBlockHeader) - if err != nil { - return err - } - - blocksReceived++ - if blocksReceived%ibdBatchSize == 0 { - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextHeaders()) - if err != nil { - return err - } - } - } -} - -func (flow *handleIBDFlow) sendRequestHeaders(highestSharedBlockHash *externalapi.DomainHash, - peerSelectedTipHash *externalapi.DomainHash) error { - - msgGetBlockInvs := appmessage.NewMsgRequstHeaders(highestSharedBlockHash, peerSelectedTipHash) - return flow.outgoingRoute.Enqueue(msgGetBlockInvs) -} - -func (flow *handleIBDFlow) receiveHeader() (msgIBDBlock *appmessage.MsgBlockHeader, doneIBD bool, err error) { - message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) - if err != nil { - return nil, false, err - } - switch message := message.(type) { - case *appmessage.MsgBlockHeader: - return message, false, nil - case *appmessage.MsgDoneHeaders: - return nil, true, nil - default: - return nil, false, - protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s or %s, got: %s", appmessage.CmdHeader, appmessage.CmdDoneHeaders, message.Command()) - } -} - -func (flow *handleIBDFlow) processHeader(msgBlockHeader *appmessage.MsgBlockHeader) error { - header := appmessage.BlockHeaderToDomainBlockHeader(msgBlockHeader) - block := &externalapi.DomainBlock{ - Header: header, - Transactions: nil, - } - - blockHash := consensushashing.BlockHash(block) - blockInfo, err := flow.Domain().Consensus().GetBlockInfo(blockHash) - if err != nil { - return err - } - if blockInfo.Exists { - log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash) - return nil - } - 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) - } - log.Infof("Rejected block header %s from %s during IBD: %s", blockHash, flow.peer, err) - - return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) - } - return nil -} diff --git a/app/protocol/flows/handshake/handshake.go b/app/protocol/flows/handshake/handshake.go index 8f305d859..ff2ce6d3b 100644 --- a/app/protocol/flows/handshake/handshake.go +++ b/app/protocol/flows/handshake/handshake.go @@ -24,7 +24,6 @@ type HandleHandshakeContext interface { NetAdapter() *netadapter.NetAdapter Domain() domain.Domain AddressManager() *addressmanager.AddressManager - StartIBDIfRequired() error AddToPeers(peer *peerpkg.Peer) error HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error) } @@ -92,12 +91,6 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N if peerAddress != nil { context.AddressManager().AddAddresses(peerAddress) } - - err = context.StartIBDIfRequired() - if err != nil { - return nil, err - } - return peer, nil } diff --git a/app/protocol/flows/handshake/sendversion.go b/app/protocol/flows/handshake/sendversion.go index a7633fa8c..a98c8568d 100644 --- a/app/protocol/flows/handshake/sendversion.go +++ b/app/protocol/flows/handshake/sendversion.go @@ -4,7 +4,6 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/version" @@ -52,17 +51,11 @@ func (flow *sendVersionFlow) start() error { onEnd := logger.LogAndMeasureExecutionTime(log, "sendVersionFlow.start") defer onEnd() - virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent() - if err != nil { - return err - } - selectedTipHash := consensushashing.BlockHash(virtualSelectedParent) - subnetworkID := flow.Config().SubnetworkID - // Version message. localAddress := flow.AddressManager().BestLocalAddress(flow.peer.Connection().NetAddress()) + subnetworkID := flow.Config().SubnetworkID msg := appmessage.NewMsgVersion(localAddress, flow.NetAdapter().ID(), - flow.Config().ActiveNetParams.Name, selectedTipHash, subnetworkID) + flow.Config().ActiveNetParams.Name, subnetworkID) msg.AddUserAgent(userAgentName, userAgentVersion, flow.Config().UserAgentComments...) // Advertise the services flag @@ -74,7 +67,7 @@ func (flow *sendVersionFlow) start() error { // Advertise if inv messages for transactions are desired. msg.DisableRelayTx = flow.Config().BlocksOnly - err = flow.outgoingRoute.Enqueue(msg) + err := flow.outgoingRoute.Enqueue(msg) if err != nil { return err } diff --git a/app/protocol/flows/ibd/log.go b/app/protocol/flows/ibd/log.go deleted file mode 100644 index 99d53c983..000000000 --- a/app/protocol/flows/ibd/log.go +++ /dev/null @@ -1,9 +0,0 @@ -package ibd - -import ( - "github.com/kaspanet/kaspad/infrastructure/logger" - "github.com/kaspanet/kaspad/util/panics" -) - -var log, _ = logger.Get(logger.SubsystemTags.IBDS) -var spawn = panics.GoroutineWrapperFunc(log) diff --git a/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go b/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go deleted file mode 100644 index 2477b995f..000000000 --- a/app/protocol/flows/ibd/selectedtip/handle_request_selected_tip.go +++ /dev/null @@ -1,66 +0,0 @@ -package selectedtip - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/domain" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" - "github.com/pkg/errors" -) - -// HandleRequestSelectedTipContext is the interface for the context needed for the HandleRequestSelectedTip flow. -type HandleRequestSelectedTipContext interface { - Domain() domain.Domain -} - -type handleRequestSelectedTipFlow struct { - HandleRequestSelectedTipContext - incomingRoute, outgoingRoute *router.Route -} - -// HandleRequestSelectedTip handles getSelectedTip messages -func HandleRequestSelectedTip(context HandleRequestSelectedTipContext, incomingRoute *router.Route, outgoingRoute *router.Route) error { - flow := &handleRequestSelectedTipFlow{ - HandleRequestSelectedTipContext: context, - incomingRoute: incomingRoute, - outgoingRoute: outgoingRoute, - } - return flow.start() -} - -func (flow *handleRequestSelectedTipFlow) start() error { - for { - err := flow.receiveGetSelectedTip() - if err != nil { - return err - } - - err = flow.sendSelectedTipHash() - if err != nil { - return err - } - } -} - -func (flow *handleRequestSelectedTipFlow) receiveGetSelectedTip() error { - message, err := flow.incomingRoute.Dequeue() - if err != nil { - return err - } - _, ok := message.(*appmessage.MsgRequestSelectedTip) - if !ok { - return errors.Errorf("received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdRequestSelectedTip, message.Command()) - } - - return nil -} - -func (flow *handleRequestSelectedTipFlow) sendSelectedTipHash() error { - virtualSelectedParent, err := flow.Domain().Consensus().GetVirtualSelectedParent() - if err != nil { - return err - } - msgSelectedTip := appmessage.NewMsgSelectedTip(consensushashing.BlockHash(virtualSelectedParent)) - return flow.outgoingRoute.Enqueue(msgSelectedTip) -} diff --git a/app/protocol/flows/ibd/selectedtip/request_selected_tip.go b/app/protocol/flows/ibd/selectedtip/request_selected_tip.go deleted file mode 100644 index df79b8445..000000000 --- a/app/protocol/flows/ibd/selectedtip/request_selected_tip.go +++ /dev/null @@ -1,78 +0,0 @@ -package selectedtip - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/protocol/common" - peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" - "github.com/kaspanet/kaspad/domain" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" -) - -// RequestSelectedTipContext is the interface for the context needed for the RequestSelectedTip flow. -type RequestSelectedTipContext interface { - Domain() domain.Domain - StartIBDIfRequired() error -} - -type requestSelectedTipFlow struct { - RequestSelectedTipContext - incomingRoute, outgoingRoute *router.Route - peer *peerpkg.Peer -} - -// RequestSelectedTip waits for selected tip requests and handles them -func RequestSelectedTip(context RequestSelectedTipContext, incomingRoute *router.Route, - outgoingRoute *router.Route, peer *peerpkg.Peer) error { - - flow := &requestSelectedTipFlow{ - RequestSelectedTipContext: context, - incomingRoute: incomingRoute, - outgoingRoute: outgoingRoute, - peer: peer, - } - return flow.start() -} - -func (flow *requestSelectedTipFlow) start() error { - for { - err := flow.runSelectedTipRequest() - if err != nil { - return err - } - } -} - -func (flow *requestSelectedTipFlow) runSelectedTipRequest() error { - - flow.peer.WaitForSelectedTipRequests() - defer flow.peer.FinishRequestingSelectedTip() - - err := flow.requestSelectedTip() - if err != nil { - return err - } - - peerSelectedTipHash, err := flow.receiveSelectedTip() - if err != nil { - return err - } - - flow.peer.SetSelectedTipHash(peerSelectedTipHash) - return flow.StartIBDIfRequired() -} - -func (flow *requestSelectedTipFlow) requestSelectedTip() error { - msgGetSelectedTip := appmessage.NewMsgRequestSelectedTip() - return flow.outgoingRoute.Enqueue(msgGetSelectedTip) -} - -func (flow *requestSelectedTipFlow) receiveSelectedTip() (selectedTipHash *externalapi.DomainHash, err error) { - message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) - if err != nil { - return nil, err - } - msgSelectedTip := message.(*appmessage.MsgSelectedTip) - - return msgSelectedTip.SelectedTipHash, nil -} diff --git a/app/protocol/flows/relaytransactions/handle_relayed_transactions.go b/app/protocol/flows/transactionrelay/handle_relayed_transactions.go similarity index 99% rename from app/protocol/flows/relaytransactions/handle_relayed_transactions.go rename to app/protocol/flows/transactionrelay/handle_relayed_transactions.go index 9fc42aec3..26f9d6d2c 100644 --- a/app/protocol/flows/relaytransactions/handle_relayed_transactions.go +++ b/app/protocol/flows/transactionrelay/handle_relayed_transactions.go @@ -1,4 +1,4 @@ -package relaytransactions +package transactionrelay import ( "github.com/kaspanet/kaspad/app/appmessage" diff --git a/app/protocol/flows/relaytransactions/handle_requested_transactions.go b/app/protocol/flows/transactionrelay/handle_requested_transactions.go similarity index 98% rename from app/protocol/flows/relaytransactions/handle_requested_transactions.go rename to app/protocol/flows/transactionrelay/handle_requested_transactions.go index f006ecb67..3dd8b294b 100644 --- a/app/protocol/flows/relaytransactions/handle_requested_transactions.go +++ b/app/protocol/flows/transactionrelay/handle_requested_transactions.go @@ -1,4 +1,4 @@ -package relaytransactions +package transactionrelay import ( "github.com/kaspanet/kaspad/app/appmessage" diff --git a/app/protocol/flows/relaytransactions/shared_requested_transactions.go b/app/protocol/flows/transactionrelay/shared_requested_transactions.go similarity index 97% rename from app/protocol/flows/relaytransactions/shared_requested_transactions.go rename to app/protocol/flows/transactionrelay/shared_requested_transactions.go index 4831d2841..fd1d3b0f6 100644 --- a/app/protocol/flows/relaytransactions/shared_requested_transactions.go +++ b/app/protocol/flows/transactionrelay/shared_requested_transactions.go @@ -1,4 +1,4 @@ -package relaytransactions +package transactionrelay import ( "sync" diff --git a/app/protocol/manager.go b/app/protocol/manager.go index 17027f5b9..7ea7d0ceb 100644 --- a/app/protocol/manager.go +++ b/app/protocol/manager.go @@ -37,12 +37,6 @@ func (m *Manager) Peers() []*peerpkg.Peer { return m.context.Peers() } -// IBDPeer returns the currently active IBD peer. -// Returns nil if we aren't currently in IBD -func (m *Manager) IBDPeer() *peerpkg.Peer { - return m.context.IBDPeer() -} - // AddTransaction adds transaction to the mempool and propagates it. func (m *Manager) AddTransaction(tx *externalapi.DomainTransaction) error { return m.context.AddTransaction(tx) diff --git a/app/protocol/peer/peer.go b/app/protocol/peer/peer.go index 9438beac9..f27f20ace 100644 --- a/app/protocol/peer/peer.go +++ b/app/protocol/peer/peer.go @@ -2,7 +2,6 @@ package peer import ( "sync" - "sync/atomic" "time" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -22,9 +21,6 @@ const maxProtocolVersion = 1 type Peer struct { connection *netadapter.NetConnection - selectedTipHashMtx sync.RWMutex - selectedTipHash *externalapi.DomainHash - userAgent string services appmessage.ServiceFlag advertisedProtocolVerion uint32 // protocol version advertised by remote @@ -39,21 +35,13 @@ type Peer struct { lastPingNonce uint64 // The nonce of the last ping we sent lastPingTime time.Time // Time we sent last ping lastPingDuration time.Duration // Time for last ping to return - - isSelectedTipRequested uint32 - selectedTipRequestChan chan struct{} - lastSelectedTipRequest mstime.Time - - ibdStartChan chan struct{} } // New returns a new Peer func New(connection *netadapter.NetConnection) *Peer { return &Peer{ - connection: connection, - selectedTipRequestChan: make(chan struct{}), - ibdStartChan: make(chan struct{}), - connectionStarted: time.Now(), + connection: connection, + connectionStarted: time.Now(), } } @@ -62,20 +50,6 @@ func (p *Peer) Connection() *netadapter.NetConnection { return p.connection } -// SelectedTipHash returns the selected tip of the peer. -func (p *Peer) SelectedTipHash() *externalapi.DomainHash { - p.selectedTipHashMtx.RLock() - defer p.selectedTipHashMtx.RUnlock() - return p.selectedTipHash -} - -// SetSelectedTipHash sets the selected tip of the peer. -func (p *Peer) SetSelectedTipHash(hash *externalapi.DomainHash) { - p.selectedTipHashMtx.Lock() - defer p.selectedTipHashMtx.Unlock() - p.selectedTipHash = hash -} - // SubnetworkID returns the subnetwork the peer is associated with. // It is nil in full nodes. func (p *Peer) SubnetworkID() *externalapi.DomainSubnetworkID { @@ -128,7 +102,6 @@ func (p *Peer) UpdateFieldsFromMsgVersion(msg *appmessage.MsgVersion) { p.userAgent = msg.UserAgent p.disableRelayTx = msg.DisableRelayTx - p.selectedTipHash = msg.SelectedTipHash p.subnetworkID = msg.SubnetworkID p.timeOffset = mstime.Since(msg.Timestamp) @@ -156,46 +129,6 @@ func (p *Peer) String() string { return p.connection.String() } -// RequestSelectedTipIfRequired notifies the peer that requesting -// a selected tip is required. This triggers the selected tip -// request flow. -func (p *Peer) RequestSelectedTipIfRequired() { - if atomic.SwapUint32(&p.isSelectedTipRequested, 1) != 0 { - return - } - - const minGetSelectedTipInterval = time.Minute - if mstime.Since(p.lastSelectedTipRequest) < minGetSelectedTipInterval { - return - } - - p.lastSelectedTipRequest = mstime.Now() - p.selectedTipRequestChan <- struct{}{} -} - -// WaitForSelectedTipRequests blocks the current thread until -// a selected tip is requested from this peer -func (p *Peer) WaitForSelectedTipRequests() { - <-p.selectedTipRequestChan -} - -// FinishRequestingSelectedTip finishes requesting the selected -// tip from this peer -func (p *Peer) FinishRequestingSelectedTip() { - atomic.StoreUint32(&p.isSelectedTipRequested, 0) -} - -// StartIBD starts the IBD process for this peer -func (p *Peer) StartIBD() { - p.ibdStartChan <- struct{}{} -} - -// WaitForIBDStart blocks the current thread until -// IBD start is requested from this peer -func (p *Peer) WaitForIBDStart() { - <-p.ibdStartChan -} - // Address returns the address associated with this connection func (p *Peer) Address() string { return p.connection.Address() diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 28c0ee772..6d7527744 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -8,10 +8,8 @@ import ( "github.com/kaspanet/kaspad/app/protocol/flows/addressexchange" "github.com/kaspanet/kaspad/app/protocol/flows/blockrelay" "github.com/kaspanet/kaspad/app/protocol/flows/handshake" - "github.com/kaspanet/kaspad/app/protocol/flows/ibd" - "github.com/kaspanet/kaspad/app/protocol/flows/ibd/selectedtip" "github.com/kaspanet/kaspad/app/protocol/flows/ping" - "github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions" + "github.com/kaspanet/kaspad/app/protocol/flows/transactionrelay" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" @@ -107,7 +105,6 @@ func (m *Manager) registerFlows(router *routerpkg.Router, errChan chan error, is flows = m.registerAddressFlows(router, isStopping, errChan) flows = append(flows, m.registerBlockRelayFlows(router, isStopping, errChan)...) flows = append(flows, m.registerPingFlows(router, isStopping, errChan)...) - flows = append(flows, m.registerIBDFlows(router, isStopping, errChan)...) flows = append(flows, m.registerTransactionRelayFlow(router, isStopping, errChan)...) flows = append(flows, m.registerRejectsFlow(router, isStopping, errChan)...) @@ -136,7 +133,10 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * outgoingRoute := router.OutgoingRoute() return []*flow{ - m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{appmessage.CmdInvRelayBlock, appmessage.CmdBlock}, isStopping, errChan, + m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ + appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, + appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, + appmessage.CmdHeader}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) @@ -148,6 +148,34 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * return blockrelay.HandleRelayBlockRequests(m.context, incomingRoute, outgoingRoute, peer) }, ), + + m.registerFlow("HandleRequestBlockLocator", router, + []appmessage.MessageCommand{appmessage.CmdRequestBlockLocator}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.HandleRequestBlockLocator(m.context, incomingRoute, outgoingRoute) + }, + ), + + m.registerFlow("HandleRequestHeaders", router, + []appmessage.MessageCommand{appmessage.CmdRequestHeaders, appmessage.CmdRequestNextHeaders}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.HandleRequestHeaders(m.context, incomingRoute, outgoingRoute) + }, + ), + + m.registerFlow("HandleRequestIBDRootUTXOSetAndBlock", router, + []appmessage.MessageCommand{appmessage.CmdRequestIBDRootUTXOSetAndBlock}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.HandleRequestIBDRootUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute) + }, + ), + + m.registerFlow("HandleIBDBlockRequests", router, + []appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.HandleIBDBlockRequests(m.context, incomingRoute, outgoingRoute) + }, + ), } } @@ -169,62 +197,6 @@ func (m *Manager) registerPingFlows(router *routerpkg.Router, isStopping *uint32 } } -func (m *Manager) registerIBDFlows(router *routerpkg.Router, isStopping *uint32, errChan chan error) []*flow { - outgoingRoute := router.OutgoingRoute() - - return []*flow{ - m.registerFlow("HandleIBD", router, []appmessage.MessageCommand{appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, - appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, appmessage.CmdHeader}, - isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return ibd.HandleIBD(m.context, incomingRoute, outgoingRoute, peer) - }, - ), - - m.registerFlow("RequestSelectedTip", router, - []appmessage.MessageCommand{appmessage.CmdSelectedTip}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return selectedtip.RequestSelectedTip(m.context, incomingRoute, outgoingRoute, peer) - }, - ), - - m.registerFlow("HandleRequestSelectedTip", router, - []appmessage.MessageCommand{appmessage.CmdRequestSelectedTip}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return selectedtip.HandleRequestSelectedTip(m.context, incomingRoute, outgoingRoute) - }, - ), - - m.registerFlow("HandleRequestBlockLocator", router, - []appmessage.MessageCommand{appmessage.CmdRequestBlockLocator}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return ibd.HandleRequestBlockLocator(m.context, incomingRoute, outgoingRoute) - }, - ), - - m.registerFlow("HandleRequestHeaders", router, - []appmessage.MessageCommand{appmessage.CmdRequestHeaders, appmessage.CmdRequestNextHeaders}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return ibd.HandleRequestHeaders(m.context, incomingRoute, outgoingRoute) - }, - ), - - m.registerFlow("HandleRequestIBDRootUTXOSetAndBlock", router, - []appmessage.MessageCommand{appmessage.CmdRequestIBDRootUTXOSetAndBlock}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return ibd.HandleRequestIBDRootUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute) - }, - ), - - m.registerFlow("HandleIBDBlockRequests", router, - []appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return ibd.HandleIBDBlockRequests(m.context, incomingRoute, outgoingRoute) - }, - ), - } -} - func (m *Manager) registerTransactionRelayFlow(router *routerpkg.Router, isStopping *uint32, errChan chan error) []*flow { outgoingRoute := router.OutgoingRoute() @@ -232,13 +204,13 @@ func (m *Manager) registerTransactionRelayFlow(router *routerpkg.Router, isStopp m.registerFlow("HandleRelayedTransactions", router, []appmessage.MessageCommand{appmessage.CmdInvTransaction, appmessage.CmdTx, appmessage.CmdTransactionNotFound}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return relaytransactions.HandleRelayedTransactions(m.context, incomingRoute, outgoingRoute) + return transactionrelay.HandleRelayedTransactions(m.context, incomingRoute, outgoingRoute) }, ), m.registerFlow("HandleRequestTransactions", router, []appmessage.MessageCommand{appmessage.CmdRequestTransactions}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return relaytransactions.HandleRequestedTransactions(m.context, incomingRoute, outgoingRoute) + return transactionrelay.HandleRequestedTransactions(m.context, incomingRoute, outgoingRoute) }, ), } diff --git a/app/rpc/rpchandlers/get_connected_peer_info.go b/app/rpc/rpchandlers/get_connected_peer_info.go index 130a4a7d7..e16696e00 100644 --- a/app/rpc/rpchandlers/get_connected_peer_info.go +++ b/app/rpc/rpchandlers/get_connected_peer_info.go @@ -9,15 +9,12 @@ import ( // HandleGetConnectedPeerInfo handles the respectively named RPC command func HandleGetConnectedPeerInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { peers := context.ProtocolManager.Peers() - ibdPeer := context.ProtocolManager.IBDPeer() infos := make([]*appmessage.GetConnectedPeerInfoMessage, 0, len(peers)) for _, peer := range peers { info := &appmessage.GetConnectedPeerInfoMessage{ ID: peer.ID().String(), Address: peer.Address(), LastPingDuration: peer.LastPingDuration().Milliseconds(), - SelectedTipHash: peer.SelectedTipHash().String(), - IsSyncNode: peer == ibdPeer, IsOutbound: peer.IsOutbound(), TimeOffset: peer.TimeOffset().Milliseconds(), UserAgent: peer.UserAgent(), diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 6db33d9df..4d16e5a37 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -199,11 +199,11 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent()) } -func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { +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) + return s.syncManager.CreateBlockLocator(lowHash, highHash, limit) } func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index c37db65f0..4462d3974 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -248,7 +248,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ) blockProcessor := blockprocessor.New( - dagParams, + genesisHash, dbManager, consensusStateManager, pruningManager, diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 598316ac4..197878b14 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -15,7 +15,7 @@ type Consensus interface { GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error) SetPruningPointUTXOSet(serializedUTXOSet []byte) error GetVirtualSelectedParent() (*DomainBlock, error) - CreateBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) + CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error) GetSyncInfo() (*SyncInfo, error) } diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index 4bf942fa2..758581dc4 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -5,11 +5,10 @@ import "fmt" // Each of the following represent one of the possible sync // states of the consensus const ( - SyncStateRelay SyncState = iota - SyncStateMissingGenesis - SyncStateHeadersFirst - SyncStateMissingUTXOSet - SyncStateMissingBlockBodies + SyncStateSynced SyncState = iota + SyncStateAwaitingGenesis + SyncStateAwaitingUTXOSet + SyncStateAwaitingBlockBodies ) // SyncState represents the current sync state of the consensus @@ -17,16 +16,14 @@ type SyncState uint8 func (s SyncState) String() string { switch s { - case SyncStateRelay: - return "SyncStateRelay" - case SyncStateMissingGenesis: - return "SyncStateMissingGenesis" - case SyncStateHeadersFirst: - return "SyncStateHeadersFirst" - case SyncStateMissingUTXOSet: - return "SyncStateMissingUTXOSet" - case SyncStateMissingBlockBodies: - return "SyncStateMissingBlockBodies" + case SyncStateSynced: + return "SyncStateSynced" + case SyncStateAwaitingGenesis: + return "SyncStateAwaitingGenesis" + case SyncStateAwaitingUTXOSet: + return "SyncStateAwaitingUTXOSet" + case SyncStateAwaitingBlockBodies: + return "SyncStateAwaitingBlockBodies" } return fmt.Sprintf("", s) diff --git a/domain/consensus/model/interface_processes_syncmanager.go b/domain/consensus/model/interface_processes_syncmanager.go index f4a4a6ae1..cc0a32567 100644 --- a/domain/consensus/model/interface_processes_syncmanager.go +++ b/domain/consensus/model/interface_processes_syncmanager.go @@ -6,7 +6,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type SyncManager interface { GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) - CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, 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) diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index 805892a28..3acb04cf8 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -3,14 +3,13 @@ package blockprocessor import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/logger" ) // blockProcessor is responsible for processing incoming blocks // and creating blocks from the current state type blockProcessor struct { - dagParams *dagconfig.Params + genesisHash *externalapi.DomainHash databaseContext model.DBManager consensusStateManager model.ConsensusStateManager @@ -43,7 +42,7 @@ type blockProcessor struct { // New instantiates a new BlockProcessor func New( - dagParams *dagconfig.Params, + genesisHash *externalapi.DomainHash, databaseContext model.DBManager, consensusStateManager model.ConsensusStateManager, pruningManager model.PruningManager, @@ -71,7 +70,7 @@ func New( headerTipsStore model.HeaderTipsStore) model.BlockProcessor { return &blockProcessor{ - dagParams: dagParams, + genesisHash: genesisHash, databaseContext: databaseContext, pruningManager: pruningManager, blockValidator: blockValidator, diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index b8d8603ec..35f845469 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -11,88 +11,51 @@ import ( "github.com/pkg/errors" ) +type insertMode uint8 + +const ( + insertModeGenesis insertMode = iota + insertModeHeader + insertModeBlockBody + insertModeBlock +) + func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error { - hash := consensushashing.HeaderHash(block.Header) - log.Debugf("Validating block %s", hash) + blockHash := consensushashing.HeaderHash(block.Header) + log.Debugf("Validating block %s", blockHash) - syncInfo, err := bp.syncManager.GetSyncInfo() + insertMode, err := bp.validateAgainstSyncStateAndResolveInsertMode(block) if err != nil { return err } - if isHeaderOnlyBlock(block) && syncInfo.State != externalapi.SyncStateRelay { - syncInfo.State = externalapi.SyncStateHeadersFirst - } - - if syncInfo.State == externalapi.SyncStateMissingUTXOSet { - if isHeaderOnlyBlock(block) { - // Allow processing headers while in state SyncStateMissingUTXOSet - syncInfo.State = externalapi.SyncStateHeadersFirst - } else { - headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint() - if err != nil { - return err - } - - if *hash != *headerTipsPruningPoint { - return errors.Errorf("cannot insert blocks other than the header pruning point "+ - "while in %s mode", syncInfo.State) - } - - syncInfo.State = externalapi.SyncStateMissingBlockBodies - } - } - - if syncInfo.State == externalapi.SyncStateHeadersFirst && !isHeaderOnlyBlock(block) { - syncInfo.State = externalapi.SyncStateRelay - log.Warnf("block %s contains transactions while validating in header only mode", hash) - } - - if syncInfo.State == externalapi.SyncStateMissingBlockBodies { - headerTips, err := bp.headerTipsStore.Tips(bp.databaseContext) - if err != nil { - return err - } - selectedHeaderTip, err := bp.ghostdagManager.ChooseSelectedParent(headerTips...) - if err != nil { - return err - } - if *selectedHeaderTip == *hash { - syncInfo.State = externalapi.SyncStateRelay - } - } - - err = bp.checkBlockStatus(hash, syncInfo) + err = bp.checkBlockStatus(blockHash, insertMode) if err != nil { return err } - err = bp.validateBlock(block, syncInfo) + err = bp.validateBlock(block, insertMode) if err != nil { bp.discardAllChanges() return err } - hasHeader, err := bp.hasHeader(hash) + hasHeader, err := bp.hasHeader(blockHash) if err != nil { return err } if !hasHeader { - if syncInfo.State == externalapi.SyncStateMissingBlockBodies { - return errors.Wrapf(ruleerrors.ErrMissingBlockHeaderInIBD, "no block header is stored for block %s. "+ - "Every block we get during %s mode should have a pre-stored header", syncInfo.State, hash) - } - err = bp.reachabilityManager.AddBlock(hash) + err = bp.reachabilityManager.AddBlock(blockHash) if err != nil { return err } } - if syncInfo.State == externalapi.SyncStateHeadersFirst { - bp.blockStatusStore.Stage(hash, externalapi.StatusHeaderOnly) + if insertMode == insertModeHeader { + bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) } else { - bp.blockStatusStore.Stage(hash, externalapi.StatusUTXOPendingVerification) + bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) } // Block validations passed, save whatever DAG data was @@ -102,13 +65,8 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) return err } - hasTips, err := bp.headerTipsStore.HasTips(bp.databaseContext) - if err != nil { - return err - } - var oldHeadersSelectedTip *externalapi.DomainHash - if hasTips { + if insertMode != insertModeGenesis { var err error oldHeadersSelectedTip, err = bp.headerTipsManager.SelectedTip() if err != nil { @@ -116,14 +74,14 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } } - if syncInfo.State == externalapi.SyncStateHeadersFirst { - err = bp.headerTipsManager.AddHeaderTip(hash) + if insertMode == insertModeHeader { + err = bp.headerTipsManager.AddHeaderTip(blockHash) if err != nil { return err } - } else if syncInfo.State == externalapi.SyncStateRelay || syncInfo.State == externalapi.SyncStateMissingGenesis { + } else if insertMode == insertModeBlock || insertMode == insertModeGenesis { // Attempt to add the block to the virtual - err = bp.consensusStateManager.AddBlockToVirtual(hash) + err = bp.consensusStateManager.AddBlockToVirtual(blockHash) if err != nil { return err } @@ -135,14 +93,14 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) bp.headerTipsStore.Stage(tips) } - if syncInfo.State != externalapi.SyncStateMissingGenesis { - err = bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) + if insertMode != insertModeGenesis { + err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) if err != nil { return err } } - if syncInfo.State == externalapi.SyncStateRelay { + if insertMode == insertModeBlock { // Trigger pruning, which will check if the pruning point changed and delete the data if it did. err = bp.pruningManager.FindNextPruningPoint() if err != nil { @@ -155,7 +113,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) return err } - log.Debugf("Block %s validated and inserted", hash) + log.Debugf("Block %s validated and inserted", blockHash) var logClosureErr error log.Debugf("%s", logger.NewLogClosure(func() string { @@ -179,6 +137,62 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) 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 +} + +func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool { + return len(block.Transactions) == 0 +} + func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error { headersSelectedTip, err := bp.headerTipsManager.SelectedTip() if err != nil { @@ -192,16 +206,11 @@ func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *e return bp.reachabilityManager.UpdateReindexRoot(headersSelectedTip) } -func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool { - return len(block.Transactions) == 0 -} - -func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode *externalapi.SyncInfo) error { +func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode insertMode) error { exists, err := bp.blockStatusStore.Exists(bp.databaseContext, hash) if err != nil { return err } - if !exists { return nil } @@ -215,14 +224,20 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode *e return errors.Wrapf(ruleerrors.ErrKnownInvalid, "block %s is a known invalid block", hash) } - if mode.State == externalapi.SyncStateHeadersFirst || status != externalapi.StatusHeaderOnly { + isBlockBodyAfterBlockHeader := mode != insertModeHeader && status == externalapi.StatusHeaderOnly + if !isBlockBodyAfterBlockHeader { + return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash) + } + + isDuplicateHeader := mode == insertModeHeader && status == externalapi.StatusHeaderOnly + if isDuplicateHeader { return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash) } return nil } -func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *externalapi.SyncInfo) error { +func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode insertMode) error { blockHash := consensushashing.HeaderHash(block.Header) hasHeader, err := bp.hasHeader(blockHash) if err != nil { @@ -241,7 +256,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *ex return err } - err = bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash) + err = bp.validatePruningPointViolationAndProofOfWorkAndDifficulty(block, mode) if err != nil { return err } @@ -283,12 +298,19 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) return nil } -func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, mode *externalapi.SyncInfo) error { +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 { blockHash := consensushashing.BlockHash(block) - if mode.State != externalapi.SyncStateHeadersFirst { - bp.blockStore.Stage(blockHash, block) - + if mode != insertModeHeader { err := bp.blockValidator.ValidateBodyInIsolation(blockHash) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index a63b70f93..896818159 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -15,7 +15,7 @@ func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficult return err } - err = v.checkParentsExist(header) + err = v.checkParentsExist(blockHash, header) if err != nil { return err } @@ -104,17 +104,32 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) return nil } -func (v *blockValidator) checkParentsExist(header *externalapi.DomainBlockHeader) error { +func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error { missingParentHashes := []*externalapi.DomainHash{} + isFullBlock, err := v.blockStore.HasBlock(v.databaseContext, blockHash) + if err != nil { + return err + } + for _, parent := range header.ParentHashes { - exists, err := v.blockHeaderStore.HasBlockHeader(v.databaseContext, parent) + parentHeaderExists, err := v.blockHeaderStore.HasBlockHeader(v.databaseContext, parent) if err != nil { return err } - - if !exists { + if !parentHeaderExists { missingParentHashes = append(missingParentHashes, parent) + continue + } + + if isFullBlock { + parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent) + if err != nil { + return err + } + if parentStatus == externalapi.StatusHeaderOnly { + missingParentHashes = append(missingParentHashes, parent) + } } } diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index 1c430c8af..f939a7ec3 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -103,7 +103,6 @@ func isHashInSlice(hash *externalapi.DomainHash, hashes []*externalapi.DomainHas } func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, parentHashes []*externalapi.DomainHash) error { - hasRelations, err := dtm.blockRelationStore.Has(dtm.databaseContext, blockHash) if err != nil { return err @@ -128,7 +127,6 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par if *parentChild == *blockHash { parentRelations.Children = append(parentRelations.Children[:i], parentRelations.Children[i+1:]...) dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations) - break } } diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index 5561a4d4a..10d3023cc 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -13,7 +13,7 @@ type selectedChildIterator struct { current *externalapi.DomainHash } -func (s selectedChildIterator) Next() bool { +func (s *selectedChildIterator) Next() bool { children, err := s.dagTopologyManager.Children(s.current) if err != nil { panic(err) @@ -21,7 +21,7 @@ func (s selectedChildIterator) Next() bool { for _, child := range children { if *child == *model.VirtualBlockHash { - break + continue } isChildInSelectedParentChainOfHighHash, err := s.dagTopologyManager.IsInSelectedParentChainOf(child, s.highHash) diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 7cdf339c1..c0e1908ec 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -110,6 +110,7 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) } lowHash := headerTipsPruningPoint + foundHeaderOnlyBlock := false for selectedChildIterator.Next() { selectedChild := selectedChildIterator.Get() selectedChildStatus, err := sm.blockStatusStore.Get(sm.databaseContext, selectedChild) @@ -117,10 +118,17 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) return nil, err } - if selectedChildStatus != externalapi.StatusHeaderOnly { - lowHash = selectedChild + if selectedChildStatus == externalapi.StatusHeaderOnly { + foundHeaderOnlyBlock = true break } + lowHash = selectedChild + } + if !foundHeaderOnlyBlock { + // TODO: Once block children are fixed, this error + // should be returned instead of simply logged + log.Errorf("no header-only blocks between %s and %s", + lowHash, highHash) } hashesBetween, err := sm.antiPastHashesBetween(lowHash, highHash) @@ -128,44 +136,17 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) return nil, err } - lowHashAnticone, err := sm.dagTraversalManager.AnticoneFromContext(highHash, lowHash) - if err != nil { - return nil, err - } - - blockToRemoveFromHashesBetween := hashset.New() - for _, blockHash := range lowHashAnticone { - isHeaderOnlyBlock, err := sm.isHeaderOnlyBlock(blockHash) + missingBlocks := make([]*externalapi.DomainHash, 0, len(hashesBetween)) + for _, blockHash := range hashesBetween { + blockStatus, err := sm.blockStatusStore.Get(sm.databaseContext, blockHash) if err != nil { return nil, err } - - if !isHeaderOnlyBlock { - blockToRemoveFromHashesBetween.Add(blockHash) + if blockStatus == externalapi.StatusHeaderOnly { + missingBlocks = append(missingBlocks, blockHash) } } - missingBlocks := make([]*externalapi.DomainHash, 0, len(hashesBetween)-len(lowHashAnticone)) - for i, blockHash := range hashesBetween { - // If blockToRemoveFromHashesBetween is empty, no more blocks should be - // filtered, so we can copy the rest of hashesBetween into missingBlocks - if blockToRemoveFromHashesBetween.Length() == 0 { - missingBlocks = append(missingBlocks, hashesBetween[i:]...) - break - } - - if blockToRemoveFromHashesBetween.Contains(blockHash) { - blockToRemoveFromHashesBetween.Remove(blockHash) - continue - } - - missingBlocks = append(missingBlocks, blockHash) - } - - if blockToRemoveFromHashesBetween.Length() != 0 { - return nil, errors.Errorf("blockToRemoveFromHashesBetween.Length() is expected to be 0") - } - return missingBlocks, nil } diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index 770b22ee6..7bcc80e5a 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -7,7 +7,7 @@ import ( // createBlockLocator creates a block locator for the passed high and low hashes. // See the BlockLocator type comments for more details. -func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { +func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) { // We use the selected parent of the high block, so that the // block locator won't contain it. highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash) @@ -28,6 +28,11 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH for currentHash != nil { locator = append(locator, currentHash) + // Stop if we've reached the limit (if it's set) + if limit > 0 && uint32(len(locator)) == limit { + break + } + currentBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, currentHash) if err != nil { return nil, err @@ -36,7 +41,11 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH // Nothing more to add once the low node has been added. if currentBlockBlueScore <= lowBlockBlueScore { - if *currentHash != *lowHash { + isCurrentHashInSelectedParentChainOfLowHash, err := sm.dagTopologyManager.IsInSelectedParentChainOf(currentHash, lowHash) + if err != nil { + return nil, err + } + if !isCurrentHashInSelectedParentChainOfLowHash { return nil, errors.Errorf("highHash and lowHash are " + "not in the same selected parent chain.") } @@ -67,24 +76,24 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH // hash and the highest known block locator hash. This is used to create the // next block locator to find the highest shared known chain block with a // remote kaspad. -func (sm *syncManager) findNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { +func (sm *syncManager) findNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) ( + lowHash, highHash *externalapi.DomainHash, err error) { + // Find the most recent locator block hash in the DAG. In case none of // the hashes in the locator are in the DAG, fall back to the genesis block. - lowHash = sm.genesisBlockHash - nextBlockLocatorIndex := int64(len(blockLocator) - 1) - for i, hash := range blockLocator { + highestKnownHash := sm.genesisBlockHash + lowestUnknownHash := blockLocator[len(blockLocator)-1] + for _, hash := range blockLocator { exists, err := sm.blockStatusStore.Exists(sm.databaseContext, hash) if err != nil { return nil, nil, err } - if exists { - lowHash = hash - nextBlockLocatorIndex = int64(i) - 1 + if !exists { + lowestUnknownHash = hash + } else { + highestKnownHash = hash break } } - if nextBlockLocatorIndex < 0 { - return nil, lowHash, nil - } - return blockLocator[nextBlockLocatorIndex], lowHash, nil + return highestKnownHash, lowestUnknownHash, nil } diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 62a3f2a7b..2738f8e11 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -1,9 +1,7 @@ package syncmanager import ( - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util/mstime" ) // areHeaderTipsSyncedMaxTimeDifference is the number of blocks from @@ -18,7 +16,7 @@ func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { } var ibdRootUTXOBlockHash *externalapi.DomainHash - if syncState == externalapi.SyncStateMissingUTXOSet { + if syncState == externalapi.SyncStateAwaitingUTXOSet { ibdRootUTXOBlockHash, err = sm.consensusStateManager.HeaderTipsPruningPoint() if err != nil { return nil, err @@ -42,27 +40,19 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { return 0, err } if !hasTips { - return externalapi.SyncStateMissingGenesis, nil + return externalapi.SyncStateAwaitingGenesis, nil } headerVirtualSelectedParentHash, err := sm.headerVirtualSelectedParentHash() if err != nil { return 0, err } - isSynced, err := sm.areHeaderTipsSynced(headerVirtualSelectedParentHash) + headerVirtualSelectedParentStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerVirtualSelectedParentHash) if err != nil { return 0, err } - if !isSynced { - return externalapi.SyncStateHeadersFirst, nil - } - - virtualSelectedParentHash, err := sm.virtualSelectedParentHash() - if err != nil { - return 0, err - } - if *virtualSelectedParentHash == *headerVirtualSelectedParentHash { - return externalapi.SyncStateRelay, nil + if headerVirtualSelectedParentStatus != externalapi.StatusHeaderOnly { + return externalapi.SyncStateSynced, nil } // Once the header tips are synced, check the status of @@ -80,18 +70,10 @@ func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { return 0, err } if headerTipsPruningPointStatus != externalapi.StatusValid { - return externalapi.SyncStateMissingUTXOSet, nil + return externalapi.SyncStateAwaitingUTXOSet, nil } - return externalapi.SyncStateMissingBlockBodies, nil -} - -func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, error) { - virtualGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, model.VirtualBlockHash) - if err != nil { - return nil, err - } - return virtualGHOSTDAGData.SelectedParent(), nil + return externalapi.SyncStateAwaitingBlockBodies, nil } func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) { @@ -102,21 +84,6 @@ func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHas return sm.ghostdagManager.ChooseSelectedParent(headerTips...) } -func (sm *syncManager) areHeaderTipsSynced(headerVirtualSelectedParentHash *externalapi.DomainHash) (bool, error) { - virtualSelectedParentHeader, err := sm.blockHeaderStore.BlockHeader(sm.databaseContext, headerVirtualSelectedParentHash) - if err != nil { - return false, err - } - virtualSelectedParentTimeInMilliseconds := virtualSelectedParentHeader.TimeInMilliseconds - - nowInMilliseconds := mstime.Now().UnixMilliseconds() - timeDifference := nowInMilliseconds - virtualSelectedParentTimeInMilliseconds - - maxTimeDifference := areHeaderTipsSyncedMaxTimeDifference * sm.targetTimePerBlock - - return timeDifference <= maxTimeDifference, nil -} - func (sm *syncManager) getHeaderCount() uint64 { return sm.blockHeaderStore.Count() } diff --git a/domain/consensus/processes/syncmanager/syncmanager.go b/domain/consensus/processes/syncmanager/syncmanager.go index 5c206c408..c3edba5d6 100644 --- a/domain/consensus/processes/syncmanager/syncmanager.go +++ b/domain/consensus/processes/syncmanager/syncmanager.go @@ -78,11 +78,11 @@ func (sm *syncManager) IsBlockInHeaderPruningPointFuture(blockHash *externalapi. return sm.isBlockInHeaderPruningPointFuture(blockHash) } -func (sm *syncManager) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { +func (sm *syncManager) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "CreateBlockLocator") defer onEnd() - return sm.createBlockLocator(lowHash, highHash) + return sm.createBlockLocator(lowHash, highHash, limit) } func (sm *syncManager) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 720aef602..cf0c21798 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -228,8 +228,6 @@ var ( ErrSubnetworksDisabled = newRuleError("ErrSubnetworksDisabled") ErrBadPruningPointUTXOSet = newRuleError("ErrBadPruningPointUTXOSet") - ErrMissingBlockHeaderInIBD = newRuleError("ErrMissingBlockHeaderInIBD") - ErrMalformedUTXO = newRuleError("ErrMalformedUTXO") ErrWrongPruningPointHash = newRuleError("ErrWrongPruningPointHash") diff --git a/infrastructure/logger/logger.go b/infrastructure/logger/logger.go index 58ae577d7..8e2d952b3 100644 --- a/infrastructure/logger/logger.go +++ b/infrastructure/logger/logger.go @@ -52,7 +52,6 @@ var ( ntarLog = BackendLog.Logger("NTAR") dnssLog = BackendLog.Logger("DNSS") snvrLog = BackendLog.Logger("SNVR") - ibdsLog = BackendLog.Logger("IBDS") wsvcLog = BackendLog.Logger("WSVC") reacLog = BackendLog.Logger("REAC") ) @@ -85,7 +84,6 @@ var SubsystemTags = struct { NTAR, DNSS, SNVR, - IBDS, WSVC, REAC string }{ @@ -115,7 +113,6 @@ var SubsystemTags = struct { NTAR: "NTAR", DNSS: "DNSS", SNVR: "SNVR", - IBDS: "IBDS", WSVC: "WSVC", REAC: "REAC", } @@ -148,7 +145,6 @@ var subsystemLoggers = map[string]*Logger{ SubsystemTags.NTAR: ntarLog, SubsystemTags.DNSS: dnssLog, SubsystemTags.SNVR: snvrLog, - SubsystemTags.IBDS: ibdsLog, SubsystemTags.WSVC: wsvcLog, SubsystemTags.REAC: reacLog, } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 119e90c62..6f72f7a20 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -41,14 +41,12 @@ type KaspadMessage struct { // *KaspadMessage_RequestNextHeaders // *KaspadMessage_DoneHeaders // *KaspadMessage_RequestRelayBlocks - // *KaspadMessage_RequestSelectedTip // *KaspadMessage_RequestTransactions // *KaspadMessage_IbdBlock // *KaspadMessage_InvRelayBlock // *KaspadMessage_InvTransactions // *KaspadMessage_Ping // *KaspadMessage_Pong - // *KaspadMessage_SelectedTip // *KaspadMessage_Verack // *KaspadMessage_Version // *KaspadMessage_TransactionNotFound @@ -218,13 +216,6 @@ func (x *KaspadMessage) GetRequestRelayBlocks() *RequestRelayBlocksMessage { return nil } -func (x *KaspadMessage) GetRequestSelectedTip() *RequestSelectedTipMessage { - if x, ok := x.GetPayload().(*KaspadMessage_RequestSelectedTip); ok { - return x.RequestSelectedTip - } - return nil -} - func (x *KaspadMessage) GetRequestTransactions() *RequestTransactionsMessage { if x, ok := x.GetPayload().(*KaspadMessage_RequestTransactions); ok { return x.RequestTransactions @@ -267,13 +258,6 @@ func (x *KaspadMessage) GetPong() *PongMessage { return nil } -func (x *KaspadMessage) GetSelectedTip() *SelectedTipMessage { - if x, ok := x.GetPayload().(*KaspadMessage_SelectedTip); ok { - return x.SelectedTip - } - return nil -} - func (x *KaspadMessage) GetVerack() *VerackMessage { if x, ok := x.GetPayload().(*KaspadMessage_Verack); ok { return x.Verack @@ -717,10 +701,6 @@ type KaspadMessage_RequestRelayBlocks struct { RequestRelayBlocks *RequestRelayBlocksMessage `protobuf:"bytes,10,opt,name=requestRelayBlocks,proto3,oneof"` } -type KaspadMessage_RequestSelectedTip struct { - RequestSelectedTip *RequestSelectedTipMessage `protobuf:"bytes,11,opt,name=requestSelectedTip,proto3,oneof"` -} - type KaspadMessage_RequestTransactions struct { RequestTransactions *RequestTransactionsMessage `protobuf:"bytes,12,opt,name=requestTransactions,proto3,oneof"` } @@ -745,10 +725,6 @@ type KaspadMessage_Pong struct { Pong *PongMessage `protobuf:"bytes,17,opt,name=pong,proto3,oneof"` } -type KaspadMessage_SelectedTip struct { - SelectedTip *SelectedTipMessage `protobuf:"bytes,18,opt,name=selectedTip,proto3,oneof"` -} - type KaspadMessage_Verack struct { Verack *VerackMessage `protobuf:"bytes,19,opt,name=verack,proto3,oneof"` } @@ -997,8 +973,6 @@ func (*KaspadMessage_DoneHeaders) isKaspadMessage_Payload() {} func (*KaspadMessage_RequestRelayBlocks) isKaspadMessage_Payload() {} -func (*KaspadMessage_RequestSelectedTip) isKaspadMessage_Payload() {} - func (*KaspadMessage_RequestTransactions) isKaspadMessage_Payload() {} func (*KaspadMessage_IbdBlock) isKaspadMessage_Payload() {} @@ -1011,8 +985,6 @@ func (*KaspadMessage_Ping) isKaspadMessage_Payload() {} func (*KaspadMessage_Pong) isKaspadMessage_Payload() {} -func (*KaspadMessage_SelectedTip) isKaspadMessage_Payload() {} - func (*KaspadMessage_Verack) isKaspadMessage_Payload() {} func (*KaspadMessage_Version) isKaspadMessage_Payload() {} @@ -1885,8 +1857,9 @@ type RequestBlockLocatorMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - LowHash *Hash `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` - HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` + LowHash *Hash `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` + HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` + Limit uint32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` } func (x *RequestBlockLocatorMessage) Reset() { @@ -1935,6 +1908,13 @@ func (x *RequestBlockLocatorMessage) GetHighHash() *Hash { return nil } +func (x *RequestBlockLocatorMessage) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + // BlockLocatorMessage start type BlockLocatorMessage struct { state protoimpl.MessageState @@ -2165,45 +2145,6 @@ func (x *RequestRelayBlocksMessage) GetHashes() []*Hash { return nil } -// GetSelectedTipMessage start -type RequestSelectedTipMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *RequestSelectedTipMessage) Reset() { - *x = RequestSelectedTipMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestSelectedTipMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestSelectedTipMessage) ProtoMessage() {} - -func (x *RequestSelectedTipMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestSelectedTipMessage.ProtoReflect.Descriptor instead. -func (*RequestSelectedTipMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{19} -} - // RequestTransactionsMessage start type RequestTransactionsMessage struct { state protoimpl.MessageState @@ -2216,7 +2157,7 @@ type RequestTransactionsMessage struct { func (x *RequestTransactionsMessage) Reset() { *x = RequestTransactionsMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[20] + mi := &file_messages_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2229,7 +2170,7 @@ func (x *RequestTransactionsMessage) String() string { func (*RequestTransactionsMessage) ProtoMessage() {} func (x *RequestTransactionsMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[20] + mi := &file_messages_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2242,7 +2183,7 @@ func (x *RequestTransactionsMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestTransactionsMessage.ProtoReflect.Descriptor instead. func (*RequestTransactionsMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{20} + return file_messages_proto_rawDescGZIP(), []int{19} } func (x *RequestTransactionsMessage) GetIds() []*TransactionId { @@ -2264,7 +2205,7 @@ type TransactionNotFoundMessage struct { func (x *TransactionNotFoundMessage) Reset() { *x = TransactionNotFoundMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[21] + mi := &file_messages_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2277,7 +2218,7 @@ func (x *TransactionNotFoundMessage) String() string { func (*TransactionNotFoundMessage) ProtoMessage() {} func (x *TransactionNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[21] + mi := &file_messages_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2290,7 +2231,7 @@ func (x *TransactionNotFoundMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionNotFoundMessage.ProtoReflect.Descriptor instead. func (*TransactionNotFoundMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{21} + return file_messages_proto_rawDescGZIP(), []int{20} } func (x *TransactionNotFoundMessage) GetId() *TransactionId { @@ -2312,7 +2253,7 @@ type InvRelayBlockMessage struct { func (x *InvRelayBlockMessage) Reset() { *x = InvRelayBlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[22] + mi := &file_messages_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2325,7 +2266,7 @@ func (x *InvRelayBlockMessage) String() string { func (*InvRelayBlockMessage) ProtoMessage() {} func (x *InvRelayBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[22] + mi := &file_messages_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2338,7 +2279,7 @@ func (x *InvRelayBlockMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use InvRelayBlockMessage.ProtoReflect.Descriptor instead. func (*InvRelayBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{22} + return file_messages_proto_rawDescGZIP(), []int{21} } func (x *InvRelayBlockMessage) GetHash() *Hash { @@ -2360,7 +2301,7 @@ type InvTransactionsMessage struct { func (x *InvTransactionsMessage) Reset() { *x = InvTransactionsMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[23] + mi := &file_messages_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2373,7 +2314,7 @@ func (x *InvTransactionsMessage) String() string { func (*InvTransactionsMessage) ProtoMessage() {} func (x *InvTransactionsMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[23] + mi := &file_messages_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2386,7 +2327,7 @@ func (x *InvTransactionsMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use InvTransactionsMessage.ProtoReflect.Descriptor instead. func (*InvTransactionsMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{23} + return file_messages_proto_rawDescGZIP(), []int{22} } func (x *InvTransactionsMessage) GetIds() []*TransactionId { @@ -2408,7 +2349,7 @@ type PingMessage struct { func (x *PingMessage) Reset() { *x = PingMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[24] + mi := &file_messages_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2421,7 +2362,7 @@ func (x *PingMessage) String() string { func (*PingMessage) ProtoMessage() {} func (x *PingMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[24] + mi := &file_messages_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2434,7 +2375,7 @@ func (x *PingMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use PingMessage.ProtoReflect.Descriptor instead. func (*PingMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{24} + return file_messages_proto_rawDescGZIP(), []int{23} } func (x *PingMessage) GetNonce() uint64 { @@ -2456,7 +2397,7 @@ type PongMessage struct { func (x *PongMessage) Reset() { *x = PongMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[25] + mi := &file_messages_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2469,7 +2410,7 @@ func (x *PongMessage) String() string { func (*PongMessage) ProtoMessage() {} func (x *PongMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[25] + mi := &file_messages_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2482,7 +2423,7 @@ func (x *PongMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use PongMessage.ProtoReflect.Descriptor instead. func (*PongMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{25} + return file_messages_proto_rawDescGZIP(), []int{24} } func (x *PongMessage) GetNonce() uint64 { @@ -2492,54 +2433,6 @@ func (x *PongMessage) GetNonce() uint64 { return 0 } -// SelectedTipMessage start -type SelectedTipMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SelectedTipHash *Hash `protobuf:"bytes,1,opt,name=selectedTipHash,proto3" json:"selectedTipHash,omitempty"` -} - -func (x *SelectedTipMessage) Reset() { - *x = SelectedTipMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SelectedTipMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SelectedTipMessage) ProtoMessage() {} - -func (x *SelectedTipMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SelectedTipMessage.ProtoReflect.Descriptor instead. -func (*SelectedTipMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{26} -} - -func (x *SelectedTipMessage) GetSelectedTipHash() *Hash { - if x != nil { - return x.SelectedTipHash - } - return nil -} - // VerackMessage start type VerackMessage struct { state protoimpl.MessageState @@ -2550,7 +2443,7 @@ type VerackMessage struct { func (x *VerackMessage) Reset() { *x = VerackMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[27] + mi := &file_messages_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2563,7 +2456,7 @@ func (x *VerackMessage) String() string { func (*VerackMessage) ProtoMessage() {} func (x *VerackMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[27] + mi := &file_messages_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2576,7 +2469,7 @@ func (x *VerackMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use VerackMessage.ProtoReflect.Descriptor instead. func (*VerackMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{27} + return file_messages_proto_rawDescGZIP(), []int{25} } // VersionMessage start @@ -2591,7 +2484,6 @@ type VersionMessage struct { Address *NetAddress `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` Id []byte `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` UserAgent string `protobuf:"bytes,6,opt,name=userAgent,proto3" json:"userAgent,omitempty"` - SelectedTipHash *Hash `protobuf:"bytes,7,opt,name=selectedTipHash,proto3" json:"selectedTipHash,omitempty"` DisableRelayTx bool `protobuf:"varint,8,opt,name=disableRelayTx,proto3" json:"disableRelayTx,omitempty"` SubnetworkId *SubnetworkId `protobuf:"bytes,9,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` Network string `protobuf:"bytes,10,opt,name=network,proto3" json:"network,omitempty"` @@ -2600,7 +2492,7 @@ type VersionMessage struct { func (x *VersionMessage) Reset() { *x = VersionMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[28] + mi := &file_messages_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2613,7 +2505,7 @@ func (x *VersionMessage) String() string { func (*VersionMessage) ProtoMessage() {} func (x *VersionMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[28] + mi := &file_messages_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2626,7 +2518,7 @@ func (x *VersionMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionMessage.ProtoReflect.Descriptor instead. func (*VersionMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{28} + return file_messages_proto_rawDescGZIP(), []int{26} } func (x *VersionMessage) GetProtocolVersion() uint32 { @@ -2671,13 +2563,6 @@ func (x *VersionMessage) GetUserAgent() string { return "" } -func (x *VersionMessage) GetSelectedTipHash() *Hash { - if x != nil { - return x.SelectedTipHash - } - return nil -} - func (x *VersionMessage) GetDisableRelayTx() bool { if x != nil { return x.DisableRelayTx @@ -2711,7 +2596,7 @@ type RejectMessage struct { func (x *RejectMessage) Reset() { *x = RejectMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[29] + mi := &file_messages_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2724,7 +2609,7 @@ func (x *RejectMessage) String() string { func (*RejectMessage) ProtoMessage() {} func (x *RejectMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[29] + mi := &file_messages_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2737,7 +2622,7 @@ func (x *RejectMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectMessage.ProtoReflect.Descriptor instead. func (*RejectMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{29} + return file_messages_proto_rawDescGZIP(), []int{27} } func (x *RejectMessage) GetReason() string { @@ -2759,7 +2644,7 @@ type RequestIBDRootUTXOSetAndBlockMessage struct { func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { *x = RequestIBDRootUTXOSetAndBlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[30] + mi := &file_messages_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2772,7 +2657,7 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) String() string { func (*RequestIBDRootUTXOSetAndBlockMessage) ProtoMessage() {} func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[30] + mi := &file_messages_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2785,7 +2670,7 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Messa // Deprecated: Use RequestIBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. func (*RequestIBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{30} + return file_messages_proto_rawDescGZIP(), []int{28} } func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { @@ -2808,7 +2693,7 @@ type IBDRootUTXOSetAndBlockMessage struct { func (x *IBDRootUTXOSetAndBlockMessage) Reset() { *x = IBDRootUTXOSetAndBlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[31] + mi := &file_messages_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2821,7 +2706,7 @@ func (x *IBDRootUTXOSetAndBlockMessage) String() string { func (*IBDRootUTXOSetAndBlockMessage) ProtoMessage() {} func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[31] + mi := &file_messages_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2834,7 +2719,7 @@ func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. func (*IBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{31} + return file_messages_proto_rawDescGZIP(), []int{29} } func (x *IBDRootUTXOSetAndBlockMessage) GetUtxoSet() []byte { @@ -2863,7 +2748,7 @@ type RequestIBDBlocksMessage struct { func (x *RequestIBDBlocksMessage) Reset() { *x = RequestIBDBlocksMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2876,7 +2761,7 @@ func (x *RequestIBDBlocksMessage) String() string { func (*RequestIBDBlocksMessage) ProtoMessage() {} func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2889,7 +2774,7 @@ func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{32} + return file_messages_proto_rawDescGZIP(), []int{30} } func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { @@ -2909,7 +2794,7 @@ type IBDRootNotFoundMessage struct { func (x *IBDRootNotFoundMessage) Reset() { *x = IBDRootNotFoundMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2922,7 +2807,7 @@ func (x *IBDRootNotFoundMessage) String() string { func (*IBDRootNotFoundMessage) ProtoMessage() {} func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2935,7 +2820,7 @@ func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{33} + return file_messages_proto_rawDescGZIP(), []int{31} } type RPCError struct { @@ -2949,7 +2834,7 @@ type RPCError struct { func (x *RPCError) Reset() { *x = RPCError{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2962,7 +2847,7 @@ func (x *RPCError) String() string { func (*RPCError) ProtoMessage() {} func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2975,7 +2860,7 @@ func (x *RPCError) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCError.ProtoReflect.Descriptor instead. func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} + return file_messages_proto_rawDescGZIP(), []int{32} } func (x *RPCError) GetMessage() string { @@ -2994,7 +2879,7 @@ type GetCurrentNetworkRequestMessage struct { func (x *GetCurrentNetworkRequestMessage) Reset() { *x = GetCurrentNetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3007,7 +2892,7 @@ func (x *GetCurrentNetworkRequestMessage) String() string { func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3020,7 +2905,7 @@ func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{35} + return file_messages_proto_rawDescGZIP(), []int{33} } type GetCurrentNetworkResponseMessage struct { @@ -3035,7 +2920,7 @@ type GetCurrentNetworkResponseMessage struct { func (x *GetCurrentNetworkResponseMessage) Reset() { *x = GetCurrentNetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3048,7 +2933,7 @@ func (x *GetCurrentNetworkResponseMessage) String() string { func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3061,7 +2946,7 @@ func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} + return file_messages_proto_rawDescGZIP(), []int{34} } func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { @@ -3089,7 +2974,7 @@ type SubmitBlockRequestMessage struct { func (x *SubmitBlockRequestMessage) Reset() { *x = SubmitBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3102,7 +2987,7 @@ func (x *SubmitBlockRequestMessage) String() string { func (*SubmitBlockRequestMessage) ProtoMessage() {} func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3115,7 +3000,7 @@ func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} + return file_messages_proto_rawDescGZIP(), []int{35} } func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { @@ -3136,7 +3021,7 @@ type SubmitBlockResponseMessage struct { func (x *SubmitBlockResponseMessage) Reset() { *x = SubmitBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3149,7 +3034,7 @@ func (x *SubmitBlockResponseMessage) String() string { func (*SubmitBlockResponseMessage) ProtoMessage() {} func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3162,7 +3047,7 @@ func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} + return file_messages_proto_rawDescGZIP(), []int{36} } func (x *SubmitBlockResponseMessage) GetError() *RPCError { @@ -3183,7 +3068,7 @@ type GetBlockTemplateRequestMessage struct { func (x *GetBlockTemplateRequestMessage) Reset() { *x = GetBlockTemplateRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3196,7 +3081,7 @@ func (x *GetBlockTemplateRequestMessage) String() string { func (*GetBlockTemplateRequestMessage) ProtoMessage() {} func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3209,7 +3094,7 @@ func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} + return file_messages_proto_rawDescGZIP(), []int{37} } func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { @@ -3231,7 +3116,7 @@ type GetBlockTemplateResponseMessage struct { func (x *GetBlockTemplateResponseMessage) Reset() { *x = GetBlockTemplateResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3244,7 +3129,7 @@ func (x *GetBlockTemplateResponseMessage) String() string { func (*GetBlockTemplateResponseMessage) ProtoMessage() {} func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3257,7 +3142,7 @@ func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} + return file_messages_proto_rawDescGZIP(), []int{38} } func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { @@ -3283,7 +3168,7 @@ type NotifyBlockAddedRequestMessage struct { func (x *NotifyBlockAddedRequestMessage) Reset() { *x = NotifyBlockAddedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3296,7 +3181,7 @@ func (x *NotifyBlockAddedRequestMessage) String() string { func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3309,7 +3194,7 @@ func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} + return file_messages_proto_rawDescGZIP(), []int{39} } type NotifyBlockAddedResponseMessage struct { @@ -3323,7 +3208,7 @@ type NotifyBlockAddedResponseMessage struct { func (x *NotifyBlockAddedResponseMessage) Reset() { *x = NotifyBlockAddedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3336,7 +3221,7 @@ func (x *NotifyBlockAddedResponseMessage) String() string { func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3349,7 +3234,7 @@ func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} + return file_messages_proto_rawDescGZIP(), []int{40} } func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { @@ -3370,7 +3255,7 @@ type BlockAddedNotificationMessage struct { func (x *BlockAddedNotificationMessage) Reset() { *x = BlockAddedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3383,7 +3268,7 @@ func (x *BlockAddedNotificationMessage) String() string { func (*BlockAddedNotificationMessage) ProtoMessage() {} func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3396,7 +3281,7 @@ func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} + return file_messages_proto_rawDescGZIP(), []int{41} } func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { @@ -3415,7 +3300,7 @@ type GetPeerAddressesRequestMessage struct { func (x *GetPeerAddressesRequestMessage) Reset() { *x = GetPeerAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3428,7 +3313,7 @@ func (x *GetPeerAddressesRequestMessage) String() string { func (*GetPeerAddressesRequestMessage) ProtoMessage() {} func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3441,7 +3326,7 @@ func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} + return file_messages_proto_rawDescGZIP(), []int{42} } type GetPeerAddressesResponseMessage struct { @@ -3457,7 +3342,7 @@ type GetPeerAddressesResponseMessage struct { func (x *GetPeerAddressesResponseMessage) Reset() { *x = GetPeerAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3470,7 +3355,7 @@ func (x *GetPeerAddressesResponseMessage) String() string { func (*GetPeerAddressesResponseMessage) ProtoMessage() {} func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3483,7 +3368,7 @@ func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} + return file_messages_proto_rawDescGZIP(), []int{43} } func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { @@ -3518,7 +3403,7 @@ type GetPeerAddressesKnownAddressMessage struct { func (x *GetPeerAddressesKnownAddressMessage) Reset() { *x = GetPeerAddressesKnownAddressMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3531,7 +3416,7 @@ func (x *GetPeerAddressesKnownAddressMessage) String() string { func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3544,7 +3429,7 @@ func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} + return file_messages_proto_rawDescGZIP(), []int{44} } func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { @@ -3563,7 +3448,7 @@ type GetSelectedTipHashRequestMessage struct { func (x *GetSelectedTipHashRequestMessage) Reset() { *x = GetSelectedTipHashRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3576,7 +3461,7 @@ func (x *GetSelectedTipHashRequestMessage) String() string { func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3589,7 +3474,7 @@ func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} + return file_messages_proto_rawDescGZIP(), []int{45} } type GetSelectedTipHashResponseMessage struct { @@ -3604,7 +3489,7 @@ type GetSelectedTipHashResponseMessage struct { func (x *GetSelectedTipHashResponseMessage) Reset() { *x = GetSelectedTipHashResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3617,7 +3502,7 @@ func (x *GetSelectedTipHashResponseMessage) String() string { func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3630,7 +3515,7 @@ func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} + return file_messages_proto_rawDescGZIP(), []int{46} } func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { @@ -3660,7 +3545,7 @@ type MempoolEntry struct { func (x *MempoolEntry) Reset() { *x = MempoolEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3673,7 +3558,7 @@ func (x *MempoolEntry) String() string { func (*MempoolEntry) ProtoMessage() {} func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3686,7 +3571,7 @@ func (x *MempoolEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} + return file_messages_proto_rawDescGZIP(), []int{47} } func (x *MempoolEntry) GetFee() uint64 { @@ -3714,7 +3599,7 @@ type GetMempoolEntryRequestMessage struct { func (x *GetMempoolEntryRequestMessage) Reset() { *x = GetMempoolEntryRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3727,7 +3612,7 @@ func (x *GetMempoolEntryRequestMessage) String() string { func (*GetMempoolEntryRequestMessage) ProtoMessage() {} func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3740,7 +3625,7 @@ func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} + return file_messages_proto_rawDescGZIP(), []int{48} } func (x *GetMempoolEntryRequestMessage) GetTxId() string { @@ -3762,7 +3647,7 @@ type GetMempoolEntryResponseMessage struct { func (x *GetMempoolEntryResponseMessage) Reset() { *x = GetMempoolEntryResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3775,7 +3660,7 @@ func (x *GetMempoolEntryResponseMessage) String() string { func (*GetMempoolEntryResponseMessage) ProtoMessage() {} func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3788,7 +3673,7 @@ func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} + return file_messages_proto_rawDescGZIP(), []int{49} } func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { @@ -3814,7 +3699,7 @@ type GetMempoolEntriesRequestMessage struct { func (x *GetMempoolEntriesRequestMessage) Reset() { *x = GetMempoolEntriesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3827,7 +3712,7 @@ func (x *GetMempoolEntriesRequestMessage) String() string { func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3840,7 +3725,7 @@ func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} + return file_messages_proto_rawDescGZIP(), []int{50} } type GetMempoolEntriesResponseMessage struct { @@ -3855,7 +3740,7 @@ type GetMempoolEntriesResponseMessage struct { func (x *GetMempoolEntriesResponseMessage) Reset() { *x = GetMempoolEntriesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3868,7 +3753,7 @@ func (x *GetMempoolEntriesResponseMessage) String() string { func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3881,7 +3766,7 @@ func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} + return file_messages_proto_rawDescGZIP(), []int{51} } func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { @@ -3907,7 +3792,7 @@ type GetConnectedPeerInfoRequestMessage struct { func (x *GetConnectedPeerInfoRequestMessage) Reset() { *x = GetConnectedPeerInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3920,7 +3805,7 @@ func (x *GetConnectedPeerInfoRequestMessage) String() string { func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3933,7 +3818,7 @@ func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} + return file_messages_proto_rawDescGZIP(), []int{52} } type GetConnectedPeerInfoResponseMessage struct { @@ -3948,7 +3833,7 @@ type GetConnectedPeerInfoResponseMessage struct { func (x *GetConnectedPeerInfoResponseMessage) Reset() { *x = GetConnectedPeerInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3961,7 +3846,7 @@ func (x *GetConnectedPeerInfoResponseMessage) String() string { func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3974,7 +3859,7 @@ func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} + return file_messages_proto_rawDescGZIP(), []int{53} } func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { @@ -3999,8 +3884,6 @@ type GetConnectedPeerInfoMessage struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` LastPingDuration int64 `protobuf:"varint,3,opt,name=lastPingDuration,proto3" json:"lastPingDuration,omitempty"` - SelectedTipHash string `protobuf:"bytes,4,opt,name=selectedTipHash,proto3" json:"selectedTipHash,omitempty"` - IsSyncNode bool `protobuf:"varint,5,opt,name=isSyncNode,proto3" json:"isSyncNode,omitempty"` IsOutbound bool `protobuf:"varint,6,opt,name=isOutbound,proto3" json:"isOutbound,omitempty"` TimeOffset int64 `protobuf:"varint,7,opt,name=timeOffset,proto3" json:"timeOffset,omitempty"` UserAgent string `protobuf:"bytes,8,opt,name=userAgent,proto3" json:"userAgent,omitempty"` @@ -4011,7 +3894,7 @@ type GetConnectedPeerInfoMessage struct { func (x *GetConnectedPeerInfoMessage) Reset() { *x = GetConnectedPeerInfoMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4024,7 +3907,7 @@ func (x *GetConnectedPeerInfoMessage) String() string { func (*GetConnectedPeerInfoMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4037,7 +3920,7 @@ func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} + return file_messages_proto_rawDescGZIP(), []int{54} } func (x *GetConnectedPeerInfoMessage) GetId() string { @@ -4061,20 +3944,6 @@ func (x *GetConnectedPeerInfoMessage) GetLastPingDuration() int64 { return 0 } -func (x *GetConnectedPeerInfoMessage) GetSelectedTipHash() string { - if x != nil { - return x.SelectedTipHash - } - return "" -} - -func (x *GetConnectedPeerInfoMessage) GetIsSyncNode() bool { - if x != nil { - return x.IsSyncNode - } - return false -} - func (x *GetConnectedPeerInfoMessage) GetIsOutbound() bool { if x != nil { return x.IsOutbound @@ -4122,7 +3991,7 @@ type AddPeerRequestMessage struct { func (x *AddPeerRequestMessage) Reset() { *x = AddPeerRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4135,7 +4004,7 @@ func (x *AddPeerRequestMessage) String() string { func (*AddPeerRequestMessage) ProtoMessage() {} func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4148,7 +4017,7 @@ func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} + return file_messages_proto_rawDescGZIP(), []int{55} } func (x *AddPeerRequestMessage) GetAddress() string { @@ -4176,7 +4045,7 @@ type AddPeerResponseMessage struct { func (x *AddPeerResponseMessage) Reset() { *x = AddPeerResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4189,7 +4058,7 @@ func (x *AddPeerResponseMessage) String() string { func (*AddPeerResponseMessage) ProtoMessage() {} func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4202,7 +4071,7 @@ func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} + return file_messages_proto_rawDescGZIP(), []int{56} } func (x *AddPeerResponseMessage) GetError() *RPCError { @@ -4223,7 +4092,7 @@ type SubmitTransactionRequestMessage struct { func (x *SubmitTransactionRequestMessage) Reset() { *x = SubmitTransactionRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4236,7 +4105,7 @@ func (x *SubmitTransactionRequestMessage) String() string { func (*SubmitTransactionRequestMessage) ProtoMessage() {} func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4249,7 +4118,7 @@ func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} + return file_messages_proto_rawDescGZIP(), []int{57} } func (x *SubmitTransactionRequestMessage) GetTransaction() *TransactionMessage { @@ -4271,7 +4140,7 @@ type SubmitTransactionResponseMessage struct { func (x *SubmitTransactionResponseMessage) Reset() { *x = SubmitTransactionResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4284,7 +4153,7 @@ func (x *SubmitTransactionResponseMessage) String() string { func (*SubmitTransactionResponseMessage) ProtoMessage() {} func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4297,7 +4166,7 @@ func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} + return file_messages_proto_rawDescGZIP(), []int{58} } func (x *SubmitTransactionResponseMessage) GetTxId() string { @@ -4323,7 +4192,7 @@ type NotifyChainChangedRequestMessage struct { func (x *NotifyChainChangedRequestMessage) Reset() { *x = NotifyChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4336,7 +4205,7 @@ func (x *NotifyChainChangedRequestMessage) String() string { func (*NotifyChainChangedRequestMessage) ProtoMessage() {} func (x *NotifyChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4349,7 +4218,7 @@ func (x *NotifyChainChangedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyChainChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} + return file_messages_proto_rawDescGZIP(), []int{59} } type NotifyChainChangedResponseMessage struct { @@ -4363,7 +4232,7 @@ type NotifyChainChangedResponseMessage struct { func (x *NotifyChainChangedResponseMessage) Reset() { *x = NotifyChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4376,7 +4245,7 @@ func (x *NotifyChainChangedResponseMessage) String() string { func (*NotifyChainChangedResponseMessage) ProtoMessage() {} func (x *NotifyChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4389,7 +4258,7 @@ func (x *NotifyChainChangedResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use NotifyChainChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} + return file_messages_proto_rawDescGZIP(), []int{60} } func (x *NotifyChainChangedResponseMessage) GetError() *RPCError { @@ -4411,7 +4280,7 @@ type ChainChangedNotificationMessage struct { func (x *ChainChangedNotificationMessage) Reset() { *x = ChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4424,7 +4293,7 @@ func (x *ChainChangedNotificationMessage) String() string { func (*ChainChangedNotificationMessage) ProtoMessage() {} func (x *ChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4437,7 +4306,7 @@ func (x *ChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*ChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} + return file_messages_proto_rawDescGZIP(), []int{61} } func (x *ChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { @@ -4466,7 +4335,7 @@ type ChainBlock struct { func (x *ChainBlock) Reset() { *x = ChainBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4479,7 +4348,7 @@ func (x *ChainBlock) String() string { func (*ChainBlock) ProtoMessage() {} func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4492,7 +4361,7 @@ func (x *ChainBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} + return file_messages_proto_rawDescGZIP(), []int{62} } func (x *ChainBlock) GetHash() string { @@ -4521,7 +4390,7 @@ type AcceptedBlock struct { func (x *AcceptedBlock) Reset() { *x = AcceptedBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4534,7 +4403,7 @@ func (x *AcceptedBlock) String() string { func (*AcceptedBlock) ProtoMessage() {} func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4547,7 +4416,7 @@ func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} + return file_messages_proto_rawDescGZIP(), []int{63} } func (x *AcceptedBlock) GetHash() string { @@ -4577,7 +4446,7 @@ type GetBlockRequestMessage struct { func (x *GetBlockRequestMessage) Reset() { *x = GetBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4590,7 +4459,7 @@ func (x *GetBlockRequestMessage) String() string { func (*GetBlockRequestMessage) ProtoMessage() {} func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4603,7 +4472,7 @@ func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} + return file_messages_proto_rawDescGZIP(), []int{64} } func (x *GetBlockRequestMessage) GetHash() string { @@ -4640,7 +4509,7 @@ type GetBlockResponseMessage struct { func (x *GetBlockResponseMessage) Reset() { *x = GetBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4653,7 +4522,7 @@ func (x *GetBlockResponseMessage) String() string { func (*GetBlockResponseMessage) ProtoMessage() {} func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4666,7 +4535,7 @@ func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} + return file_messages_proto_rawDescGZIP(), []int{65} } func (x *GetBlockResponseMessage) GetBlockHash() string { @@ -4714,7 +4583,7 @@ type BlockVerboseData struct { func (x *BlockVerboseData) Reset() { *x = BlockVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4727,7 +4596,7 @@ func (x *BlockVerboseData) String() string { func (*BlockVerboseData) ProtoMessage() {} func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4740,7 +4609,7 @@ func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} + return file_messages_proto_rawDescGZIP(), []int{66} } func (x *BlockVerboseData) GetHash() string { @@ -4865,7 +4734,7 @@ type TransactionVerboseData struct { func (x *TransactionVerboseData) Reset() { *x = TransactionVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4878,7 +4747,7 @@ func (x *TransactionVerboseData) String() string { func (*TransactionVerboseData) ProtoMessage() {} func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4891,7 +4760,7 @@ func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} + return file_messages_proto_rawDescGZIP(), []int{67} } func (x *TransactionVerboseData) GetTxId() string { @@ -5006,7 +4875,7 @@ type TransactionVerboseInput struct { func (x *TransactionVerboseInput) Reset() { *x = TransactionVerboseInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5019,7 +4888,7 @@ func (x *TransactionVerboseInput) String() string { func (*TransactionVerboseInput) ProtoMessage() {} func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5032,7 +4901,7 @@ func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} + return file_messages_proto_rawDescGZIP(), []int{68} } func (x *TransactionVerboseInput) GetTxId() string { @@ -5075,7 +4944,7 @@ type ScriptSig struct { func (x *ScriptSig) Reset() { *x = ScriptSig{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5088,7 +4957,7 @@ func (x *ScriptSig) String() string { func (*ScriptSig) ProtoMessage() {} func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5101,7 +4970,7 @@ func (x *ScriptSig) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} + return file_messages_proto_rawDescGZIP(), []int{69} } func (x *ScriptSig) GetAsm() string { @@ -5131,7 +5000,7 @@ type TransactionVerboseOutput struct { func (x *TransactionVerboseOutput) Reset() { *x = TransactionVerboseOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5144,7 +5013,7 @@ func (x *TransactionVerboseOutput) String() string { func (*TransactionVerboseOutput) ProtoMessage() {} func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5157,7 +5026,7 @@ func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} + return file_messages_proto_rawDescGZIP(), []int{70} } func (x *TransactionVerboseOutput) GetValue() uint64 { @@ -5195,7 +5064,7 @@ type ScriptPubKeyResult struct { func (x *ScriptPubKeyResult) Reset() { *x = ScriptPubKeyResult{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5208,7 +5077,7 @@ func (x *ScriptPubKeyResult) String() string { func (*ScriptPubKeyResult) ProtoMessage() {} func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5221,7 +5090,7 @@ func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptPubKeyResult.ProtoReflect.Descriptor instead. func (*ScriptPubKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} + return file_messages_proto_rawDescGZIP(), []int{71} } func (x *ScriptPubKeyResult) GetAsm() string { @@ -5263,7 +5132,7 @@ type GetSubnetworkRequestMessage struct { func (x *GetSubnetworkRequestMessage) Reset() { *x = GetSubnetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5276,7 +5145,7 @@ func (x *GetSubnetworkRequestMessage) String() string { func (*GetSubnetworkRequestMessage) ProtoMessage() {} func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5289,7 +5158,7 @@ func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} + return file_messages_proto_rawDescGZIP(), []int{72} } func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { @@ -5311,7 +5180,7 @@ type GetSubnetworkResponseMessage struct { func (x *GetSubnetworkResponseMessage) Reset() { *x = GetSubnetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5324,7 +5193,7 @@ func (x *GetSubnetworkResponseMessage) String() string { func (*GetSubnetworkResponseMessage) ProtoMessage() {} func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5337,7 +5206,7 @@ func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} + return file_messages_proto_rawDescGZIP(), []int{73} } func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { @@ -5366,7 +5235,7 @@ type GetChainFromBlockRequestMessage struct { func (x *GetChainFromBlockRequestMessage) Reset() { *x = GetChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5379,7 +5248,7 @@ func (x *GetChainFromBlockRequestMessage) String() string { func (*GetChainFromBlockRequestMessage) ProtoMessage() {} func (x *GetChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5392,7 +5261,7 @@ func (x *GetChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} + return file_messages_proto_rawDescGZIP(), []int{74} } func (x *GetChainFromBlockRequestMessage) GetStartHash() string { @@ -5423,7 +5292,7 @@ type GetChainFromBlockResponseMessage struct { func (x *GetChainFromBlockResponseMessage) Reset() { *x = GetChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5436,7 +5305,7 @@ func (x *GetChainFromBlockResponseMessage) String() string { func (*GetChainFromBlockResponseMessage) ProtoMessage() {} func (x *GetChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5449,7 +5318,7 @@ func (x *GetChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} + return file_messages_proto_rawDescGZIP(), []int{75} } func (x *GetChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { @@ -5494,7 +5363,7 @@ type GetBlocksRequestMessage struct { func (x *GetBlocksRequestMessage) Reset() { *x = GetBlocksRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5507,7 +5376,7 @@ func (x *GetBlocksRequestMessage) String() string { func (*GetBlocksRequestMessage) ProtoMessage() {} func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5520,7 +5389,7 @@ func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} + return file_messages_proto_rawDescGZIP(), []int{76} } func (x *GetBlocksRequestMessage) GetLowHash() string { @@ -5565,7 +5434,7 @@ type GetBlocksResponseMessage struct { func (x *GetBlocksResponseMessage) Reset() { *x = GetBlocksResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5578,7 +5447,7 @@ func (x *GetBlocksResponseMessage) String() string { func (*GetBlocksResponseMessage) ProtoMessage() {} func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5591,7 +5460,7 @@ func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} + return file_messages_proto_rawDescGZIP(), []int{77} } func (x *GetBlocksResponseMessage) GetBlockHashes() []string { @@ -5631,7 +5500,7 @@ type GetBlockCountRequestMessage struct { func (x *GetBlockCountRequestMessage) Reset() { *x = GetBlockCountRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5644,7 +5513,7 @@ func (x *GetBlockCountRequestMessage) String() string { func (*GetBlockCountRequestMessage) ProtoMessage() {} func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5657,7 +5526,7 @@ func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} + return file_messages_proto_rawDescGZIP(), []int{78} } type GetBlockCountResponseMessage struct { @@ -5672,7 +5541,7 @@ type GetBlockCountResponseMessage struct { func (x *GetBlockCountResponseMessage) Reset() { *x = GetBlockCountResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5685,7 +5554,7 @@ func (x *GetBlockCountResponseMessage) String() string { func (*GetBlockCountResponseMessage) ProtoMessage() {} func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5698,7 +5567,7 @@ func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} + return file_messages_proto_rawDescGZIP(), []int{79} } func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { @@ -5724,7 +5593,7 @@ type GetBlockDagInfoRequestMessage struct { func (x *GetBlockDagInfoRequestMessage) Reset() { *x = GetBlockDagInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5737,7 +5606,7 @@ func (x *GetBlockDagInfoRequestMessage) String() string { func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5750,7 +5619,7 @@ func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} + return file_messages_proto_rawDescGZIP(), []int{80} } type GetBlockDagInfoResponseMessage struct { @@ -5770,7 +5639,7 @@ type GetBlockDagInfoResponseMessage struct { func (x *GetBlockDagInfoResponseMessage) Reset() { *x = GetBlockDagInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5783,7 +5652,7 @@ func (x *GetBlockDagInfoResponseMessage) String() string { func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5796,7 +5665,7 @@ func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} + return file_messages_proto_rawDescGZIP(), []int{81} } func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { @@ -5859,7 +5728,7 @@ type ResolveFinalityConflictRequestMessage struct { func (x *ResolveFinalityConflictRequestMessage) Reset() { *x = ResolveFinalityConflictRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5872,7 +5741,7 @@ func (x *ResolveFinalityConflictRequestMessage) String() string { func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5885,7 +5754,7 @@ func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} + return file_messages_proto_rawDescGZIP(), []int{82} } func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { @@ -5906,7 +5775,7 @@ type ResolveFinalityConflictResponseMessage struct { func (x *ResolveFinalityConflictResponseMessage) Reset() { *x = ResolveFinalityConflictResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5919,7 +5788,7 @@ func (x *ResolveFinalityConflictResponseMessage) String() string { func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5932,7 +5801,7 @@ func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} + return file_messages_proto_rawDescGZIP(), []int{83} } func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { @@ -5951,7 +5820,7 @@ type NotifyFinalityConflictsRequestMessage struct { func (x *NotifyFinalityConflictsRequestMessage) Reset() { *x = NotifyFinalityConflictsRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5964,7 +5833,7 @@ func (x *NotifyFinalityConflictsRequestMessage) String() string { func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5977,7 +5846,7 @@ func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} + return file_messages_proto_rawDescGZIP(), []int{84} } type NotifyFinalityConflictsResponseMessage struct { @@ -5991,7 +5860,7 @@ type NotifyFinalityConflictsResponseMessage struct { func (x *NotifyFinalityConflictsResponseMessage) Reset() { *x = NotifyFinalityConflictsResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6004,7 +5873,7 @@ func (x *NotifyFinalityConflictsResponseMessage) String() string { func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6017,7 +5886,7 @@ func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} + return file_messages_proto_rawDescGZIP(), []int{85} } func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { @@ -6038,7 +5907,7 @@ type FinalityConflictNotificationMessage struct { func (x *FinalityConflictNotificationMessage) Reset() { *x = FinalityConflictNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6051,7 +5920,7 @@ func (x *FinalityConflictNotificationMessage) String() string { func (*FinalityConflictNotificationMessage) ProtoMessage() {} func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6064,7 +5933,7 @@ func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} + return file_messages_proto_rawDescGZIP(), []int{86} } func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { @@ -6085,7 +5954,7 @@ type FinalityConflictResolvedNotificationMessage struct { func (x *FinalityConflictResolvedNotificationMessage) Reset() { *x = FinalityConflictResolvedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6098,7 +5967,7 @@ func (x *FinalityConflictResolvedNotificationMessage) String() string { func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6111,7 +5980,7 @@ func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflec // Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} + return file_messages_proto_rawDescGZIP(), []int{87} } func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { @@ -6130,7 +5999,7 @@ type ShutDownRequestMessage struct { func (x *ShutDownRequestMessage) Reset() { *x = ShutDownRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6143,7 +6012,7 @@ func (x *ShutDownRequestMessage) String() string { func (*ShutDownRequestMessage) ProtoMessage() {} func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6156,7 +6025,7 @@ func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{90} + return file_messages_proto_rawDescGZIP(), []int{88} } type ShutDownResponseMessage struct { @@ -6170,7 +6039,7 @@ type ShutDownResponseMessage struct { func (x *ShutDownResponseMessage) Reset() { *x = ShutDownResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6183,7 +6052,7 @@ func (x *ShutDownResponseMessage) String() string { func (*ShutDownResponseMessage) ProtoMessage() {} func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6196,7 +6065,7 @@ func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{91} + return file_messages_proto_rawDescGZIP(), []int{89} } func (x *ShutDownResponseMessage) GetError() *RPCError { @@ -6219,7 +6088,7 @@ type GetHeadersRequestMessage struct { func (x *GetHeadersRequestMessage) Reset() { *x = GetHeadersRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6232,7 +6101,7 @@ func (x *GetHeadersRequestMessage) String() string { func (*GetHeadersRequestMessage) ProtoMessage() {} func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6245,7 +6114,7 @@ func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{92} + return file_messages_proto_rawDescGZIP(), []int{90} } func (x *GetHeadersRequestMessage) GetStartHash() string { @@ -6281,7 +6150,7 @@ type GetHeadersResponseMessage struct { func (x *GetHeadersResponseMessage) Reset() { *x = GetHeadersResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6294,7 +6163,7 @@ func (x *GetHeadersResponseMessage) String() string { func (*GetHeadersResponseMessage) ProtoMessage() {} func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6307,7 +6176,7 @@ func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{93} + return file_messages_proto_rawDescGZIP(), []int{91} } func (x *GetHeadersResponseMessage) GetHeaders() []string { @@ -6328,7 +6197,7 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xbc, 0x36, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xa1, 0x35, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -6376,1061 +6245,1037 @@ var file_messages_proto_rawDesc = []byte{ 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x69, 0x6e, - 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, - 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, - 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x41, - 0x0a, 0x0b, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x12, 0x32, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x13, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, - 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x76, - 0x65, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x13, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, - 0x75, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, - 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, - 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x77, - 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, - 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x69, + 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, + 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x69, + 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x69, + 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x32, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, + 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x59, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, + 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x41, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x12, 0x77, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x16, + 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, + 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, - 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, - 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, - 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, - 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4d, 0x0a, - 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, - 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, - 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x69, 0x0a, 0x18, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, + 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, + 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, + 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, + 0x64, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, - 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, - 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, - 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, + 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, + 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, - 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, - 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, - 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, - 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, - 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, - 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, - 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, - 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, - 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, - 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 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, 0x48, 0x00, 0x52, 0x14, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 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, 0x48, 0x00, 0x52, - 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, + 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1e, 0x72, 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, - 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x1f, 0x72, 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, - 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, - 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, 0x12, 0x7e, 0x0a, - 0x1f, 0x6e, 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, - 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, - 0x1c, 0x66, 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, 0x18, 0x91, 0x08, + 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, + 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, + 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 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, 0x48, 0x00, 0x52, 0x24, - 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, - 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, - 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, - 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, - 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x50, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, - 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, - 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, - 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, - 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, - 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, - 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, - 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, - 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, - 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, - 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, - 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 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, - 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, - 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 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, 0x22, - 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, - 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, + 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, + 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, + 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, + 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x50, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, + 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, + 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, + 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, + 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, + 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, + 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, - 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, - 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, - 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, - 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, - 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, - 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x22, 0x74, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, - 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, - 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, - 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, - 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, - 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, - 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x48, 0x0a, - 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, - 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, - 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, - 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x4f, 0x0a, 0x12, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0f, 0x73, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0f, 0x0a, - 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8d, - 0x03, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0f, - 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, - 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, - 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, - 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, - 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, + 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, + 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, + 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, - 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, - 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, - 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, + 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, + 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, - 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, + 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, + 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, + 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, + 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, + 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, + 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, + 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, + 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, + 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, + 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, + 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, + 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, + 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, + 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, + 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, + 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, + 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, - 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, - 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1f, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, - 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, - 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, - 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, - 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, - 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, - 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 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, 0x7b, 0x0a, - 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, - 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, + 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 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, 0x21, 0x0a, 0x1f, - 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, - 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x12, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x40, 0x0a, 0x1e, + 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, + 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0xff, 0x02, 0x0a, 0x1b, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, - 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x69, - 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, - 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, - 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, - 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, - 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, - 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, - 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, - 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, - 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x62, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x20, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x78, 0x49, 0x64, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, - 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, - 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, 0x6a, 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, 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x20, 0x0a, 0x1e, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, + 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, + 0x64, 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, 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, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x4e, 0x0a, 0x1d, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, + 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, + 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, + 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, + 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, + 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, + 0x65, 0x65, 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, 0x02, 0x20, 0x01, + 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, 0x22, 0x33, 0x0a, + 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, + 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, + 0x74, 0x72, 0x79, 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, + 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, + 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, + 0x6f, 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, 0xb5, + 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, + 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, + 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, + 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, + 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x62, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 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, + 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, + 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 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, 0x9e, + 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, + 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, + 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, + 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, + 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, 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, + 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, 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, + 0x6a, 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, + 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, + 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, 0x04, 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, 0x05, 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, 0x06, + 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, 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, 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, + 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, 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 ( @@ -7445,7 +7290,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 94) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 92) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage @@ -7466,81 +7311,79 @@ var file_messages_proto_goTypes = []interface{}{ (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage - (*RequestSelectedTipMessage)(nil), // 19: protowire.RequestSelectedTipMessage - (*RequestTransactionsMessage)(nil), // 20: protowire.RequestTransactionsMessage - (*TransactionNotFoundMessage)(nil), // 21: protowire.TransactionNotFoundMessage - (*InvRelayBlockMessage)(nil), // 22: protowire.InvRelayBlockMessage - (*InvTransactionsMessage)(nil), // 23: protowire.InvTransactionsMessage - (*PingMessage)(nil), // 24: protowire.PingMessage - (*PongMessage)(nil), // 25: protowire.PongMessage - (*SelectedTipMessage)(nil), // 26: protowire.SelectedTipMessage - (*VerackMessage)(nil), // 27: protowire.VerackMessage - (*VersionMessage)(nil), // 28: protowire.VersionMessage - (*RejectMessage)(nil), // 29: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 30: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IBDRootUTXOSetAndBlockMessage)(nil), // 31: protowire.IBDRootUTXOSetAndBlockMessage - (*RequestIBDBlocksMessage)(nil), // 32: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 33: protowire.IBDRootNotFoundMessage - (*RPCError)(nil), // 34: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 35: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 36: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 37: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 38: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 39: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 40: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 41: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 42: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 43: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 44: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 45: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 46: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 47: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 48: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 49: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 50: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 51: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 52: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 53: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 54: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 55: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 56: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 57: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 58: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 59: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 60: protowire.SubmitTransactionResponseMessage - (*NotifyChainChangedRequestMessage)(nil), // 61: protowire.NotifyChainChangedRequestMessage - (*NotifyChainChangedResponseMessage)(nil), // 62: protowire.NotifyChainChangedResponseMessage - (*ChainChangedNotificationMessage)(nil), // 63: protowire.ChainChangedNotificationMessage - (*ChainBlock)(nil), // 64: protowire.ChainBlock - (*AcceptedBlock)(nil), // 65: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 66: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 67: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 68: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 69: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 70: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 71: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 72: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 73: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 74: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 75: protowire.GetSubnetworkResponseMessage - (*GetChainFromBlockRequestMessage)(nil), // 76: protowire.GetChainFromBlockRequestMessage - (*GetChainFromBlockResponseMessage)(nil), // 77: protowire.GetChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 78: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 79: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 80: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 81: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 82: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 83: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 84: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 85: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 86: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 87: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 88: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 89: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 90: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 91: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 92: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 93: protowire.GetHeadersResponseMessage + (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage + (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage + (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 23: protowire.PingMessage + (*PongMessage)(nil), // 24: protowire.PongMessage + (*VerackMessage)(nil), // 25: protowire.VerackMessage + (*VersionMessage)(nil), // 26: protowire.VersionMessage + (*RejectMessage)(nil), // 27: protowire.RejectMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage + (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage + (*RPCError)(nil), // 32: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 33: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 34: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 35: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 36: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 37: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 38: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 39: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 40: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 41: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 42: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 43: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 44: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 45: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 46: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 47: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 48: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 49: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 50: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 51: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 52: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 53: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 54: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 55: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 56: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 57: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 58: protowire.SubmitTransactionResponseMessage + (*NotifyChainChangedRequestMessage)(nil), // 59: protowire.NotifyChainChangedRequestMessage + (*NotifyChainChangedResponseMessage)(nil), // 60: protowire.NotifyChainChangedResponseMessage + (*ChainChangedNotificationMessage)(nil), // 61: protowire.ChainChangedNotificationMessage + (*ChainBlock)(nil), // 62: protowire.ChainBlock + (*AcceptedBlock)(nil), // 63: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 64: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 65: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 66: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 67: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 68: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 69: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 70: protowire.TransactionVerboseOutput + (*ScriptPubKeyResult)(nil), // 71: protowire.ScriptPubKeyResult + (*GetSubnetworkRequestMessage)(nil), // 72: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 73: protowire.GetSubnetworkResponseMessage + (*GetChainFromBlockRequestMessage)(nil), // 74: protowire.GetChainFromBlockRequestMessage + (*GetChainFromBlockResponseMessage)(nil), // 75: protowire.GetChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 76: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 77: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 78: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 79: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 80: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 81: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 82: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 83: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 84: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 85: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 86: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 87: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 88: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 89: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 90: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 91: protowire.GetHeadersResponseMessage } var file_messages_proto_depIdxs = []int32{ 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -7553,154 +7396,150 @@ var file_messages_proto_depIdxs = []int32{ 16, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage 17, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage 18, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage - 19, // 10: protowire.KaspadMessage.requestSelectedTip:type_name -> protowire.RequestSelectedTipMessage - 20, // 11: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage - 10, // 12: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage - 22, // 13: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage - 23, // 14: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage - 24, // 15: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage - 25, // 16: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage - 26, // 17: protowire.KaspadMessage.selectedTip:type_name -> protowire.SelectedTipMessage - 27, // 18: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage - 28, // 19: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage - 21, // 20: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage - 29, // 21: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 11, // 22: protowire.KaspadMessage.blockHeader:type_name -> protowire.BlockHeaderMessage - 30, // 23: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage - 31, // 24: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage - 32, // 25: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 33, // 26: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 35, // 27: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 36, // 28: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 37, // 29: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 38, // 30: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 39, // 31: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 40, // 32: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 41, // 33: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 42, // 34: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 43, // 35: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 44, // 36: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 45, // 37: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 47, // 38: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 48, // 39: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 50, // 40: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 51, // 41: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 54, // 42: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 55, // 43: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 57, // 44: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 58, // 45: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 59, // 46: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 60, // 47: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 61, // 48: protowire.KaspadMessage.notifyChainChangedRequest:type_name -> protowire.NotifyChainChangedRequestMessage - 62, // 49: protowire.KaspadMessage.notifyChainChangedResponse:type_name -> protowire.NotifyChainChangedResponseMessage - 63, // 50: protowire.KaspadMessage.chainChangedNotification:type_name -> protowire.ChainChangedNotificationMessage - 66, // 51: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 67, // 52: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 74, // 53: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 75, // 54: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 76, // 55: protowire.KaspadMessage.getChainFromBlockRequest:type_name -> protowire.GetChainFromBlockRequestMessage - 77, // 56: protowire.KaspadMessage.getChainFromBlockResponse:type_name -> protowire.GetChainFromBlockResponseMessage - 78, // 57: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 79, // 58: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 80, // 59: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 81, // 60: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 82, // 61: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 83, // 62: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 84, // 63: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 85, // 64: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 86, // 65: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 87, // 66: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 88, // 67: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 89, // 68: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 52, // 69: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 53, // 70: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 90, // 71: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 91, // 72: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 92, // 73: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 93, // 74: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 4, // 75: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId - 3, // 76: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 6, // 77: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 78: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 4, // 79: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 80: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 81: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint - 8, // 82: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId - 11, // 83: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 84: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 85: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 12, // 86: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 87: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash - 12, // 88: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 12, // 89: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 90: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 91: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 92: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 12, // 93: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 12, // 94: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 95: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId - 8, // 96: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId - 12, // 97: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 98: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId - 12, // 99: protowire.SelectedTipMessage.selectedTipHash:type_name -> protowire.Hash - 3, // 100: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 12, // 101: protowire.VersionMessage.selectedTipHash:type_name -> protowire.Hash - 4, // 102: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 103: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 104: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 105: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 34, // 106: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 107: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 34, // 108: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 109: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 34, // 110: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 34, // 111: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 112: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 46, // 113: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 46, // 114: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 34, // 115: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 34, // 116: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 69, // 117: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 49, // 118: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 34, // 119: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 49, // 120: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 34, // 121: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 56, // 122: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 34, // 123: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 124: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 5, // 125: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.TransactionMessage - 34, // 126: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 34, // 127: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError - 64, // 128: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 65, // 129: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 68, // 130: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 131: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 69, // 132: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 70, // 133: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 72, // 134: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 71, // 135: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 73, // 136: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 34, // 137: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 64, // 138: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 68, // 139: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 140: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 68, // 141: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 142: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 34, // 143: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 34, // 144: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 145: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 34, // 146: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 34, // 147: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 34, // 148: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 0, // 149: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 150: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 151: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 152: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 151, // [151:153] is the sub-list for method output_type - 149, // [149:151] is the sub-list for method input_type - 149, // [149:149] is the sub-list for extension type_name - 149, // [149:149] is the sub-list for extension extendee - 0, // [0:149] is the sub-list for field type_name + 19, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage + 10, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage + 21, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage + 22, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage + 23, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage + 24, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage + 25, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage + 26, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage + 20, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage + 27, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage + 11, // 20: protowire.KaspadMessage.blockHeader:type_name -> protowire.BlockHeaderMessage + 28, // 21: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage + 29, // 22: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage + 30, // 23: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage + 31, // 24: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage + 33, // 25: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 34, // 26: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 35, // 27: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 36, // 28: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 37, // 29: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 38, // 30: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 39, // 31: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 40, // 32: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 41, // 33: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 42, // 34: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 43, // 35: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 45, // 36: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 46, // 37: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 48, // 38: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 49, // 39: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 52, // 40: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 53, // 41: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 55, // 42: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 56, // 43: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 57, // 44: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 58, // 45: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 59, // 46: protowire.KaspadMessage.notifyChainChangedRequest:type_name -> protowire.NotifyChainChangedRequestMessage + 60, // 47: protowire.KaspadMessage.notifyChainChangedResponse:type_name -> protowire.NotifyChainChangedResponseMessage + 61, // 48: protowire.KaspadMessage.chainChangedNotification:type_name -> protowire.ChainChangedNotificationMessage + 64, // 49: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 65, // 50: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 72, // 51: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 73, // 52: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 74, // 53: protowire.KaspadMessage.getChainFromBlockRequest:type_name -> protowire.GetChainFromBlockRequestMessage + 75, // 54: protowire.KaspadMessage.getChainFromBlockResponse:type_name -> protowire.GetChainFromBlockResponseMessage + 76, // 55: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 77, // 56: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 78, // 57: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 79, // 58: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 80, // 59: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 81, // 60: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 82, // 61: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 83, // 62: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 84, // 63: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 85, // 64: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 86, // 65: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 87, // 66: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 50, // 67: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 51, // 68: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 88, // 69: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 89, // 70: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 90, // 71: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 91, // 72: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 4, // 73: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId + 3, // 74: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 6, // 75: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 76: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 4, // 77: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 78: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 7, // 79: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint + 8, // 80: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId + 11, // 81: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 82: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 83: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 84: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 85: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash + 12, // 86: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 87: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 88: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 89: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 90: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 91: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 92: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 93: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 8, // 94: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId + 12, // 95: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 96: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId + 3, // 97: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 4, // 98: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 99: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 100: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 101: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 32, // 102: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 103: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 32, // 104: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 105: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 32, // 106: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 32, // 107: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 108: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 44, // 109: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 44, // 110: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 32, // 111: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 32, // 112: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 67, // 113: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 47, // 114: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 32, // 115: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 47, // 116: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 32, // 117: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 54, // 118: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 32, // 119: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 32, // 120: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 5, // 121: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.TransactionMessage + 32, // 122: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 32, // 123: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError + 62, // 124: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 63, // 125: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 66, // 126: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 127: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 67, // 128: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 68, // 129: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 70, // 130: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 69, // 131: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 71, // 132: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 32, // 133: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 62, // 134: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 66, // 135: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 136: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 66, // 137: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 138: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 32, // 139: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 32, // 140: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 32, // 141: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 32, // 142: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 32, // 143: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 32, // 144: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 0, // 145: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 146: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 147: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 148: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 147, // [147:149] is the sub-list for method output_type + 145, // [145:147] is the sub-list for method input_type + 145, // [145:145] is the sub-list for extension type_name + 145, // [145:145] is the sub-list for extension extendee + 0, // [0:145] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -7938,18 +7777,6 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestSelectedTipMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RequestTransactionsMessage); i { case 0: return &v.state @@ -7961,7 +7788,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransactionNotFoundMessage); i { case 0: return &v.state @@ -7973,7 +7800,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*InvRelayBlockMessage); i { case 0: return &v.state @@ -7985,7 +7812,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*InvTransactionsMessage); i { case 0: return &v.state @@ -7997,7 +7824,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PingMessage); i { case 0: return &v.state @@ -8009,7 +7836,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PongMessage); i { case 0: return &v.state @@ -8021,19 +7848,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectedTipMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VerackMessage); i { case 0: return &v.state @@ -8045,7 +7860,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VersionMessage); i { case 0: return &v.state @@ -8057,7 +7872,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RejectMessage); i { case 0: return &v.state @@ -8069,7 +7884,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { case 0: return &v.state @@ -8081,7 +7896,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { case 0: return &v.state @@ -8093,7 +7908,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RequestIBDBlocksMessage); i { case 0: return &v.state @@ -8105,7 +7920,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IBDRootNotFoundMessage); i { case 0: return &v.state @@ -8117,7 +7932,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RPCError); i { case 0: return &v.state @@ -8129,7 +7944,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetCurrentNetworkRequestMessage); i { case 0: return &v.state @@ -8141,7 +7956,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetCurrentNetworkResponseMessage); i { case 0: return &v.state @@ -8153,7 +7968,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubmitBlockRequestMessage); i { case 0: return &v.state @@ -8165,7 +7980,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubmitBlockResponseMessage); i { case 0: return &v.state @@ -8177,7 +7992,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockTemplateRequestMessage); i { case 0: return &v.state @@ -8189,7 +8004,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockTemplateResponseMessage); i { case 0: return &v.state @@ -8201,7 +8016,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyBlockAddedRequestMessage); i { case 0: return &v.state @@ -8213,7 +8028,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyBlockAddedResponseMessage); i { case 0: return &v.state @@ -8225,7 +8040,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlockAddedNotificationMessage); i { case 0: return &v.state @@ -8237,7 +8052,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetPeerAddressesRequestMessage); i { case 0: return &v.state @@ -8249,7 +8064,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetPeerAddressesResponseMessage); i { case 0: return &v.state @@ -8261,7 +8076,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetPeerAddressesKnownAddressMessage); i { case 0: return &v.state @@ -8273,7 +8088,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetSelectedTipHashRequestMessage); i { case 0: return &v.state @@ -8285,7 +8100,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetSelectedTipHashResponseMessage); i { case 0: return &v.state @@ -8297,7 +8112,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MempoolEntry); i { case 0: return &v.state @@ -8309,7 +8124,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetMempoolEntryRequestMessage); i { case 0: return &v.state @@ -8321,7 +8136,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetMempoolEntryResponseMessage); i { case 0: return &v.state @@ -8333,7 +8148,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetMempoolEntriesRequestMessage); i { case 0: return &v.state @@ -8345,7 +8160,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetMempoolEntriesResponseMessage); i { case 0: return &v.state @@ -8357,7 +8172,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetConnectedPeerInfoRequestMessage); i { case 0: return &v.state @@ -8369,7 +8184,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetConnectedPeerInfoResponseMessage); i { case 0: return &v.state @@ -8381,7 +8196,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetConnectedPeerInfoMessage); i { case 0: return &v.state @@ -8393,7 +8208,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddPeerRequestMessage); i { case 0: return &v.state @@ -8405,7 +8220,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddPeerResponseMessage); i { case 0: return &v.state @@ -8417,7 +8232,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubmitTransactionRequestMessage); i { case 0: return &v.state @@ -8429,7 +8244,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubmitTransactionResponseMessage); i { case 0: return &v.state @@ -8441,7 +8256,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyChainChangedRequestMessage); i { case 0: return &v.state @@ -8453,7 +8268,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyChainChangedResponseMessage); i { case 0: return &v.state @@ -8465,7 +8280,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChainChangedNotificationMessage); i { case 0: return &v.state @@ -8477,7 +8292,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChainBlock); i { case 0: return &v.state @@ -8489,7 +8304,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AcceptedBlock); i { case 0: return &v.state @@ -8501,7 +8316,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockRequestMessage); i { case 0: return &v.state @@ -8513,7 +8328,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockResponseMessage); i { case 0: return &v.state @@ -8525,7 +8340,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlockVerboseData); i { case 0: return &v.state @@ -8537,7 +8352,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransactionVerboseData); i { case 0: return &v.state @@ -8549,7 +8364,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransactionVerboseInput); i { case 0: return &v.state @@ -8561,7 +8376,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ScriptSig); i { case 0: return &v.state @@ -8573,7 +8388,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransactionVerboseOutput); i { case 0: return &v.state @@ -8585,7 +8400,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ScriptPubKeyResult); i { case 0: return &v.state @@ -8597,7 +8412,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetSubnetworkRequestMessage); i { case 0: return &v.state @@ -8609,7 +8424,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetSubnetworkResponseMessage); i { case 0: return &v.state @@ -8621,7 +8436,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetChainFromBlockRequestMessage); i { case 0: return &v.state @@ -8633,7 +8448,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetChainFromBlockResponseMessage); i { case 0: return &v.state @@ -8645,7 +8460,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlocksRequestMessage); i { case 0: return &v.state @@ -8657,7 +8472,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlocksResponseMessage); i { case 0: return &v.state @@ -8669,7 +8484,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockCountRequestMessage); i { case 0: return &v.state @@ -8681,7 +8496,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockCountResponseMessage); i { case 0: return &v.state @@ -8693,7 +8508,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockDagInfoRequestMessage); i { case 0: return &v.state @@ -8705,7 +8520,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetBlockDagInfoResponseMessage); i { case 0: return &v.state @@ -8717,7 +8532,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ResolveFinalityConflictRequestMessage); i { case 0: return &v.state @@ -8729,7 +8544,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ResolveFinalityConflictResponseMessage); i { case 0: return &v.state @@ -8741,7 +8556,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyFinalityConflictsRequestMessage); i { case 0: return &v.state @@ -8753,7 +8568,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NotifyFinalityConflictsResponseMessage); i { case 0: return &v.state @@ -8765,7 +8580,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FinalityConflictNotificationMessage); i { case 0: return &v.state @@ -8777,7 +8592,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FinalityConflictResolvedNotificationMessage); i { case 0: return &v.state @@ -8789,7 +8604,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShutDownRequestMessage); i { case 0: return &v.state @@ -8801,7 +8616,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShutDownResponseMessage); i { case 0: return &v.state @@ -8813,7 +8628,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetHeadersRequestMessage); i { case 0: return &v.state @@ -8825,7 +8640,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetHeadersResponseMessage); i { case 0: return &v.state @@ -8849,14 +8664,12 @@ func file_messages_proto_init() { (*KaspadMessage_RequestNextHeaders)(nil), (*KaspadMessage_DoneHeaders)(nil), (*KaspadMessage_RequestRelayBlocks)(nil), - (*KaspadMessage_RequestSelectedTip)(nil), (*KaspadMessage_RequestTransactions)(nil), (*KaspadMessage_IbdBlock)(nil), (*KaspadMessage_InvRelayBlock)(nil), (*KaspadMessage_InvTransactions)(nil), (*KaspadMessage_Ping)(nil), (*KaspadMessage_Pong)(nil), - (*KaspadMessage_SelectedTip)(nil), (*KaspadMessage_Verack)(nil), (*KaspadMessage_Version)(nil), (*KaspadMessage_TransactionNotFound)(nil), @@ -8921,7 +8734,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 94, + NumMessages: 92, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index ed296bfa0..243f39278 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -15,14 +15,12 @@ message KaspadMessage { RequestNextHeadersMessage requestNextHeaders = 8; DoneHeadersMessage DoneHeaders = 9; RequestRelayBlocksMessage requestRelayBlocks = 10; - RequestSelectedTipMessage requestSelectedTip = 11; RequestTransactionsMessage requestTransactions = 12; BlockMessage ibdBlock = 13; InvRelayBlockMessage invRelayBlock = 14; InvTransactionsMessage invTransactions = 15; PingMessage ping = 16; PongMessage pong = 17; - SelectedTipMessage selectedTip = 18; VerackMessage verack = 19; VersionMessage version = 20; TransactionNotFoundMessage transactionNotFound = 21; @@ -171,6 +169,7 @@ message Hash{ message RequestBlockLocatorMessage{ Hash lowHash = 1; Hash highHash = 2; + uint32 limit = 3; } // GetBlockLocatorMessage end @@ -203,11 +202,6 @@ message RequestRelayBlocksMessage{ } // RequestRelayBlocksMessage end -// GetSelectedTipMessage start -message RequestSelectedTipMessage{ -} -// GetSelectedTipMessage end - // RequestTransactionsMessage start message RequestTransactionsMessage { repeated TransactionId ids = 1; @@ -244,12 +238,6 @@ message PongMessage{ } // PongMessage end -// SelectedTipMessage start -message SelectedTipMessage{ - Hash selectedTipHash = 1; -} -// SelectedTipMessage end - // VerackMessage start message VerackMessage{ } @@ -263,7 +251,6 @@ message VersionMessage{ NetAddress address = 4; bytes id = 5; string userAgent = 6; - Hash selectedTipHash = 7; bool disableRelayTx = 8; SubnetworkId subnetworkId = 9; string network = 10; @@ -408,8 +395,6 @@ message GetConnectedPeerInfoMessage{ string id = 1; string address = 2; int64 lastPingDuration = 3; - string selectedTipHash = 4; - bool isSyncNode = 5; bool isOutbound = 6; int64 timeOffset = 7; string userAgent = 8; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_block_locator.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_block_locator.go index 87276059d..06824a0de 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_block_locator.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_block_locator.go @@ -16,6 +16,7 @@ func (x *KaspadMessage_RequestBlockLocator) toAppMessage() (appmessage.Message, return &appmessage.MsgRequestBlockLocator{ LowHash: lowHash, HighHash: highHash, + Limit: x.RequestBlockLocator.Limit, }, nil } @@ -23,6 +24,7 @@ func (x *KaspadMessage_RequestBlockLocator) fromAppMessage(msgGetBlockLocator *a x.RequestBlockLocator = &RequestBlockLocatorMessage{ LowHash: domainHashToProto(msgGetBlockLocator.LowHash), HighHash: domainHashToProto(msgGetBlockLocator.HighHash), + Limit: msgGetBlockLocator.Limit, } return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go index 20c0247f5..167455540 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_blocks.go @@ -2,14 +2,9 @@ package protowire import ( "github.com/kaspanet/kaspad/app/appmessage" - "github.com/pkg/errors" ) func (x *KaspadMessage_RequestIBDBlocks) toAppMessage() (appmessage.Message, error) { - if len(x.RequestIBDBlocks.Hashes) > appmessage.MaxRequestIBDBlocksHashes { - return nil, errors.Errorf("too many hashes for message "+ - "[count %d, max %d]", len(x.RequestIBDBlocks.Hashes), appmessage.MaxRequestIBDBlocksHashes) - } hashes, err := protoHashesToDomain(x.RequestIBDBlocks.Hashes) if err != nil { return nil, err @@ -18,11 +13,6 @@ func (x *KaspadMessage_RequestIBDBlocks) toAppMessage() (appmessage.Message, err } func (x *KaspadMessage_RequestIBDBlocks) fromAppMessage(msgRequestIBDBlocks *appmessage.MsgRequestIBDBlocks) error { - if len(msgRequestIBDBlocks.Hashes) > appmessage.MaxRequestIBDBlocksHashes { - return errors.Errorf("too many hashes for message "+ - "[count %d, max %d]", len(msgRequestIBDBlocks.Hashes), appmessage.MaxRequestIBDBlocksHashes) - } - x.RequestIBDBlocks = &RequestIBDBlocksMessage{ Hashes: domainHashesToProto(msgRequestIBDBlocks.Hashes), } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_selected_tip.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_selected_tip.go deleted file mode 100644 index 0e99ae70e..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_selected_tip.go +++ /dev/null @@ -1,11 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_RequestSelectedTip) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgRequestSelectedTip{}, nil -} - -func (x *KaspadMessage_RequestSelectedTip) fromAppMessage(_ *appmessage.MsgRequestSelectedTip) error { - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_selected_tip.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_selected_tip.go deleted file mode 100644 index fa7eabdfe..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_selected_tip.go +++ /dev/null @@ -1,19 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_SelectedTip) toAppMessage() (appmessage.Message, error) { - hash, err := x.SelectedTip.SelectedTipHash.toDomain() - if err != nil { - return nil, err - } - - return &appmessage.MsgSelectedTip{SelectedTipHash: hash}, nil -} - -func (x *KaspadMessage_SelectedTip) fromAppMessage(msgSelectedTip *appmessage.MsgSelectedTip) error { - x.SelectedTip = &SelectedTipMessage{ - SelectedTipHash: domainHashToProto(msgSelectedTip.SelectedTipHash), - } - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go index 2cffe5465..f1dfa7401 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_version.go @@ -17,11 +17,6 @@ func (x *KaspadMessage_Version) toAppMessage() (appmessage.Message, error) { } } - selectedTipHash, err := x.Version.SelectedTipHash.toDomain() - if err != nil { - return nil, err - } - subnetworkID, err := x.Version.SubnetworkId.toDomain() if err != nil { return nil, err @@ -40,7 +35,6 @@ func (x *KaspadMessage_Version) toAppMessage() (appmessage.Message, error) { Address: address, ID: id.FromBytes(x.Version.Id), UserAgent: x.Version.UserAgent, - SelectedTipHash: selectedTipHash, DisableRelayTx: x.Version.DisableRelayTx, SubnetworkID: subnetworkID, }, nil @@ -71,7 +65,6 @@ func (x *KaspadMessage_Version) fromAppMessage(msgVersion *appmessage.MsgVersion Address: address, Id: versionID, UserAgent: msgVersion.UserAgent, - SelectedTipHash: domainHashToProto(msgVersion.SelectedTipHash), DisableRelayTx: msgVersion.DisableRelayTx, SubnetworkId: domainSubnetworkIDToProto(msgVersion.SubnetworkID), } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go index 32ed3109d..17f9621d2 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go @@ -23,8 +23,6 @@ func (x *KaspadMessage_GetConnectedPeerInfoResponse) toAppMessage() (appmessage. ID: info.Id, Address: info.Address, LastPingDuration: info.LastPingDuration, - SelectedTipHash: info.SelectedTipHash, - IsSyncNode: info.IsSyncNode, IsOutbound: info.IsOutbound, TimeOffset: info.TimeOffset, UserAgent: info.UserAgent, @@ -49,8 +47,6 @@ func (x *KaspadMessage_GetConnectedPeerInfoResponse) fromAppMessage(message *app Id: info.ID, Address: info.Address, LastPingDuration: info.LastPingDuration, - SelectedTipHash: info.SelectedTipHash, - IsSyncNode: info.IsSyncNode, IsOutbound: info.IsOutbound, TimeOffset: info.TimeOffset, UserAgent: info.UserAgent, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index c690ac9a3..83e6623f7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -114,13 +114,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgRequestSelectedTip: - payload := new(KaspadMessage_RequestSelectedTip) - err := payload.fromAppMessage(message) - if err != nil { - return nil, err - } - return payload, nil case *appmessage.MsgRequestTransactions: payload := new(KaspadMessage_RequestTransactions) err := payload.fromAppMessage(message) @@ -170,13 +163,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgSelectedTip: - payload := new(KaspadMessage_SelectedTip) - err := payload.fromAppMessage(message) - if err != nil { - return nil, err - } - return payload, nil case *appmessage.MsgTx: payload := new(KaspadMessage_Transaction) err := payload.fromAppMessage(message) diff --git a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go index 255780fe0..e69f2f620 100644 --- a/infrastructure/network/netadapter/standalone/minimal_net_adapter.go +++ b/infrastructure/network/netadapter/standalone/minimal_net_adapter.go @@ -120,7 +120,6 @@ func (mna *MinimalNetAdapter) handleHandshake(routes *Routes, ourID *id.ID) erro Address: nil, ID: ourID, UserAgent: "/net-adapter-mock/", - SelectedTipHash: versionMessage.SelectedTipHash, DisableRelayTx: true, SubnetworkID: nil, }) diff --git a/testing/integration/ibd_test.go b/testing/integration/ibd_test.go index 78b39fc8a..1a3b97803 100644 --- a/testing/integration/ibd_test.go +++ b/testing/integration/ibd_test.go @@ -14,7 +14,7 @@ func TestIBD(t *testing.T) { syncer, syncee, _, teardown := standardSetup(t) defer teardown() - for i := 0; i < numBlocks; i++ { + for i := 0; i < numBlocks-1; i++ { mineNextBlock(t, syncer) } @@ -28,6 +28,9 @@ func TestIBD(t *testing.T) { connect(t, syncer, syncee) + // We expect this to trigger IBD + mineNextBlock(t, syncer) + select { case <-time.After(defaultTimeout): t.Fatalf("Timeout waiting for IBD to finish. Received %d blocks out of %d", receivedBlocks, numBlocks) From 78550d3639ea9b9272d395aa4ad654b1e42deaf5 Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Sun, 6 Dec 2020 18:41:07 +0200 Subject: [PATCH 115/351] Adds "checkDelayedBlock" - checks if the block timeStamp is in the future. (#1183) * [#1056] Adds "checkDelayedBlock" - check if the block timeStamp is in future. Adds 2 new fields to blockValidator struct. Adds new Rule Error "ErrDelayedBlock" . * [#1056] Replace "ErrDelayedBlock" to "ErrBlockIsTooMuchInTheFuture". * [#1056] Replace "checkDelayedBlock" to "checkBlockTimeStampInIsolation". * [#1056] Cosmetics changes: timeStamp -> timestamp . * Merge remote-tracking branch 'origin/v0.8.2-dev' into droppedDelayedBlock # Conflicts: # domain/consensus/factory.go # domain/consensus/processes/blockvalidator/block_header_in_isolation.go # domain/consensus/processes/blockvalidator/blockvalidator.go Co-authored-by: tal --- domain/consensus/factory.go | 5 +- .../block_header_in_isolation.go | 18 ++++++ .../blockvalidator/blockvalidator.go | 60 ++++++++++--------- domain/consensus/ruleerrors/rule_error.go | 3 + 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 4462d3974..ddcd183b7 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,12 +1,11 @@ package consensus import ( + "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" "io/ioutil" "os" "sync" - "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" - "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database" @@ -152,6 +151,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagParams.MaxBlockSize, dagParams.MergeSetSizeLimit, dagParams.MaxBlockParents, + dagParams.TimestampDeviationTolerance, + dagParams.TargetTimePerBlock, dbManager, difficultyManager, diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index a63f910ff..8fe275a82 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -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/util/mstime" "github.com/pkg/errors" ) @@ -15,6 +16,11 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain return err } + err = v.checkBlockTimestampInIsolation(header) + if err != nil { + return err + } + err = v.checkParentsLimit(header) if err != nil { return err @@ -35,3 +41,15 @@ func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader } return nil } + +func (v *blockValidator) checkBlockTimestampInIsolation(header *externalapi.DomainBlockHeader) error { + + blockTimestamp := header.TimeInMilliseconds + now := mstime.Now().UnixMilliseconds() + maxCurrentTime := now + int64(v.timestampDeviationTolerance)*v.targetTimePerBlock.Milliseconds() + if blockTimestamp > maxCurrentTime { + return errors.Wrapf( + ruleerrors.ErrBlockIsTooMuchInTheFuture, "The block timestamp is in the future.") + } + return nil +} diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 2403a67fc..686bbf7a6 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -2,6 +2,7 @@ package blockvalidator import ( "math/big" + "time" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -11,14 +12,16 @@ import ( // blockValidator exposes a set of validation classes, after which // it's possible to determine whether either a block is valid type blockValidator struct { - powMax *big.Int - skipPoW bool - genesisHash *externalapi.DomainHash - enableNonNativeSubnetworks bool - powMaxBits uint32 - maxBlockSize uint64 - mergeSetSizeLimit uint64 - maxBlockParents model.KType + powMax *big.Int + skipPoW bool + genesisHash *externalapi.DomainHash + enableNonNativeSubnetworks bool + powMaxBits uint32 + maxBlockSize uint64 + mergeSetSizeLimit uint64 + maxBlockParents model.KType + timestampDeviationTolerance uint64 + targetTimePerBlock time.Duration databaseContext model.DBReader difficultyManager model.DifficultyManager @@ -45,6 +48,8 @@ func New(powMax *big.Int, maxBlockSize uint64, mergeSetSizeLimit uint64, maxBlockParents model.KType, + timestampDeviationTolerance uint64, + targetTimePerBlock time.Duration, databaseContext model.DBReader, @@ -64,25 +69,26 @@ func New(powMax *big.Int, blockStatusStore model.BlockStatusStore) model.BlockValidator { return &blockValidator{ - powMax: powMax, - skipPoW: skipPoW, - genesisHash: genesisHash, - enableNonNativeSubnetworks: enableNonNativeSubnetworks, - powMaxBits: util.BigToCompact(powMax), - maxBlockSize: maxBlockSize, - mergeSetSizeLimit: mergeSetSizeLimit, - maxBlockParents: maxBlockParents, - - databaseContext: databaseContext, - difficultyManager: difficultyManager, - pastMedianTimeManager: pastMedianTimeManager, - transactionValidator: transactionValidator, - ghostdagManager: ghostdagManager, - dagTopologyManager: dagTopologyManager, - dagTraversalManager: dagTraversalManager, - coinbaseManager: coinbaseManager, - mergeDepthManager: mergeDepthManager, - pruningStore: pruningStore, + powMax: powMax, + skipPoW: skipPoW, + genesisHash: genesisHash, + enableNonNativeSubnetworks: enableNonNativeSubnetworks, + powMaxBits: util.BigToCompact(powMax), + maxBlockSize: maxBlockSize, + mergeSetSizeLimit: mergeSetSizeLimit, + maxBlockParents: maxBlockParents, + timestampDeviationTolerance: timestampDeviationTolerance, + targetTimePerBlock: targetTimePerBlock, + databaseContext: databaseContext, + difficultyManager: difficultyManager, + pastMedianTimeManager: pastMedianTimeManager, + transactionValidator: transactionValidator, + ghostdagManager: ghostdagManager, + dagTopologyManager: dagTopologyManager, + dagTraversalManager: dagTraversalManager, + coinbaseManager: coinbaseManager, + mergeDepthManager: mergeDepthManager, + pruningStore: pruningStore, blockStore: blockStore, ghostdagDataStore: ghostdagDataStore, diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index cf0c21798..051efccaf 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -234,6 +234,9 @@ var ( //ErrPruningPointViolation indicates that the pruning point isn't in the block past. ErrPruningPointViolation = newRuleError("ErrPruningPointViolation") + + //ErrBlockIsTooMuchInTheFuture indicates that the block timestamp is too much in the future. + ErrBlockIsTooMuchInTheFuture = newRuleError("ErrBlockIsTooMuchInTheFuture") ) // RuleError identifies a rule violation. It is used to indicate that From 99625277935d004de0d5cb92b279145c83944538 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 6 Dec 2020 18:42:49 +0200 Subject: [PATCH 116/351] Replace BlueWindow implementation to accomadate a better DAA scheme (#1179) * Change DifficultyAdjustmentWindowSize and TimestampDeviationTolerance from uint64 to int * refactor block_heap for readability and usage * Add a new SizedUpHeap * Refactor BlueWindow with the new DAA * Update TestBlueBlockWindow with the new DAA window * Fix review requested changes --- ...interface_processes_dagtraversalmanager.go | 2 +- .../dagtraversalmanager/block_heap.go | 93 +++++++++++++++---- .../processes/dagtraversalmanager/window.go | 65 ++++++++++--- .../dagtraversalmanager/window_test.go | 58 ++++++------ .../difficultymanager/blockwindow.go | 2 +- .../difficultymanager/difficultymanager.go | 6 +- .../difficultymanager_test.go | 8 +- .../pastmediantimemanager.go | 4 +- domain/dagconfig/params.go | 4 +- infrastructure/config/network.go | 4 +- 10 files changed, 174 insertions(+), 72 deletions(-) diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index e3df498ce..f020760af 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -10,7 +10,7 @@ type DAGTraversalManager interface { SelectedParentIterator(highHash *externalapi.DomainHash) BlockIterator SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error) AnticoneFromContext(context, lowHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) - BlueWindow(highHash *externalapi.DomainHash, windowSize uint64) ([]*externalapi.DomainHash, error) + BlueWindow(highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) NewDownHeap() BlockHeap NewUpHeap() BlockHeap } diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go index 40a0849ed..99b5113c0 100644 --- a/domain/consensus/processes/dagtraversalmanager/block_heap.go +++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go @@ -12,7 +12,11 @@ type blockHeapNode struct { ghostdagData model.BlockGHOSTDAGData } -// baseHeap is an implementation for heap.Interface that sorts blocks by their height +func (left *blockHeapNode) less(right *blockHeapNode, gm model.GHOSTDAGManager) bool { + return gm.Less(left.hash, left.ghostdagData, right.hash, right.ghostdagData) +} + +// baseHeap is an implementation for heap.Interface that sorts blocks by their blueWork+hash type baseHeap struct { slice []*blockHeapNode ghostdagManager model.GHOSTDAGManager @@ -33,34 +37,39 @@ func (h *baseHeap) Pop() interface{} { return popped } +// peek returns the block with lowest blueWork+hash from this heap without removing it +func (h *baseHeap) peek() *blockHeapNode { + return h.slice[0] +} + // 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 { - heapNodeA := h.slice[i] - heapNodeB := h.slice[j] - return h.ghostdagManager.Less(heapNodeA.hash, heapNodeA.ghostdagData, heapNodeB.hash, heapNodeB.ghostdagData) + heapNodeI := h.slice[i] + heapNodeJ := h.slice[j] + return heapNodeI.less(heapNodeJ, h.ghostdagManager) } // 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 { - heapNodeA := h.slice[i] - heapNodeB := h.slice[j] - return !h.ghostdagManager.Less(heapNodeA.hash, heapNodeA.ghostdagData, heapNodeB.hash, heapNodeB.ghostdagData) + heapNodeI := h.slice[i] + heapNodeJ := h.slice[j] + return !heapNodeI.less(heapNodeJ, h.ghostdagManager) } -// BlockHeap represents a mutable heap of Blocks, sorted by their height -type BlockHeap struct { +// blockHeap represents a mutable heap of blocks, sorted by their blueWork+hash +type blockHeap struct { impl heap.Interface ghostdagStore model.GHOSTDAGDataStore dbContext model.DBReader } -// NewDownHeap initializes and returns a new BlockHeap +// NewDownHeap initializes and returns a new blockHeap func (dtm dagTraversalManager) NewDownHeap() model.BlockHeap { - h := BlockHeap{ + h := blockHeap{ impl: &downHeap{baseHeap{ghostdagManager: dtm.ghostdagManager}}, ghostdagStore: dtm.ghostdagDataStore, dbContext: dtm.databaseContext, @@ -69,9 +78,9 @@ func (dtm dagTraversalManager) NewDownHeap() model.BlockHeap { return h } -// NewUpHeap initializes and returns a new BlockHeap +// NewUpHeap initializes and returns a new blockHeap func (dtm dagTraversalManager) NewUpHeap() model.BlockHeap { - h := BlockHeap{ + h := blockHeap{ impl: &upHeap{baseHeap{ghostdagManager: dtm.ghostdagManager}}, ghostdagStore: dtm.ghostdagDataStore, dbContext: dtm.databaseContext, @@ -80,13 +89,13 @@ func (dtm dagTraversalManager) NewUpHeap() model.BlockHeap { return h } -// Pop removes the block with lowest height from this heap and returns it -func (bh BlockHeap) Pop() *externalapi.DomainHash { +// Pop removes the block with lowest blueWork+hash from this heap and returns it +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 @@ -101,6 +110,56 @@ 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() } + +// sizedUpBlockHeap represents a mutable heap of Blocks, sorted by their blueWork+hash, capped by a specific size. +type sizedUpBlockHeap struct { + impl upHeap + ghostdagStore model.GHOSTDAGDataStore + dbContext model.DBReader +} + +// newSizedUpHeap initializes and returns a new sizedUpBlockHeap +func (dtm dagTraversalManager) newSizedUpHeap(cap int) *sizedUpBlockHeap { + h := sizedUpBlockHeap{ + impl: upHeap{baseHeap{slice: make([]*blockHeapNode, 0, cap), ghostdagManager: dtm.ghostdagManager}}, + ghostdagStore: dtm.ghostdagDataStore, + dbContext: dtm.databaseContext, + } + heap.Init(&h.impl) + return &h +} + +// len returns the length of this heap +func (sbh *sizedUpBlockHeap) len() int { + return sbh.impl.Len() +} + +// pop removes the block with lowest blueWork+hash from this heap and returns it +func (sbh *sizedUpBlockHeap) pop() *externalapi.DomainHash { + return heap.Pop(&sbh.impl).(*blockHeapNode).hash +} + +// tryPush tries to push the block onto the heap, if the heap is full and it's less than the minimum it rejects it +func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, error) { + ghostdagData, err := sbh.ghostdagStore.Get(sbh.dbContext, blockHash) + if err != nil { + return false, err + } + node := &blockHeapNode{ + hash: blockHash, + ghostdagData: ghostdagData, + } + if len(sbh.impl.slice) == cap(sbh.impl.slice) { + min := sbh.impl.peek() + // if the heap is full, and the new block is less than the minimum, return false + if node.less(min, sbh.impl.ghostdagManager) { + return false, nil + } + sbh.pop() + } + heap.Push(&sbh.impl, node) + return true, nil +} diff --git a/domain/consensus/processes/dagtraversalmanager/window.go b/domain/consensus/processes/dagtraversalmanager/window.go index 25b8a3211..05e8fa10b 100644 --- a/domain/consensus/processes/dagtraversalmanager/window.go +++ b/domain/consensus/processes/dagtraversalmanager/window.go @@ -1,28 +1,61 @@ package dagtraversalmanager -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "sort" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // blueBlockWindow returns a blockWindow of the given size that contains the // blues in the past of startindNode, sorted by GHOSTDAG order. // If the number of blues in the past of startingNode is less then windowSize, // the window will be padded by genesis blocks to achieve a size of windowSize. -func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash, windowSize uint64) ([]*externalapi.DomainHash, error) { - window := make([]*externalapi.DomainHash, 0, windowSize) - +func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) { currentHash := startingBlock currentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) if err != nil { return nil, err } - for uint64(len(window)) < windowSize && currentGHOSTDAGData.SelectedParent() != nil { - for _, blue := range currentGHOSTDAGData.MergeSetBlues() { - window = append(window, blue) - if uint64(len(window)) == windowSize { + windowHeap := dtm.newSizedUpHeap(windowSize) + + for windowHeap.len() <= windowSize && currentGHOSTDAGData.SelectedParent() != nil { + added, err := windowHeap.tryPush(currentGHOSTDAGData.SelectedParent()) + if err != nil { + return nil, err + } + + // If the window is full and the selected parent is less than the minimum then we break + // because this means that there cannot be any more blocks in the past with higher blueWork + if !added { + break + } + + // Now we go over the merge set. + // Remove the SP from the blue merge set because we already added it. + mergeSetBlues := currentGHOSTDAGData.MergeSetBlues()[1:] + // Go over the merge set in reverse because it's ordered in reverse by blueWork. + for i := len(mergeSetBlues) - 1; i >= 0; i-- { + added, err := windowHeap.tryPush(mergeSetBlues[i]) + if err != nil { + return nil, err + } + // If it's smaller than minimum then we won't be able to add the rest because they're even smaller. + if !added { + break + } + } + mergeSetReds := currentGHOSTDAGData.MergeSetReds() + for i := len(mergeSetReds) - 1; i >= 0; i-- { + added, err := windowHeap.tryPush(mergeSetReds[i]) + if err != nil { + return nil, err + } + // If it's smaller than minimum then we won't be able to add the rest because they're even smaller. + if !added { break } } - currentHash = currentGHOSTDAGData.SelectedParent() currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) if err != nil { @@ -30,9 +63,19 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash } } - if uint64(len(window)) < windowSize { + // a heap is not a sorted list, and the interface promises to be sorted so we now need to sort this + sort.Slice(windowHeap.impl.slice, func(i, j int) bool { + return windowHeap.impl.slice[j].less(windowHeap.impl.slice[i], dtm.ghostdagManager) + }) + + window := make([]*externalapi.DomainHash, 0, windowSize) + for _, b := range windowHeap.impl.slice { + window = append(window, b.hash) + } + + if len(window) < windowSize { genesis := currentHash - for uint64(len(window)) < windowSize { + for len(window) < windowSize { window = append(window, genesis) } } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 782616e5f..f22af38dd 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -56,37 +56,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, }, }, "kaspa-testnet": { @@ -128,37 +128,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, }, }, "kaspa-devnet": { @@ -200,37 +200,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "D", "B", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "B", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "B"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, }, }, "kaspa-simnet": { @@ -272,37 +272,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "C", "B", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "H", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "B", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "H", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "H", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "H", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "H", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "B"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"}, }, }, } @@ -315,7 +315,7 @@ func TestBlueBlockWindow(t *testing.T) { } defer tearDown() - windowSize := uint64(10) + windowSize := 10 blockByIDMap := make(map[string]*externalapi.DomainHash) idByBlockMap := make(map[externalapi.DomainHash]string) blockByIDMap["A"] = params.GenesisHash diff --git a/domain/consensus/processes/difficultymanager/blockwindow.go b/domain/consensus/processes/difficultymanager/blockwindow.go index 520f8268a..4d25cab01 100644 --- a/domain/consensus/processes/difficultymanager/blockwindow.go +++ b/domain/consensus/processes/difficultymanager/blockwindow.go @@ -32,7 +32,7 @@ func (dm *difficultyManager) getDifficultyBlock(blockHash *externalapi.DomainHas // blues in the past of startindNode, sorted by GHOSTDAG order. // If the number of blues in the past of startingNode is less then windowSize, // the window will be padded by genesis blocks to achieve a size of windowSize. -func (dm *difficultyManager) blueBlockWindow(startingNode *externalapi.DomainHash, windowSize uint64) (blockWindow, error) { +func (dm *difficultyManager) blueBlockWindow(startingNode *externalapi.DomainHash, windowSize int) (blockWindow, error) { window := make(blockWindow, 0, windowSize) windowHashes, err := dm.dagTraversalManager.BlueWindow(startingNode, windowSize) if err != nil { diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index 058225bc9..c1e028562 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -21,7 +21,7 @@ type difficultyManager struct { dagTraversalManager model.DAGTraversalManager genesisHash *externalapi.DomainHash powMax *big.Int - difficultyAdjustmentWindowSize uint64 + difficultyAdjustmentWindowSize int disableDifficultyAdjustment bool targetTimePerBlock time.Duration } @@ -34,7 +34,7 @@ func New(databaseContext model.DBReader, dagTopologyManager model.DAGTopologyManager, dagTraversalManager model.DAGTraversalManager, powMax *big.Int, - difficultyAdjustmentWindowSize uint64, + difficultyAdjustmentWindowSize int, disableDifficultyAdjustment bool, targetTimePerBlock time.Duration, genesisHash *externalapi.DomainHash) model.DifficultyManager { @@ -95,7 +95,7 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas } // Not enough blocks for building a difficulty window. - if bluestGhostDAG.BlueScore() < dm.difficultyAdjustmentWindowSize+1 { + if bluestGhostDAG.BlueScore() < uint64(dm.difficultyAdjustmentWindowSize)+1 { return dm.genesisBits() } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index b938cab6c..0714e58a6 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -86,14 +86,14 @@ func TestDifficulty(t *testing.T) { tipHash := params.GenesisHash tip := params.GenesisBlock - for i := uint64(0); i < params.DifficultyAdjustmentWindowSize; i++ { + for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ { tip, tipHash = addBlock(0, tipHash) if tip.Header.Bits != params.GenesisBlock.Header.Bits { t.Fatalf("As long as the bluest parent's blue score is less then the difficulty adjustment " + "window size, the difficulty should be the same as genesis'") } } - for i := uint64(0); i < params.DifficultyAdjustmentWindowSize+100; i++ { + for i := 0; i < params.DifficultyAdjustmentWindowSize+100; i++ { tip, tipHash = addBlock(0, tipHash) if tip.Header.Bits != params.GenesisBlock.Header.Bits { t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change") @@ -130,7 +130,7 @@ func TestDifficulty(t *testing.T) { } // Increase block rate to increase difficulty - for i := uint64(0); i < params.DifficultyAdjustmentWindowSize; i++ { + for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ { tip, tipHash = addBlockWithMinimumTime(tipHash) tipGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), tipHash) if err != nil { @@ -150,7 +150,7 @@ func TestDifficulty(t *testing.T) { // Add blocks until difficulty stabilizes lastBits := tip.Header.Bits - sameBitsCount := uint64(0) + sameBitsCount := 0 for sameBitsCount < params.DifficultyAdjustmentWindowSize+1 { tip, tipHash = addBlock(0, tipHash) if tip.Header.Bits == lastBits { diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go index 5d29206ce..fc496bbf3 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go @@ -11,7 +11,7 @@ import ( // pastMedianTimeManager provides a method to resolve the // past median time of a block type pastMedianTimeManager struct { - timestampDeviationTolerance uint64 + timestampDeviationTolerance int databaseContext model.DBReader @@ -22,7 +22,7 @@ type pastMedianTimeManager struct { } // New instantiates a new PastMedianTimeManager -func New(timestampDeviationTolerance uint64, +func New(timestampDeviationTolerance int, databaseContext model.DBReader, dagTraversalManager model.DAGTraversalManager, blockHeaderStore model.BlockHeaderStore, diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 70a2c8596..acb701709 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -98,11 +98,11 @@ type Params struct { // TimestampDeviationTolerance is the maximum offset a block timestamp // is allowed to be in the future before it gets delayed - TimestampDeviationTolerance uint64 + TimestampDeviationTolerance int // DifficultyAdjustmentWindowSize is the size of window that is inspected // to calculate the required difficulty of each block. - DifficultyAdjustmentWindowSize uint64 + DifficultyAdjustmentWindowSize int // These fields are related to voting on consensus rule changes as // defined by BIP0009. diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index b6b4828ed..4ec22a74e 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -39,8 +39,8 @@ type overrideDAGParamsConfig struct { SubsidyReductionInterval *uint64 `json:"subsidyReductionInterval"` TargetTimePerBlockInMilliSeconds *int64 `json:"targetTimePerBlockInMilliSeconds"` FinalityDuration *int64 `json:"finalityDuration"` - TimestampDeviationTolerance *uint64 `json:"timestampDeviationTolerance"` - DifficultyAdjustmentWindowSize *uint64 `json:"difficultyAdjustmentWindowSize"` + TimestampDeviationTolerance *int `json:"timestampDeviationTolerance"` + DifficultyAdjustmentWindowSize *int `json:"difficultyAdjustmentWindowSize"` RelayNonStdTxs *bool `json:"relayNonStdTxs"` AcceptUnroutable *bool `json:"acceptUnroutable"` EnableNonNativeSubnetworks *bool `json:"enableNonNativeSubnetworks"` From d90e18ec513780e00e75edb67ac5ebafd1c84037 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 7 Dec 2020 02:39:40 -0800 Subject: [PATCH 117/351] Fix v0.8.2-dev build (#1189) --- domain/consensus/processes/blockvalidator/blockvalidator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 686bbf7a6..09c5621aa 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -20,7 +20,7 @@ type blockValidator struct { maxBlockSize uint64 mergeSetSizeLimit uint64 maxBlockParents model.KType - timestampDeviationTolerance uint64 + timestampDeviationTolerance int targetTimePerBlock time.Duration databaseContext model.DBReader @@ -48,7 +48,7 @@ func New(powMax *big.Int, maxBlockSize uint64, mergeSetSizeLimit uint64, maxBlockParents model.KType, - timestampDeviationTolerance uint64, + timestampDeviationTolerance int, targetTimePerBlock time.Duration, databaseContext model.DBReader, From 37bf261da1c7145c2b6c7215b8456da752dcd0e9 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 7 Dec 2020 14:18:33 +0200 Subject: [PATCH 118/351] [NOD-1581] Enable fsync in database writes (#1168) --- infrastructure/db/database/ldb/transaction.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/db/database/ldb/transaction.go b/infrastructure/db/database/ldb/transaction.go index df612f3be..5271ed717 100644 --- a/infrastructure/db/database/ldb/transaction.go +++ b/infrastructure/db/database/ldb/transaction.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/opt" ) // LevelDBTransaction is a thin wrapper around native leveldb @@ -53,7 +54,7 @@ func (tx *LevelDBTransaction) Commit() error { tx.isClosed = true tx.snapshot.Release() - return errors.WithStack(tx.db.ldb.Write(tx.batch, nil)) + return errors.WithStack(tx.db.ldb.Write(tx.batch, &opt.WriteOptions{Sync: true})) } // Rollback rolls back whatever changes were made to the From b7ca3f44614ed548acd790d1c5cdd57d5b517183 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 8 Dec 2020 10:26:39 +0200 Subject: [PATCH 119/351] [NOD-1590] Implement optimized finalityPoint calculation mechanism (#1190) * [NOD-1590] Moved all finality logic to FinalityManager * [NOD-1590] Add finality store * [NOD-1590] Implement optimized finalityPoint calculation mechanism * [NOD-1590] Add comments * [NOD-1590] Add finalityStore to consensus object, and TestConsensus * [NOD-1590] Added logs to finalityPoint calculation --- domain/consensus/consensus.go | 2 + .../finalitystore/finality_store.go | 78 ++++++++++ domain/consensus/factory.go | 30 +++- domain/consensus/finality_test.go | 6 +- .../interface_datastructures_finalitystore.go | 13 ++ .../interface_processes_dagtopologymanager.go | 1 + .../interface_processes_finalitymanager.go | 10 ++ .../interface_processes_reachabilitytree.go | 1 + .../consensus/model/testapi/test_consensus.go | 1 + .../testapi/test_consensus_state_manager.go | 1 - .../blockprocessor/blockprocessor.go | 7 +- .../blockprocessor/validateandinsertblock.go | 12 -- .../blockvalidator/block_header_in_context.go | 15 ++ .../blockvalidator/blockvalidator.go | 29 ++-- .../check_finality_violation.go | 24 +++ .../consensus_state_manager.go | 8 +- .../consensusstatemanager/finality.go | 71 --------- .../pick_virtual_parents.go | 2 +- .../test_consensus_state_manager.go | 4 - .../dagtopologymanager/dagtopologymanager.go | 39 ++++- .../finalitymanager/finality_manager.go | 144 ++++++++++++++++++ .../processes/finalitymanager/log.go | 7 + .../ghostdagmanager/ghostdag_test.go | 9 +- .../mergedepthmanager/merge_depth_manager.go | 16 +- .../processes/reachabilitymanager/tree.go | 14 +- domain/consensus/test_consensus_getters.go | 8 + 26 files changed, 418 insertions(+), 134 deletions(-) create mode 100644 domain/consensus/datastructures/finalitystore/finality_store.go create mode 100644 domain/consensus/model/interface_datastructures_finalitystore.go create mode 100644 domain/consensus/model/interface_processes_finalitymanager.go create mode 100644 domain/consensus/processes/consensusstatemanager/check_finality_violation.go delete mode 100644 domain/consensus/processes/consensusstatemanager/finality.go create mode 100644 domain/consensus/processes/finalitymanager/finality_manager.go create mode 100644 domain/consensus/processes/finalitymanager/log.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 4d16e5a37..7e49e8abf 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -29,6 +29,7 @@ type consensus struct { mergeDepthManager model.MergeDepthManager pruningManager model.PruningManager reachabilityManager model.ReachabilityManager + finalityManager model.FinalityManager acceptanceDataStore model.AcceptanceDataStore blockStore model.BlockStore @@ -42,6 +43,7 @@ type consensus struct { multisetStore model.MultisetStore reachabilityDataStore model.ReachabilityDataStore utxoDiffStore model.UTXODiffStore + finalityStore model.FinalityStore } // BuildBlock builds a block over the current state, with the transactions diff --git a/domain/consensus/datastructures/finalitystore/finality_store.go b/domain/consensus/datastructures/finalitystore/finality_store.go new file mode 100644 index 000000000..4cd34e35c --- /dev/null +++ b/domain/consensus/datastructures/finalitystore/finality_store.go @@ -0,0 +1,78 @@ +package finalitystore + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" +) + +var bucket = dbkeys.MakeBucket([]byte("finality-points")) + +type finalityStore struct { + staging map[externalapi.DomainHash]*externalapi.DomainHash + toDelete map[externalapi.DomainHash]struct{} + cache *lrucache.LRUCache +} + +// New instantiates a new FinalityStore +func New(cacheSize int) model.FinalityStore { + return &finalityStore{ + staging: make(map[externalapi.DomainHash]*externalapi.DomainHash), + toDelete: make(map[externalapi.DomainHash]struct{}), + cache: lrucache.New(cacheSize), + } +} + +func (fs *finalityStore) StageFinalityPoint(blockHash *externalapi.DomainHash, finalityPointHash *externalapi.DomainHash) { + fs.staging[*blockHash] = finalityPointHash +} + +func (fs *finalityStore) FinalityPoint( + dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + if finalityPointHash, ok := fs.staging[*blockHash]; ok { + return finalityPointHash, nil + } + + if finalityPointHash, ok := fs.cache.Get(blockHash); ok { + return finalityPointHash.(*externalapi.DomainHash), nil + } + + finalityPointHashBytes, err := dbContext.Get(fs.hashAsKey(blockHash)) + if err != nil { + return nil, err + } + finalityPointHash, err := hashes.FromBytes(finalityPointHashBytes) + if err != nil { + return nil, err + } + + fs.cache.Add(blockHash, finalityPointHash) + return finalityPointHash, nil +} + +func (fs *finalityStore) Discard() { + fs.staging = make(map[externalapi.DomainHash]*externalapi.DomainHash) +} + +func (fs *finalityStore) Commit(dbTx model.DBTransaction) error { + for hash, finalityPointHash := range fs.staging { + err := dbTx.Put(fs.hashAsKey(&hash), finalityPointHash[:]) + if err != nil { + return err + } + fs.cache.Add(&hash, finalityPointHash) + } + + fs.Discard() + return nil +} + +func (fs *finalityStore) IsStaged() bool { + return len(fs.staging) == 0 +} + +func (fs *finalityStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { + return bucket.Key(hash[:]) +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index ddcd183b7..ee8f93414 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,12 +1,12 @@ package consensus import ( - "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" "io/ioutil" "os" "sync" - "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" + "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" + "github.com/kaspanet/kaspad/domain/consensus/processes/finalitymanager" consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore" @@ -15,6 +15,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/datastructures/blockstatusstore" "github.com/kaspanet/kaspad/domain/consensus/datastructures/blockstore" "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/multisetstore" @@ -40,6 +41,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/processes/transactionvalidator" "github.com/kaspanet/kaspad/domain/dagconfig" infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" ) // Factory instantiates new Consensuses @@ -80,6 +82,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat consensusStateStore := consensusstatestore.New() ghostdagDataStore := ghostdagdatastore.New(10_000) headerTipsStore := headertipsstore.New() + finalityStore := finalitystore.New(200) // Processes reachabilityManager := reachabilitymanager.New( @@ -89,7 +92,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTopologyManager := dagtopologymanager.New( dbManager, reachabilityManager, - blockRelationStore) + blockRelationStore, + ghostdagDataStore) ghostdagManager := ghostdagmanager.New( dbManager, dagTopologyManager, @@ -137,11 +141,18 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat acceptanceDataStore) headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore) genesisHash := dagParams.GenesisHash + finalityManager := finalitymanager.New( + dbManager, + dagTopologyManager, + finalityStore, + ghostdagDataStore, + genesisHash, + dagParams.FinalityDepth()) mergeDepthManager := mergedepthmanager.New( - dagParams.FinalityDepth(), dbManager, dagTopologyManager, dagTraversalManager, + finalityManager, ghostdagDataStore) blockValidator := blockvalidator.New( dagParams.PowMax, @@ -163,16 +174,17 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTraversalManager, coinbaseManager, mergeDepthManager, - pruningStore, + reachabilityManager, + pruningStore, blockStore, ghostdagDataStore, blockHeaderStore, blockStatusStore, + reachabilityDataStore, ) consensusStateManager, err := consensusstatemanager.New( dbManager, - dagParams.FinalityDepth(), dagParams.PruningDepth(), dagParams.MaxMassAcceptedByBlock, dagParams.MaxBlockParents, @@ -188,6 +200,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat reachabilityManager, coinbaseManager, mergeDepthManager, + finalityManager, blockStatusStore, ghostdagDataStore, @@ -274,7 +287,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat reachabilityDataStore, utxoDiffStore, blockHeaderStore, - headerTipsStore) + headerTipsStore, + finalityStore) c := &consensus{ lock: &sync.Mutex{}, @@ -296,6 +310,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat mergeDepthManager: mergeDepthManager, pruningManager: pruningManager, reachabilityManager: reachabilityManager, + finalityManager: finalityManager, acceptanceDataStore: acceptanceDataStore, blockStore: blockStore, @@ -309,6 +324,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat multisetStore: multisetStore, reachabilityDataStore: reachabilityDataStore, utxoDiffStore: utxoDiffStore, + finalityStore: finalityStore, } genesisInfo, err := c.GetBlockInfo(genesisHash) diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 856a02dce..8eb2c8732 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -47,13 +47,13 @@ func TestFinality(t *testing.T) { for i := uint64(0); i < finalityInterval-1; i++ { mainChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{mainChainTipHash}) if err != nil { - t.Fatalf("TestFinality: Failed to process Block #%d: %v", i, err) + t.Fatalf("TestFinality: Failed to process Block #%d: %+v", i, err) } mainChainTipHash = consensushashing.BlockHash(mainChainTip) blockInfo, err := consensus.GetBlockInfo(mainChainTipHash) if err != nil { - t.Fatalf("TestFinality: Block #%d failed to get info: %v", i, err) + t.Fatalf("TestFinality: Block #%d failed to get info: %+v", i, err) } if blockInfo.BlockStatus != externalapi.StatusValid { t.Fatalf("Block #%d in main chain expected to have status '%s', but got '%s'", @@ -120,7 +120,7 @@ func TestFinality(t *testing.T) { mainChainTipHash = consensushashing.BlockHash(mainChainTip) } - virtualFinality, err := consensus.ConsensusStateManager().VirtualFinalityPoint() + virtualFinality, err := consensus.FinalityManager().VirtualFinalityPoint() if err != nil { t.Fatalf("TestFinality: Failed getting the virtual's finality point: %v", err) } diff --git a/domain/consensus/model/interface_datastructures_finalitystore.go b/domain/consensus/model/interface_datastructures_finalitystore.go new file mode 100644 index 000000000..52b11b3d9 --- /dev/null +++ b/domain/consensus/model/interface_datastructures_finalitystore.go @@ -0,0 +1,13 @@ +package model + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// FinalityStore represents a store for finality data +type FinalityStore interface { + Store + IsStaged() bool + StageFinalityPoint(blockHash *externalapi.DomainHash, finalityPointHash *externalapi.DomainHash) + FinalityPoint(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) +} diff --git a/domain/consensus/model/interface_processes_dagtopologymanager.go b/domain/consensus/model/interface_processes_dagtopologymanager.go index 7e93e89e0..bb49f7928 100644 --- a/domain/consensus/model/interface_processes_dagtopologymanager.go +++ b/domain/consensus/model/interface_processes_dagtopologymanager.go @@ -13,6 +13,7 @@ type DAGTopologyManager interface { IsDescendantOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) IsAncestorOfAny(blockHash *externalapi.DomainHash, potentialDescendants []*externalapi.DomainHash) (bool, error) IsInSelectedParentChainOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) + ChildInSelectedParentChainOf(context, highHash *externalapi.DomainHash) (*externalapi.DomainHash, error) SetParents(blockHash *externalapi.DomainHash, parentHashes []*externalapi.DomainHash) error } diff --git a/domain/consensus/model/interface_processes_finalitymanager.go b/domain/consensus/model/interface_processes_finalitymanager.go new file mode 100644 index 000000000..c58a5c339 --- /dev/null +++ b/domain/consensus/model/interface_processes_finalitymanager.go @@ -0,0 +1,10 @@ +package model + +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) +} diff --git a/domain/consensus/model/interface_processes_reachabilitytree.go b/domain/consensus/model/interface_processes_reachabilitytree.go index 47284dae6..e2bbbd7fc 100644 --- a/domain/consensus/model/interface_processes_reachabilitytree.go +++ b/domain/consensus/model/interface_processes_reachabilitytree.go @@ -9,4 +9,5 @@ type ReachabilityManager interface { IsReachabilityTreeAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) IsDAGAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) UpdateReindexRoot(selectedTip *externalapi.DomainHash) error + FindAncestorOfThisAmongChildrenOfOther(this, other *externalapi.DomainHash) (*externalapi.DomainHash, error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 9bf365e9e..9800400ab 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -41,6 +41,7 @@ type TestConsensus interface { BlockValidator() model.BlockValidator CoinbaseManager() model.CoinbaseManager ConsensusStateManager() TestConsensusStateManager + FinalityManager() model.FinalityManager DAGTopologyManager() model.DAGTopologyManager DAGTraversalManager() model.DAGTraversalManager DifficultyManager() model.DifficultyManager diff --git a/domain/consensus/model/testapi/test_consensus_state_manager.go b/domain/consensus/model/testapi/test_consensus_state_manager.go index 251eae8a5..b2f30aa17 100644 --- a/domain/consensus/model/testapi/test_consensus_state_manager.go +++ b/domain/consensus/model/testapi/test_consensus_state_manager.go @@ -11,5 +11,4 @@ type TestConsensusStateManager interface { AddUTXOToMultiset(multiset model.Multiset, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) - VirtualFinalityPoint() (*externalapi.DomainHash, error) } diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index 3acb04cf8..e3e9ed460 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -36,6 +36,7 @@ type blockProcessor struct { utxoDiffStore model.UTXODiffStore blockHeaderStore model.BlockHeaderStore headerTipsStore model.HeaderTipsStore + finalityStore model.FinalityStore stores []model.Store } @@ -67,7 +68,9 @@ func New( reachabilityDataStore model.ReachabilityDataStore, utxoDiffStore model.UTXODiffStore, blockHeaderStore model.BlockHeaderStore, - headerTipsStore model.HeaderTipsStore) model.BlockProcessor { + headerTipsStore model.HeaderTipsStore, + finalityStore model.FinalityStore, +) model.BlockProcessor { return &blockProcessor{ genesisHash: genesisHash, @@ -96,6 +99,7 @@ func New( utxoDiffStore: utxoDiffStore, blockHeaderStore: blockHeaderStore, headerTipsStore: headerTipsStore, + finalityStore: finalityStore, stores: []model.Store{ consensusStateStore, @@ -111,6 +115,7 @@ func New( utxoDiffStore, blockHeaderStore, headerTipsStore, + finalityStore, }, } } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 35f845469..0cdff5ec7 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -40,18 +40,6 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) return err } - hasHeader, err := bp.hasHeader(blockHash) - if err != nil { - return err - } - - if !hasHeader { - err = bp.reachabilityManager.AddBlock(blockHash) - if err != nil { - return err - } - } - if insertMode == insertModeHeader { bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) } else { diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index cc2aa156a..0d2f3fdfc 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -37,6 +37,21 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa return err } + // If needed - calculate reachability data right before calling CheckBoundedMergeDepth, + // since it's used to find a block's finality point. + // This might not be required if this block's header has previously been received during + // headers-first synchronization. + hasReachabilityData, err := v.reachabilityStore.HasReachabilityData(v.databaseContext, blockHash) + if err != nil { + return err + } + if !hasReachabilityData { + err = v.reachabilityManager.AddBlock(blockHash) + if err != nil { + return err + } + } + err = v.mergeDepthManager.CheckBoundedMergeDepth(blockHash) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index 09c5621aa..bb5bf40af 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -33,11 +33,13 @@ type blockValidator struct { coinbaseManager model.CoinbaseManager mergeDepthManager model.MergeDepthManager pruningStore model.PruningStore + reachabilityManager model.ReachabilityManager blockStore model.BlockStore ghostdagDataStore model.GHOSTDAGDataStore blockHeaderStore model.BlockHeaderStore blockStatusStore model.BlockStatusStore + reachabilityStore model.ReachabilityDataStore } // New instantiates a new BlockValidator @@ -61,22 +63,27 @@ func New(powMax *big.Int, dagTraversalManager model.DAGTraversalManager, coinbaseManager model.CoinbaseManager, mergeDepthManager model.MergeDepthManager, + reachabilityManager model.ReachabilityManager, + pruningStore model.PruningStore, blockStore model.BlockStore, ghostdagDataStore model.GHOSTDAGDataStore, blockHeaderStore model.BlockHeaderStore, - blockStatusStore model.BlockStatusStore) model.BlockValidator { + blockStatusStore model.BlockStatusStore, + reachabilityStore model.ReachabilityDataStore, +) model.BlockValidator { return &blockValidator{ - powMax: powMax, - skipPoW: skipPoW, - genesisHash: genesisHash, - enableNonNativeSubnetworks: enableNonNativeSubnetworks, - powMaxBits: util.BigToCompact(powMax), - maxBlockSize: maxBlockSize, - mergeSetSizeLimit: mergeSetSizeLimit, - maxBlockParents: maxBlockParents, + powMax: powMax, + skipPoW: skipPoW, + genesisHash: genesisHash, + enableNonNativeSubnetworks: enableNonNativeSubnetworks, + powMaxBits: util.BigToCompact(powMax), + maxBlockSize: maxBlockSize, + mergeSetSizeLimit: mergeSetSizeLimit, + maxBlockParents: maxBlockParents, + timestampDeviationTolerance: timestampDeviationTolerance, targetTimePerBlock: targetTimePerBlock, databaseContext: databaseContext, @@ -88,11 +95,13 @@ func New(powMax *big.Int, dagTraversalManager: dagTraversalManager, coinbaseManager: coinbaseManager, mergeDepthManager: mergeDepthManager, - pruningStore: pruningStore, + reachabilityManager: reachabilityManager, + pruningStore: pruningStore, blockStore: blockStore, ghostdagDataStore: ghostdagDataStore, blockHeaderStore: blockHeaderStore, blockStatusStore: blockStatusStore, + reachabilityStore: reachabilityStore, } } diff --git a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go new file mode 100644 index 000000000..c8c9e022e --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go @@ -0,0 +1,24 @@ +package consensusstatemanager + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +func (csm *consensusStateManager) checkFinalityViolation( + blockHash *externalapi.DomainHash) error { + + log.Tracef("checkFinalityViolation start for block %s", blockHash) + defer log.Tracef("checkFinalityViolation end for block %s", blockHash) + + isViolatingFinality, err := csm.finalityManager.IsViolatingFinality(blockHash) + if err != nil { + return err + } + + if isViolatingFinality { + csm.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) + log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash) + return nil + } + log.Tracef("Block %s does not violate finality", blockHash) + + return nil +} diff --git a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go index 01cb3b320..c0c8ab738 100644 --- a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go @@ -7,7 +7,6 @@ import ( // consensusStateManager manages the node's consensus state type consensusStateManager struct { - finalityDepth uint64 pruningDepth uint64 maxMassAcceptedByBlock uint64 maxBlockParents model.KType @@ -24,8 +23,9 @@ type consensusStateManager struct { reachabilityManager model.ReachabilityManager coinbaseManager model.CoinbaseManager mergeDepthManager model.MergeDepthManager - headerTipsStore model.HeaderTipsStore + finalityManager model.FinalityManager + headerTipsStore model.HeaderTipsStore blockStatusStore model.BlockStatusStore ghostdagDataStore model.GHOSTDAGDataStore consensusStateStore model.ConsensusStateStore @@ -42,7 +42,6 @@ type consensusStateManager struct { // New instantiates a new ConsensusStateManager func New( databaseContext model.DBManager, - finalityDepth uint64, pruningDepth uint64, maxMassAcceptedByBlock uint64, maxBlockParents model.KType, @@ -58,6 +57,7 @@ func New( reachabilityManager model.ReachabilityManager, coinbaseManager model.CoinbaseManager, mergeDepthManager model.MergeDepthManager, + finalityManager model.FinalityManager, blockStatusStore model.BlockStatusStore, ghostdagDataStore model.GHOSTDAGDataStore, @@ -71,7 +71,6 @@ func New( headerTipsStore model.HeaderTipsStore) (model.ConsensusStateManager, error) { csm := &consensusStateManager{ - finalityDepth: finalityDepth, pruningDepth: pruningDepth, maxMassAcceptedByBlock: maxMassAcceptedByBlock, maxBlockParents: maxBlockParents, @@ -88,6 +87,7 @@ func New( reachabilityManager: reachabilityManager, coinbaseManager: coinbaseManager, mergeDepthManager: mergeDepthManager, + finalityManager: finalityManager, multisetStore: multisetStore, blockStore: blockStore, diff --git a/domain/consensus/processes/consensusstatemanager/finality.go b/domain/consensus/processes/consensusstatemanager/finality.go deleted file mode 100644 index 88c77612e..000000000 --- a/domain/consensus/processes/consensusstatemanager/finality.go +++ /dev/null @@ -1,71 +0,0 @@ -package consensusstatemanager - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -func (csm *consensusStateManager) checkFinalityViolation( - blockHash *externalapi.DomainHash) error { - - log.Tracef("checkFinalityViolation start for block %s", blockHash) - defer log.Tracef("checkFinalityViolation end for block %s", blockHash) - - if *blockHash == *csm.genesisHash { - log.Tracef("Block %s is the genesis block, "+ - "and does not violate finality by definition", blockHash) - return nil - } - - isViolatingFinality, err := csm.isViolatingFinality(blockHash) - if err != nil { - return err - } - - if isViolatingFinality { - csm.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) - log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash) - return nil - } - log.Tracef("Block %s does not violate finality", blockHash) - - return nil -} - -func (csm *consensusStateManager) virtualFinalityPoint() ( - *externalapi.DomainHash, error) { - - log.Tracef("virtualFinalityPoint start") - defer log.Tracef("virtualFinalityPoint end") - - virtualFinalityPoint, err := csm.dagTraversalManager.BlockAtDepth( - model.VirtualBlockHash, csm.finalityDepth) - if err != nil { - return nil, err - } - log.Tracef("The current virtual finality block is: %s", virtualFinalityPoint) - - return virtualFinalityPoint, nil -} - -func (csm *consensusStateManager) isViolatingFinality( - blockHash *externalapi.DomainHash) (bool, error) { - - log.Tracef("isViolatingFinality start for block %s", blockHash) - defer log.Tracef("isViolatingFinality end for block %s", blockHash) - - virtualFinalityPoint, err := csm.virtualFinalityPoint() - if err != nil { - return false, err - } - log.Tracef("The virtual finality point is: %s", virtualFinalityPoint) - - isInSelectedParentChain, err := csm.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 -} diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 84af3bf63..c85f03892 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -202,7 +202,7 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( } log.Tracef("The potentially kosherizing blocks are: %s", potentiallyKosherizingBlocks) - virtualFinalityPoint, err := csm.virtualFinalityPoint() + virtualFinalityPoint, err := csm.finalityManager.VirtualFinalityPoint() if err != nil { return nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go index e10edc826..8efc08d84 100644 --- a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -24,7 +24,3 @@ func (csm testConsensusStateManager) AddUTXOToMultiset( func (csm testConsensusStateManager) ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { return csm.resolveBlockStatus(blockHash) } - -func (csm testConsensusStateManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) { - return csm.virtualFinalityPoint() -} diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index f939a7ec3..245fbfb13 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -3,6 +3,7 @@ package dagtopologymanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" ) // dagTopologyManager exposes methods for querying relationships @@ -10,6 +11,7 @@ import ( type dagTopologyManager struct { reachabilityManager model.ReachabilityManager blockRelationStore model.BlockRelationStore + ghostdagStore model.GHOSTDAGDataStore databaseContext model.DBReader } @@ -17,12 +19,14 @@ type dagTopologyManager struct { func New( databaseContext model.DBReader, reachabilityManager model.ReachabilityManager, - blockRelationStore model.BlockRelationStore) model.DAGTopologyManager { + blockRelationStore model.BlockRelationStore, + ghostdagStore model.GHOSTDAGDataStore) model.DAGTopologyManager { return &dagTopologyManager{ databaseContext: databaseContext, reachabilityManager: reachabilityManager, blockRelationStore: blockRelationStore, + ghostdagStore: ghostdagStore, } } @@ -160,3 +164,36 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par return nil } + +// ChildInSelectedParentChainOf returns the child of `context` that is in the selected-parent-chain of `highHash` +func (dtm *dagTopologyManager) ChildInSelectedParentChainOf( + blockHash, highHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + + // Virtual doesn't have reachability data, therefore, it should be treated as a special case - + // use it's selected parent as highHash. + specifiedHighHash := highHash + if highHash == model.VirtualBlockHash { + ghostdagData, err := dtm.ghostdagStore.Get(dtm.databaseContext, highHash) + if err != nil { + return nil, err + } + selectedParent := ghostdagData.SelectedParent() + + // In case where `blockHash` is an immediate parent of `highHash` + if *blockHash == *selectedParent { + return highHash, nil + } + highHash = selectedParent + } + + isInSelectedParentChain, err := dtm.IsInSelectedParentChainOf(blockHash, highHash) + if err != nil { + return nil, err + } + if !isInSelectedParentChain { + return nil, errors.Errorf("blockHash(%s) is not in the selected-parent-chain of highHash(%s)", + blockHash, specifiedHighHash) + } + + return dtm.reachabilityManager.FindAncestorOfThisAmongChildrenOfOther(highHash, blockHash) +} diff --git a/domain/consensus/processes/finalitymanager/finality_manager.go b/domain/consensus/processes/finalitymanager/finality_manager.go new file mode 100644 index 000000000..7fd8cf30e --- /dev/null +++ b/domain/consensus/processes/finalitymanager/finality_manager.go @@ -0,0 +1,144 @@ +package finalitymanager + +import ( + "errors" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/infrastructure/db/database" +) + +type finalityManager struct { + databaseContext model.DBReader + dagTopologyManager model.DAGTopologyManager + finalityStore model.FinalityStore + ghostdagDataStore model.GHOSTDAGDataStore + genesisHash *externalapi.DomainHash + finalityDepth uint64 +} + +// New instantiates a new FinalityManager +func New(databaseContext model.DBReader, + dagTopologyManager model.DAGTopologyManager, + finalityStore model.FinalityStore, + ghostdagDataStore model.GHOSTDAGDataStore, + genesisHash *externalapi.DomainHash, + finalityDepth uint64) model.FinalityManager { + + return &finalityManager{ + databaseContext: databaseContext, + genesisHash: genesisHash, + dagTopologyManager: dagTopologyManager, + finalityStore: finalityStore, + ghostdagDataStore: ghostdagDataStore, + finalityDepth: finalityDepth, + } +} + +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") + + virtualFinalityPoint, err := fm.calculateFinalityPoint(model.VirtualBlockHash) + if err != nil { + return nil, err + } + log.Tracef("The current virtual finality block is: %s", virtualFinalityPoint) + + return virtualFinalityPoint, nil +} + +func (fm *finalityManager) FinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + log.Tracef("FinalityPoint start") + defer log.Tracef("FinalityPoint end") + if *blockHash == *model.VirtualBlockHash { + return fm.VirtualFinalityPoint() + } + finalityPoint, err := fm.finalityStore.FinalityPoint(fm.databaseContext, blockHash) + if err != nil { + log.Tracef("%s finality point not found in store - calculating", blockHash) + if errors.Is(err, database.ErrNotFound) { + return fm.calculateAndStageFinalityPoint(blockHash) + } + return nil, err + } + return finalityPoint, nil +} + +func (fm *finalityManager) calculateAndStageFinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + finalityPoint, err := fm.calculateFinalityPoint(blockHash) + if err != nil { + return nil, err + } + fm.finalityStore.StageFinalityPoint(blockHash, finalityPoint) + return finalityPoint, nil +} + +func (fm *finalityManager) calculateFinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + log.Tracef("calculateFinalityPoint start") + defer log.Tracef("calculateFinalityPoint end") + ghostdagData, err := fm.ghostdagDataStore.Get(fm.databaseContext, blockHash) + if err != nil { + return nil, err + } + + if ghostdagData.BlueScore() < fm.finalityDepth { + log.Tracef("%s blue score lower then finality depth - returning genesis as finality point", blockHash) + return fm.genesisHash, nil + } + + selectedParent := ghostdagData.SelectedParent() + if *selectedParent == *fm.genesisHash { + return fm.genesisHash, nil + } + + current, err := fm.finalityStore.FinalityPoint(fm.databaseContext, ghostdagData.SelectedParent()) + if err != nil { + return nil, err + } + requiredBlueScore := ghostdagData.BlueScore() - fm.finalityDepth + log.Tracef("%s's finality point is the one having the highest blue score lower then %d", blockHash, requiredBlueScore) + + var next *externalapi.DomainHash + for { + next, err = fm.dagTopologyManager.ChildInSelectedParentChainOf(current, blockHash) + if err != nil { + return nil, err + } + nextGHOSTDAGData, err := fm.ghostdagDataStore.Get(fm.databaseContext, next) + if err != nil { + return nil, err + } + if nextGHOSTDAGData.BlueScore() >= requiredBlueScore { + log.Tracef("%s's finality point is %s", blockHash, current) + return current, nil + } + + current = next + } +} diff --git a/domain/consensus/processes/finalitymanager/log.go b/domain/consensus/processes/finalitymanager/log.go new file mode 100644 index 000000000..05595b916 --- /dev/null +++ b/domain/consensus/processes/finalitymanager/log.go @@ -0,0 +1,7 @@ +package finalitymanager + +import ( + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +var log, _ = logger.Get(logger.SubsystemTags.BDAG) diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index 49208549a..f41c9cf16 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -2,14 +2,15 @@ package ghostdagmanager_test import ( "encoding/json" - "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" - "github.com/kaspanet/kaspad/util" "math/big" "os" "path/filepath" "reflect" "testing" + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" + "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" @@ -226,6 +227,10 @@ type DAGTopologyManagerImpl struct { parentsMap map[externalapi.DomainHash][]*externalapi.DomainHash } +func (dt *DAGTopologyManagerImpl) ChildInSelectedParentChainOf(context, highHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + panic("implement me") +} + func (dt *DAGTopologyManagerImpl) Tips() ([]*externalapi.DomainHash, error) { panic("implement me") } diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index 155dcd731..66bb72a4e 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -8,27 +8,27 @@ import ( ) type mergeDepthManager struct { - finalityDepth uint64 - databaseContext model.DBReader dagTopologyManager model.DAGTopologyManager dagTraversalManager model.DAGTraversalManager + finalityManager model.FinalityManager ghostdagDataStore model.GHOSTDAGDataStore } // New instantiates a new MergeDepthManager -func New(finalityDepth uint64, +func New( databaseContext model.DBReader, dagTopologyManager model.DAGTopologyManager, dagTraversalManager model.DAGTraversalManager, + finalityManager model.FinalityManager, ghostdagDataStore model.GHOSTDAGDataStore) model.MergeDepthManager { return &mergeDepthManager{ - finalityDepth: finalityDepth, databaseContext: databaseContext, dagTopologyManager: dagTopologyManager, dagTraversalManager: dagTraversalManager, + finalityManager: finalityManager, ghostdagDataStore: ghostdagDataStore, } @@ -50,7 +50,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma return nil } - finalityPoint, err := mdm.finalityPoint(blockHash) + finalityPoint, err := mdm.finalityManager.FinalityPoint(blockHash) if err != nil { return err } @@ -102,14 +102,10 @@ func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exter } func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(this, other *externalapi.DomainHash) (bool, error) { - finalityPoint, err := mdm.finalityPoint(this) + finalityPoint, err := mdm.finalityManager.FinalityPoint(this) if err != nil { return false, err } return mdm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint, other) } - -func (mdm *mergeDepthManager) finalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - return mdm.dagTraversalManager.BlockAtDepth(blockHash, mdm.finalityDepth) -} diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 1dea962ea..054b3836e 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -163,7 +163,7 @@ func (rt *reachabilityManager) addChild(node, child, reindexRoot *externalapi.Do // Temporarily set the child's interval to be empty, at // the start of node's remaining interval. This is done // so that child-of-node checks (e.g. - // findAncestorOfThisAmongChildrenOfOther) will not fail for node. + // FindAncestorOfThisAmongChildrenOfOther) will not fail for node. err = rt.stageInterval(child, newReachabilityInterval(remaining.Start, remaining.Start-1)) if err != nil { return err @@ -411,7 +411,7 @@ func (rt *reachabilityManager) reindexIntervalsEarlierThanReindexRoot(node, // The chosen child is: // a. A reachability tree child of `commonAncestor` // b. A reachability tree ancestor of `reindexRoot` - commonAncestorChosenChild, err := rt.findAncestorOfThisAmongChildrenOfOther(reindexRoot, commonAncestor) + commonAncestorChosenChild, err := rt.FindAncestorOfThisAmongChildrenOfOther(reindexRoot, commonAncestor) if err != nil { return err } @@ -465,7 +465,7 @@ func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAnces break } - current, err = rt.findAncestorOfThisAmongChildrenOfOther(reindexRoot, current) + current, err = rt.FindAncestorOfThisAmongChildrenOfOther(reindexRoot, current) if err != nil { return err } @@ -587,7 +587,7 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces break } - current, err = rt.findAncestorOfThisAmongChildrenOfOther(reindexRoot, current) + current, err = rt.FindAncestorOfThisAmongChildrenOfOther(reindexRoot, current) if err != nil { return err } @@ -799,7 +799,7 @@ func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *ex return commonAncestor, true, nil } - reindexRootChosenChild, err := rt.findAncestorOfThisAmongChildrenOfOther(newTreeNode, reindexRoot) + reindexRootChosenChild, err := rt.FindAncestorOfThisAmongChildrenOfOther(newTreeNode, reindexRoot) if err != nil { return nil, false, err } @@ -826,9 +826,9 @@ func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *ex return reindexRootChosenChild, true, nil } -// findAncestorOfThisAmongChildrenOfOther finds the reachability tree child +// FindAncestorOfThisAmongChildrenOfOther finds the reachability tree child // of node that is the ancestor of node. -func (rt *reachabilityManager) findAncestorOfThisAmongChildrenOfOther(this, other *externalapi.DomainHash) (*externalapi.DomainHash, error) { +func (rt *reachabilityManager) FindAncestorOfThisAmongChildrenOfOther(this, other *externalapi.DomainHash) (*externalapi.DomainHash, error) { otherChildren, err := rt.children(other) if err != nil { return nil, err diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 8a668cc97..539bdcb0b 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -120,3 +120,11 @@ func (tc *testConsensus) SyncManager() model.SyncManager { func (tc *testConsensus) TransactionValidator() testapi.TestTransactionValidator { return tc.testTransactionValidator } + +func (tc *testConsensus) FinalityManager() model.FinalityManager { + return tc.finalityManager +} + +func (tc *testConsensus) FinalityStore() model.FinalityStore { + return tc.finalityStore +} From 82fa8e6831349dc2230c67e2d71e11a016794008 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 8 Dec 2020 17:17:30 +0200 Subject: [PATCH 120/351] Abstract CheckProofOfWork as a public function and change PoW structure (#1198) * Expose CheckProofOfWork from model/pow * Update blockvalidator to call the new CheckProofOfWork * Update genesis blocks * Update tools to use the new CheckProofOfWork * Update tests with new PoW --- cmd/kaspaminer/mineloop.go | 6 +- domain/consensus/model/pow/pow.go | 57 +++++++++++++++ .../processes/blockvalidator/proof_of_work.go | 16 ++--- .../dagtraversalmanager/window_test.go | 72 +++++++++---------- domain/consensus/utils/mining/solve.go | 6 +- domain/dagconfig/genesis.go | 46 ++++++------ testing/integration/mining_test.go | 7 +- 7 files changed, 127 insertions(+), 83 deletions(-) create mode 100644 domain/consensus/model/pow/pow.go diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 26b38dd42..ffe554c78 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -2,13 +2,12 @@ package main import ( nativeerrors "errors" + "github.com/kaspanet/kaspad/domain/consensus/model/pow" "math/rand" "sync" "sync/atomic" "time" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -114,9 +113,8 @@ func solveBlock(block *externalapi.DomainBlock, stopChan chan struct{}, foundBlo return default: block.Header.Nonce = i - hash := consensushashing.BlockHash(block) atomic.AddUint64(&hashesTried, 1) - if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { + if pow.CheckProofOfWorkWithTarget(block.Header, targetDifficulty) { foundBlock <- block return } diff --git a/domain/consensus/model/pow/pow.go b/domain/consensus/model/pow/pow.go new file mode 100644 index 000000000..7ac8b668a --- /dev/null +++ b/domain/consensus/model/pow/pow.go @@ -0,0 +1,57 @@ +package pow + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" + "github.com/kaspanet/kaspad/util" + "github.com/pkg/errors" + "math/big" +) + +// CheckProofOfWorkWithTarget check's if the block has a valid PoW according to the provided target +// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network +func CheckProofOfWorkWithTarget(header *externalapi.DomainBlockHeader, target *big.Int) bool { + // The block pow must be less than the claimed target + powNum := calcPowValue(header) + + // The block hash must be less or equal than the claimed target. + return powNum.Cmp(target) <= 0 +} + +// CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field +// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network +func CheckProofOfWorkByBits(header *externalapi.DomainBlockHeader) bool { + return CheckProofOfWorkWithTarget(header, util.CompactToBig(header.Bits)) +} + +func calcPowValue(header *externalapi.DomainBlockHeader) *big.Int { + // Zero out the time and nonce. + timestamp, nonce := header.TimeInMilliseconds, header.Nonce + header.TimeInMilliseconds, header.Nonce = 0, 0 + + prePowHash := consensushashing.HeaderHash(header) + header.TimeInMilliseconds, header.Nonce = timestamp, nonce + + // PRE_POW_HASH || TIME || 32 zero byte padding || NONCE + writer := hashes.NewHashWriter() + _, err := writer.Write(prePowHash[:]) + if err != nil { + panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + } + err = serialization.WriteElement(writer, timestamp) + if err != nil { + panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + } + zeroes := [32]byte{} + _, err = writer.Write(zeroes[:]) + if err != nil { + panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + } + err = serialization.WriteElement(writer, nonce) + if err != nil { + panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + } + return hashes.ToBig(writer.Finalize()) +} diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index 896818159..8b29c7445 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -2,9 +2,8 @@ package blockvalidator import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "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/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/util" "github.com/pkg/errors" ) @@ -89,18 +88,13 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) "higher than max of %064x", target, v.powMax) } - // The block hash must be less than the claimed target unless the flag - // to avoid proof of work checks is set. + // The block pow must be valid unless the flag to avoid proof of work checks is set. if !v.skipPoW { - // The block hash must be less than the claimed target. - hash := consensushashing.HeaderHash(header) - hashNum := hashes.ToBig(hash) - if hashNum.Cmp(target) > 0 { - return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block hash of %064x is higher than "+ - "expected max of %064x", hashNum, target) + valid := pow.CheckProofOfWorkWithTarget(header, target) + if !valid { + return errors.Wrap(ruleerrors.ErrUnexpectedDifficulty, "block has invalid difficulty") } } - return nil } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index f22af38dd..2f878ceef 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -36,12 +36,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"D", "C"}, id: "E", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"D", "C"}, id: "F", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -56,37 +56,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, }, }, "kaspa-testnet": { @@ -108,12 +108,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"D", "C"}, id: "E", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"D", "C"}, id: "F", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -128,37 +128,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "H", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "H", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "H", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "H", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "H", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"}, }, }, "kaspa-devnet": { @@ -180,12 +180,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"C", "D"}, id: "E", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"C", "D"}, id: "F", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -200,37 +200,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, }, }, "kaspa-simnet": { @@ -252,12 +252,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"C", "D"}, id: "E", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"C", "D"}, id: "F", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -272,37 +272,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "C", "H", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "H", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "H", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "H", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "H", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "H", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "H", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "H", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "H", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "H", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"}, }, }, } diff --git a/domain/consensus/utils/mining/solve.go b/domain/consensus/utils/mining/solve.go index 39b969d2f..f5274f7b0 100644 --- a/domain/consensus/utils/mining/solve.go +++ b/domain/consensus/utils/mining/solve.go @@ -1,12 +1,11 @@ package mining import ( + "github.com/kaspanet/kaspad/domain/consensus/model/pow" "math" "math/rand" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" utilsMath "github.com/kaspanet/kaspad/domain/consensus/utils/math" "github.com/pkg/errors" ) @@ -17,8 +16,7 @@ func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) { for i := rd.Uint64(); i < math.MaxUint64; i++ { block.Header.Nonce = i - hash := consensushashing.BlockHash(block) - if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { + if pow.CheckProofOfWorkWithTarget(block.Header, targetDifficulty) { return } } diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 577e37b49..2b3b1c604 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -28,10 +28,10 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.DomainHash{ - 0xbb, 0xc1, 0x88, 0xdd, 0x56, 0x9d, 0x46, 0xbd, - 0x36, 0xb0, 0x31, 0x52, 0x49, 0x93, 0xac, 0x70, - 0x1d, 0x36, 0xf1, 0xb3, 0xd2, 0x2f, 0xe5, 0x51, - 0x7c, 0x8b, 0x1a, 0xaf, 0x3c, 0x82, 0x6f, 0x18, + 0xfe, 0x18, 0xeb, 0xc3, 0x20, 0xe2, 0xdf, 0x7b, + 0xf5, 0x62, 0x27, 0xe4, 0x8c, 0x32, 0xdd, 0x06, + 0x19, 0xe2, 0xf9, 0xb1, 0xef, 0xf4, 0x96, 0x38, + 0x6b, 0x1f, 0x11, 0xba, 0x0b, 0x9f, 0x92, 0xa8, } // genesisMerkleRoot is the hash of the first transaction in the genesis block @@ -52,7 +52,7 @@ var genesisBlock = externalapi.DomainBlock{ HashMerkleRoot: genesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bc9e305a, + TimeInMilliseconds: 0x1763db5c4a9, Bits: 0x207fffff, Nonce: 0x0, }, @@ -79,10 +79,10 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.DomainHash{ - 0x92, 0xb5, 0x28, 0xd3, 0xaa, 0x6d, 0x8b, 0x30, - 0x49, 0x19, 0x53, 0x6f, 0x62, 0xce, 0x9a, 0x82, - 0x2f, 0x91, 0xd4, 0x33, 0x24, 0xbc, 0x39, 0xe6, - 0xad, 0x53, 0xe3, 0x97, 0x5f, 0x03, 0x00, 0x00, + 0x13, 0x2d, 0xfc, 0xf3, 0xcf, 0x03, 0xfb, 0x21, + 0x30, 0xb8, 0x67, 0x79, 0xbc, 0x2e, 0x18, 0x4e, + 0x08, 0xd7, 0xeb, 0xf7, 0xb6, 0x86, 0x3c, 0x3e, + 0xe0, 0x8c, 0x8d, 0x02, 0x3c, 0xfd, 0xfe, 0x66, } // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -103,9 +103,9 @@ var devnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: devnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bca27b7f, + TimeInMilliseconds: 0x1763db5c4a9, Bits: 0x1e7fffff, - Nonce: 0x1a9ba, + Nonce: 0x281ad, }, Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -129,10 +129,10 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0x84, 0x96, 0x38, 0xb6, 0x5c, 0x44, 0xc0, 0xb9, - 0x3c, 0x48, 0x03, 0x7c, 0x2e, 0xee, 0x0a, 0xbf, - 0xfb, 0x54, 0xc8, 0x5f, 0x99, 0xd6, 0x21, 0x3d, - 0x3f, 0xdd, 0xac, 0xb1, 0xe7, 0x30, 0x7e, 0x05, + 0xda, 0xcc, 0x82, 0xd2, 0xf2, 0x53, 0x49, 0x48, + 0x18, 0x9e, 0x08, 0x8f, 0xd3, 0xe1, 0xbc, 0xce, + 0xb6, 0x0d, 0x48, 0xa6, 0x51, 0x53, 0xe1, 0xc1, + 0xa7, 0xa7, 0x10, 0x8a, 0xde, 0x96, 0xa3, 0x4d, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -153,9 +153,9 @@ var simnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: simnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bca27c39, + TimeInMilliseconds: 0x1763db5c5de, Bits: 0x207fffff, - Nonce: 0x1, + Nonce: 0x0, }, Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } @@ -177,10 +177,10 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.DomainHash{ - 0xa9, 0xbe, 0xa7, 0xd9, 0x0f, 0xd2, 0xbd, 0xfb, - 0xd8, 0x09, 0x4d, 0x6a, 0x49, 0xa7, 0x59, 0x93, - 0xd1, 0x35, 0xce, 0x61, 0x18, 0x07, 0x0b, 0xe6, - 0xb9, 0xec, 0xad, 0x68, 0xe4, 0x2d, 0x00, 0x00, + 0x97, 0xb5, 0xd5, 0xf6, 0x0d, 0xfe, 0x77, 0x83, + 0x87, 0xe8, 0x06, 0x52, 0xd5, 0xbe, 0xd2, 0x5e, + 0x92, 0x5a, 0x70, 0x03, 0x2b, 0x7a, 0x75, 0x5c, + 0xc5, 0xe4, 0x73, 0xa0, 0x23, 0x47, 0x25, 0x2f, } // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -201,9 +201,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: testnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x175bcac06ec, + TimeInMilliseconds: 0x1763db5c5de, Bits: 0x1e7fffff, - Nonce: 0x568f, + Nonce: 0xec6f, }, Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/testing/integration/mining_test.go b/testing/integration/mining_test.go index 6b6fa77b1..1fecb839c 100644 --- a/testing/integration/mining_test.go +++ b/testing/integration/mining_test.go @@ -1,15 +1,13 @@ package integration import ( + "github.com/kaspanet/kaspad/domain/consensus/model/pow" "math/rand" "testing" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/util" ) @@ -18,8 +16,7 @@ func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock { initialNonce := rand.Uint64() for i := initialNonce; i != initialNonce-1; i++ { block.Header.Nonce = i - hash := consensushashing.BlockHash(block) - if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 { + if pow.CheckProofOfWorkWithTarget(block.Header, targetDifficulty) { return block } } From e04f76b800cfda05d191c992ba58b44adb184b2f Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 8 Dec 2020 19:11:35 +0200 Subject: [PATCH 121/351] [NOD-1594] Add HeaderCount to GetBlockCount rpc call (#1197) --- app/appmessage/rpc_get_block_count.go | 10 +- app/rpc/rpchandlers/get_block_count.go | 2 +- .../grpcserver/protowire/messages.pb.go | 191 +++++++++--------- .../grpcserver/protowire/messages.proto | 1 + .../protowire/rpc_get_block_count.go | 10 +- 5 files changed, 116 insertions(+), 98 deletions(-) diff --git a/app/appmessage/rpc_get_block_count.go b/app/appmessage/rpc_get_block_count.go index 77b1502d0..c915475d9 100644 --- a/app/appmessage/rpc_get_block_count.go +++ b/app/appmessage/rpc_get_block_count.go @@ -1,5 +1,7 @@ package appmessage +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + // GetBlockCountRequestMessage is an appmessage corresponding to // its respective RPC message type GetBlockCountRequestMessage struct { @@ -20,7 +22,8 @@ func NewGetBlockCountRequestMessage() *GetBlockCountRequestMessage { // its respective RPC message type GetBlockCountResponseMessage struct { baseMessage - BlockCount uint64 + BlockCount uint64 + HeaderCount uint64 Error *RPCError } @@ -31,8 +34,9 @@ func (msg *GetBlockCountResponseMessage) Command() MessageCommand { } // NewGetBlockCountResponseMessage returns a instance of the message -func NewGetBlockCountResponseMessage(blockCount uint64) *GetBlockCountResponseMessage { +func NewGetBlockCountResponseMessage(syncInfo *externalapi.SyncInfo) *GetBlockCountResponseMessage { return &GetBlockCountResponseMessage{ - BlockCount: blockCount, + BlockCount: syncInfo.BlockCount, + HeaderCount: syncInfo.HeaderCount, } } diff --git a/app/rpc/rpchandlers/get_block_count.go b/app/rpc/rpchandlers/get_block_count.go index 24b6d353b..4033e8d7d 100644 --- a/app/rpc/rpchandlers/get_block_count.go +++ b/app/rpc/rpchandlers/get_block_count.go @@ -12,6 +12,6 @@ func HandleGetBlockCount(context *rpccontext.Context, _ *router.Router, _ appmes if err != nil { return nil, err } - response := appmessage.NewGetBlockCountResponseMessage(syncInfo.BlockCount) + response := appmessage.NewGetBlockCountResponseMessage(syncInfo) return response, nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 6f72f7a20..81292f71b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -5534,8 +5534,9 @@ type GetBlockCountResponseMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - BlockCount uint64 `protobuf:"varint,1,opt,name=blockCount,proto3" json:"blockCount,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` + BlockCount uint64 `protobuf:"varint,1,opt,name=blockCount,proto3" json:"blockCount,omitempty"` + HeaderCount uint64 `protobuf:"varint,2,opt,name=headerCount,proto3" json:"headerCount,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } func (x *GetBlockCountResponseMessage) Reset() { @@ -5577,6 +5578,13 @@ func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { return 0 } +func (x *GetBlockCountResponseMessage) GetHeaderCount() uint64 { + if x != nil { + return x.HeaderCount + } + return 0 +} + func (x *GetBlockCountResponseMessage) GetError() *RPCError { if x != nil { return x.Error @@ -7186,96 +7194,99 @@ var file_messages_proto_rawDesc = []byte{ 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, - 0x6a, 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, - 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, 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, - 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, 0x04, 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, 0x05, 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, 0x06, - 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, + 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, + 0xa6, 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, 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, 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, + 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, + 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 243f39278..cf88b8480 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -553,6 +553,7 @@ message GetBlockCountRequestMessage{ message GetBlockCountResponseMessage{ uint64 blockCount = 1; + uint64 headerCount = 2; RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_count.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_count.go index a6a078272..411623713 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_count.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_count.go @@ -17,8 +17,9 @@ func (x *KaspadMessage_GetBlockCountResponse) toAppMessage() (appmessage.Message err = &appmessage.RPCError{Message: x.GetBlockCountResponse.Error.Message} } return &appmessage.GetBlockCountResponseMessage{ - BlockCount: x.GetBlockCountResponse.BlockCount, - Error: err, + BlockCount: x.GetBlockCountResponse.BlockCount, + HeaderCount: x.GetBlockCountResponse.HeaderCount, + Error: err, }, nil } @@ -28,8 +29,9 @@ func (x *KaspadMessage_GetBlockCountResponse) fromAppMessage(message *appmessage err = &RPCError{Message: message.Error.Message} } x.GetBlockCountResponse = &GetBlockCountResponseMessage{ - BlockCount: message.BlockCount, - Error: err, + BlockCount: message.BlockCount, + HeaderCount: message.HeaderCount, + Error: err, } return nil } From 0d8f7bba401e1c32a0a0fee8d55248a6f91bc166 Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 9 Dec 2020 12:14:15 +0200 Subject: [PATCH 122/351] [NOD-1595] Implement all fields of GetBlockDAGInfo (#1200) * [NOD-1595] Implement all fields of GetBlockDAGInfo * [NOD-1595] * [NOD-1595] Don't swallow errors in GetDifficultyRatio * [NOD-1595] Change roundingPrecision in GetDifficultyRatio to 2 decimal places --- app/appmessage/rpc_get_block_dag_info.go | 1 + app/rpc/rpccontext/verbosedata.go | 13 +- app/rpc/rpchandlers/get_block_dag_info.go | 23 +++ domain/consensus/consensus.go | 25 +++ .../consensus/model/externalapi/consensus.go | 2 + domain/consensus/model/externalapi/virtual.go | 8 + .../hashes/{from_string.go => strings.go} | 9 + .../grpcserver/protowire/messages.pb.go | 164 ++++++++++-------- .../grpcserver/protowire/messages.proto | 9 +- .../protowire/rpc_get_block_dag_info.go | 2 + 10 files changed, 168 insertions(+), 88 deletions(-) create mode 100644 domain/consensus/model/externalapi/virtual.go rename domain/consensus/utils/hashes/{from_string.go => strings.go} (87%) diff --git a/app/appmessage/rpc_get_block_dag_info.go b/app/appmessage/rpc_get_block_dag_info.go index 472f22347..460507258 100644 --- a/app/appmessage/rpc_get_block_dag_info.go +++ b/app/appmessage/rpc_get_block_dag_info.go @@ -22,6 +22,7 @@ type GetBlockDAGInfoResponseMessage struct { baseMessage NetworkName string BlockCount uint64 + HeaderCount uint64 TipHashes []string VirtualParentHashes []string Difficulty float64 diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index e9c1f4062..88b464072 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -3,6 +3,7 @@ package rpccontext import ( "encoding/hex" "fmt" + "math" "math/big" "strconv" @@ -29,7 +30,6 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ if err != nil { return nil, err } - result := &appmessage.BlockVerboseData{ Hash: hash.String(), Version: blockHeader.Version, @@ -77,12 +77,11 @@ func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) fl target := util.CompactToBig(bits) difficulty := new(big.Rat).SetFrac(params.PowMax, target) - outString := difficulty.FloatString(8) - diff, err := strconv.ParseFloat(outString, 64) - if err != nil { - log.Errorf("Cannot get difficulty: %s", err) - return 0 - } + diff, _ := difficulty.Float64() + + roundingPrecision := float64(100) + diff = math.Round(diff*roundingPrecision) / roundingPrecision + return diff } diff --git a/app/rpc/rpchandlers/get_block_dag_info.go b/app/rpc/rpchandlers/get_block_dag_info.go index 8c6cebc82..31dffe2a3 100644 --- a/app/rpc/rpchandlers/get_block_dag_info.go +++ b/app/rpc/rpchandlers/get_block_dag_info.go @@ -3,15 +3,38 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) // HandleGetBlockDAGInfo handles the respectively named RPC command func HandleGetBlockDAGInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { params := context.Config.ActiveNetParams + consensus := context.Domain.Consensus() response := appmessage.NewGetBlockDAGInfoResponseMessage() response.NetworkName = params.Name + syncInfo, err := consensus.GetSyncInfo() + if err != nil { + return nil, err + } + response.BlockCount = syncInfo.BlockCount + response.HeaderCount = syncInfo.HeaderCount + + tipHashes, err := consensus.Tips() + if err != nil { + return nil, err + } + response.TipHashes = hashes.ToStrings(tipHashes) + + virtualInfo, err := consensus.GetVirtualInfo() + if err != nil { + return nil, err + } + response.VirtualParentHashes = hashes.ToStrings(virtualInfo.ParentHashes) + response.Difficulty = context.GetDifficultyRatio(virtualInfo.Bits, context.Config.ActiveNetParams) + response.PastMedianTime = virtualInfo.PastMedianTime + return response, nil } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 7e49e8abf..007e5a7a0 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -221,3 +221,28 @@ func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { return s.syncManager.GetSyncInfo() } + +func (s *consensus) Tips() ([]*externalapi.DomainHash, error) { + return s.consensusStateStore.Tips(s.databaseContext) +} + +func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) { + blockRelations, err := s.blockRelationStore.BlockRelation(s.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + bits, err := s.difficultyManager.RequiredDifficulty(model.VirtualBlockHash) + if err != nil { + return nil, err + } + pastMedianTime, err := s.pastMedianTimeManager.PastMedianTime(model.VirtualBlockHash) + if err != nil { + return nil, err + } + + return &externalapi.VirtualInfo{ + ParentHashes: blockRelations.Parents, + Bits: bits, + PastMedianTime: pastMedianTime, + }, nil +} diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 197878b14..ccf94de6b 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -18,4 +18,6 @@ type Consensus interface { CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error) GetSyncInfo() (*SyncInfo, error) + Tips() ([]*DomainHash, error) + GetVirtualInfo() (*VirtualInfo, error) } diff --git a/domain/consensus/model/externalapi/virtual.go b/domain/consensus/model/externalapi/virtual.go new file mode 100644 index 000000000..b35ec4342 --- /dev/null +++ b/domain/consensus/model/externalapi/virtual.go @@ -0,0 +1,8 @@ +package externalapi + +// VirtualInfo represents information about the virtual block needed by external components +type VirtualInfo struct { + ParentHashes []*DomainHash + Bits uint32 + PastMedianTime int64 +} diff --git a/domain/consensus/utils/hashes/from_string.go b/domain/consensus/utils/hashes/strings.go similarity index 87% rename from domain/consensus/utils/hashes/from_string.go rename to domain/consensus/utils/hashes/strings.go index d4d999c56..3c4b9625e 100644 --- a/domain/consensus/utils/hashes/from_string.go +++ b/domain/consensus/utils/hashes/strings.go @@ -55,3 +55,12 @@ func decode(dst *externalapi.DomainHash, src string) error { return nil } + +// ToStrings converts a slice of hashes into a slice of the corresponding strings +func ToStrings(hashes []*externalapi.DomainHash) []string { + strings := make([]string, len(hashes)) + for i, hash := range hashes { + strings[i] = hash.String() + } + return strings +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 81292f71b..3eb8fe3f6 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -5637,10 +5637,11 @@ type GetBlockDagInfoResponseMessage struct { NetworkName string `protobuf:"bytes,1,opt,name=networkName,proto3" json:"networkName,omitempty"` BlockCount uint64 `protobuf:"varint,2,opt,name=blockCount,proto3" json:"blockCount,omitempty"` - TipHashes []string `protobuf:"bytes,3,rep,name=tipHashes,proto3" json:"tipHashes,omitempty"` - Difficulty float64 `protobuf:"fixed64,4,opt,name=difficulty,proto3" json:"difficulty,omitempty"` - PastMedianTime int64 `protobuf:"varint,5,opt,name=pastMedianTime,proto3" json:"pastMedianTime,omitempty"` - VirtualParentHashes []string `protobuf:"bytes,6,rep,name=virtualParentHashes,proto3" json:"virtualParentHashes,omitempty"` + HeaderCount uint64 `protobuf:"varint,3,opt,name=headerCount,proto3" json:"headerCount,omitempty"` + TipHashes []string `protobuf:"bytes,4,rep,name=tipHashes,proto3" json:"tipHashes,omitempty"` + Difficulty float64 `protobuf:"fixed64,5,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + PastMedianTime int64 `protobuf:"varint,6,opt,name=pastMedianTime,proto3" json:"pastMedianTime,omitempty"` + VirtualParentHashes []string `protobuf:"bytes,7,rep,name=virtualParentHashes,proto3" json:"virtualParentHashes,omitempty"` Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } @@ -5690,6 +5691,13 @@ func (x *GetBlockDagInfoResponseMessage) GetBlockCount() uint64 { return 0 } +func (x *GetBlockDagInfoResponseMessage) GetHeaderCount() uint64 { + if x != nil { + return x.HeaderCount + } + return 0 +} + func (x *GetBlockDagInfoResponseMessage) GetTipHashes() []string { if x != nil { return x.TipHashes @@ -7205,88 +7213,90 @@ var file_messages_proto_rawDesc = []byte{ 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, - 0xa6, 0x02, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, + 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, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, - 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, 0x43, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61, + 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, + 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index cf88b8480..d39caa5a1 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -563,10 +563,11 @@ message GetBlockDagInfoRequestMessage{ message GetBlockDagInfoResponseMessage{ string networkName = 1; uint64 blockCount = 2; - repeated string tipHashes = 3; - double difficulty = 4; - int64 pastMedianTime = 5; - repeated string virtualParentHashes = 6; + uint64 headerCount = 3; + repeated string tipHashes = 4; + double difficulty = 5; + int64 pastMedianTime = 6; + repeated string virtualParentHashes = 7; RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_dag_info.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_dag_info.go index ca7fd24b5..d47cb6a29 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_dag_info.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_dag_info.go @@ -21,6 +21,7 @@ func (x *KaspadMessage_GetBlockDagInfoResponse) toAppMessage() (appmessage.Messa return &appmessage.GetBlockDAGInfoResponseMessage{ NetworkName: x.GetBlockDagInfoResponse.NetworkName, BlockCount: x.GetBlockDagInfoResponse.BlockCount, + HeaderCount: x.GetBlockDagInfoResponse.HeaderCount, TipHashes: x.GetBlockDagInfoResponse.TipHashes, VirtualParentHashes: x.GetBlockDagInfoResponse.VirtualParentHashes, Difficulty: x.GetBlockDagInfoResponse.Difficulty, @@ -37,6 +38,7 @@ func (x *KaspadMessage_GetBlockDagInfoResponse) fromAppMessage(message *appmessa x.GetBlockDagInfoResponse = &GetBlockDagInfoResponseMessage{ NetworkName: message.NetworkName, BlockCount: message.BlockCount, + HeaderCount: message.HeaderCount, TipHashes: message.TipHashes, VirtualParentHashes: message.VirtualParentHashes, Difficulty: message.Difficulty, From 3354ac67c8c785107546cd9cdf7d5c31bac433f2 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 9 Dec 2020 17:43:36 +0200 Subject: [PATCH 123/351] Parallelize all the tests in ForAllNets (#1199) --- domain/consensus/utils/testutils/for_all_nets.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/domain/consensus/utils/testutils/for_all_nets.go b/domain/consensus/utils/testutils/for_all_nets.go index 689cf4053..dde91068d 100644 --- a/domain/consensus/utils/testutils/for_all_nets.go +++ b/domain/consensus/utils/testutils/for_all_nets.go @@ -18,8 +18,11 @@ func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *dagconfig for _, params := range allParams { paramsCopy := params - paramsCopy.SkipProofOfWork = skipPow - t.Logf("Running test for %s", params.Name) - testFunc(t, ¶msCopy) + t.Run(paramsCopy.Name, func(t *testing.T) { + t.Parallel() + paramsCopy.SkipProofOfWork = skipPow + t.Logf("Running test for %s", paramsCopy.Name) + testFunc(t, ¶msCopy) + }) } } From 6714e084e9d6cd6e6aafd2703b69e526e62eda1a Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 9 Dec 2020 18:31:36 +0200 Subject: [PATCH 124/351] Small fix in proof-of-work log (#1205) --- .../consensus/processes/blockvalidator/proof_of_work.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index 8b29c7445..96426f244 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "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/util" "github.com/pkg/errors" ) @@ -155,9 +156,9 @@ func (v *blockValidator) checkPruningPointViolation(header *externalapi.DomainBl if err != nil { return err } - if isAncestorOfAny { - return nil + if !isAncestorOfAny { + return errors.Wrapf(ruleerrors.ErrPruningPointViolation, + "expected pruning point %s to be in block %s past.", pruningPoint, consensushashing.HeaderHash(header)) } - return errors.Wrapf(ruleerrors.ErrPruningPointViolation, - "expected pruning point to be in block %d past.", header.Bits) + return nil } From 2c1688909d2d09b982d934cfdef470b950c18317 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 14 Dec 2020 09:09:18 +0200 Subject: [PATCH 125/351] Move TestNet to use GRPCSeeds by default (#1217) --- app/component_manager.go | 2 - domain/dagconfig/params.go | 9 ++- infrastructure/network/dnsseed/seed.go | 95 ++++++++++++++------------ 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/app/component_manager.go b/app/component_manager.go index 04d9350ca..441ec1d92 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -140,9 +140,7 @@ func (a *ComponentManager) maybeSeedFromDNS() { // source. So we'll take first returned address as source. a.addressManager.AddAddresses(addresses...) }) - } - if a.cfg.GRPCSeed != "" { dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil, func(addresses []*appmessage.NetAddress) { a.addressManager.AddAddresses(addresses...) diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index acb701709..867606224 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -5,10 +5,11 @@ package dagconfig import ( - "github.com/kaspanet/kaspad/domain/consensus/model" "math/big" "time" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/app/appmessage" @@ -71,6 +72,10 @@ type Params struct { // as one method to discover peers. DNSSeeds []string + // GRPCSeeds defines a list of GRPC seeds for the network that are used + // as one method to discover peers. + GRPCSeeds []string + // GenesisBlock defines the first block of the DAG. GenesisBlock *externalapi.DomainBlock @@ -256,7 +261,7 @@ var TestnetParams = Params{ Net: appmessage.Testnet, RPCPort: "16210", DefaultPort: "16211", - DNSSeeds: []string{"testnet-dnsseed.kas.pa"}, + GRPCSeeds: []string{"testnet-dnsseed.kas.pa:17100"}, // DAG parameters GenesisBlock: &testnetGenesisBlock, diff --git a/infrastructure/network/dnsseed/seed.go b/infrastructure/network/dnsseed/seed.go index 4caf0eb21..f59fcfac7 100644 --- a/infrastructure/network/dnsseed/seed.go +++ b/infrastructure/network/dnsseed/seed.go @@ -103,61 +103,68 @@ func SeedFromDNS(dagParams *dagconfig.Params, customSeed string, reqServices app } // SeedFromGRPC send gRPC request to get list of peers for a given host -func SeedFromGRPC(dagParams *dagconfig.Params, host string, reqServices appmessage.ServiceFlag, includeAllSubnetworks bool, +func SeedFromGRPC(dagParams *dagconfig.Params, customSeed string, reqServices appmessage.ServiceFlag, includeAllSubnetworks bool, subnetworkID *externalapi.DomainSubnetworkID, seedFn OnSeed) { + var grpcSeeds []string + if customSeed != "" { + grpcSeeds = []string{customSeed} + } else { + grpcSeeds = dagParams.GRPCSeeds + } - spawn("SeedFromGRPC", func() { + for _, host := range grpcSeeds { + spawn("SeedFromGRPC", func() { + randSource := rand.New(rand.NewSource(time.Now().UnixNano())) - randSource := rand.New(rand.NewSource(time.Now().UnixNano())) + conn, err := grpc.Dial(host, grpc.WithInsecure()) + client := pb2.NewPeerServiceClient(conn) + if err != nil { + log.Warnf("Failed to connect to gRPC server: %s", host) + } - conn, err := grpc.Dial(host, grpc.WithInsecure()) - client := pb2.NewPeerServiceClient(conn) - if err != nil { - log.Warnf("Failed to connect to gRPC server: %s", host) - } + var subnetID []byte + if subnetworkID != nil { + subnetID = subnetworkID[:] + } else { + subnetID = nil + } - var subnetID []byte - if subnetworkID != nil { - subnetID = subnetworkID[:] - } else { - subnetID = nil - } + req := &pb2.GetPeersListRequest{ + ServiceFlag: uint64(reqServices), + SubnetworkID: subnetID, + IncludeAllSubnetworks: includeAllSubnetworks, + } + res, err := client.GetPeersList(context.Background(), req) - req := &pb2.GetPeersListRequest{ - ServiceFlag: uint64(reqServices), - SubnetworkID: subnetID, - IncludeAllSubnetworks: includeAllSubnetworks, - } - res, err := client.GetPeersList(context.Background(), req) + if err != nil { + log.Infof("gRPC request to get peers failed (host=%s): %s", host, err) + return + } - if err != nil { - log.Infof("gRPC request to get peers failed (host=%s): %s", host, err) - return - } + seedPeers := fromProtobufAddresses(res.Addresses) - seedPeers := fromProtobufAddresses(res.Addresses) + numPeers := len(seedPeers) - numPeers := len(seedPeers) + log.Infof("%d addresses found from DNS seed %s", numPeers, host) - log.Infof("%d addresses found from DNS seed %s", numPeers, host) + if numPeers == 0 { + return + } + addresses := make([]*appmessage.NetAddress, len(seedPeers)) + // if this errors then we have *real* problems + intPort, _ := strconv.Atoi(dagParams.DefaultPort) + for i, peer := range seedPeers { + addresses[i] = appmessage.NewNetAddressTimestamp( + // seed with addresses from a time randomly selected + // between 3 and 7 days ago. + mstime.Now().Add(-1*time.Second*time.Duration(secondsIn3Days+ + randSource.Int31n(secondsIn4Days))), + 0, peer, uint16(intPort)) + } - if numPeers == 0 { - return - } - addresses := make([]*appmessage.NetAddress, len(seedPeers)) - // if this errors then we have *real* problems - intPort, _ := strconv.Atoi(dagParams.DefaultPort) - for i, peer := range seedPeers { - addresses[i] = appmessage.NewNetAddressTimestamp( - // seed with addresses from a time randomly selected - // between 3 and 7 days ago. - mstime.Now().Add(-1*time.Second*time.Duration(secondsIn3Days+ - randSource.Int31n(secondsIn4Days))), - 0, peer, uint16(intPort)) - } - - seedFn(addresses) - }) + seedFn(addresses) + }) + } } func fromProtobufAddresses(proto []*pb2.NetAddress) []net.IP { From a9e0c33e5cd0aed1d19bfa4a80e191b9f2b3b833 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 14 Dec 2020 12:39:54 +0200 Subject: [PATCH 126/351] Lower minimum difficulty for mainnet and testnet (#1220) --- domain/dagconfig/params.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 867606224..b26e47069 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -32,8 +32,8 @@ var ( mainPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) // testnetPowMax is the highest proof of work value a Kaspa block - // can have for the test network. It is the value 2^239 - 1. - testnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) + // can have for the test network. It is the value 2^255 - 1. + testnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) // simnetPowMax is the highest proof of work value a Kaspa block // can have for the simulation test network. It is the value 2^255 - 1. @@ -41,8 +41,8 @@ var ( // devnetPowMax is the highest proof of work value a Kaspa block // can have for the development network. It is the value - // 2^239 - 1. - devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) + // 2^255 - 1. + devnetPowMax = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) ) // KType defines the size of GHOSTDAG consensus algorithm K parameter. From 6926a7ab81ecf53b0ed40d8dcc5319e232160de9 Mon Sep 17 00:00:00 2001 From: oudeis Date: Mon, 14 Dec 2020 12:38:03 +0000 Subject: [PATCH 127/351] Update to version 0.8.3 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 1424c3221..76800bbe7 100644 --- a/version/version.go +++ b/version/version.go @@ -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 From 48e1a2c396a25f9f84b01b06c1da1f65e2d0387a Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 14 Dec 2020 17:53:08 +0200 Subject: [PATCH 128/351] 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 --- .../flows/blockrelay/handle_relay_invs.go | 1 - app/protocol/flows/blockrelay/ibd.go | 26 ++- domain/consensus/consensus.go | 80 ++++--- domain/consensus/consensus_test.go | 6 - .../headertipsstore.go | 100 +++++++++ .../headertipsstore/headertipsstore.go | 101 --------- domain/consensus/factory.go | 47 ++-- .../consensus/model/externalapi/blockinfo.go | 2 - .../consensus/model/externalapi/consensus.go | 2 +- domain/consensus/model/externalapi/sync.go | 31 +-- ...nterface_datastructures_headertipsstore.go | 10 +- .../interface_processes_blockprocessor.go | 1 + ...terface_processes_consensusstatemanager.go | 5 +- .../interface_processes_finalitymanager.go | 1 - .../interface_processes_headertipsmanager.go | 5 +- .../interface_processes_pruningmanager.go | 5 +- .../model/interface_processes_syncmanager.go | 1 - .../consensus/model/testapi/test_consensus.go | 4 +- .../blockprocessor/blockprocessor.go | 69 +++--- .../blockprocessor/validateandinsertblock.go | 200 ++++-------------- .../validateandinsertpruningpoint.go | 38 ++++ .../processes/blockprocessor/validateblock.go | 67 ++++++ .../blockvalidator/block_body_in_context.go | 4 + .../blockvalidator/block_body_in_isolation.go | 4 + .../blockvalidator/block_header_in_context.go | 10 +- .../block_header_in_isolation.go | 4 + .../consensus/processes/blockvalidator/log.go | 7 + .../processes/blockvalidator/proof_of_work.go | 35 ++- .../add_block_to_virtual.go | 52 ++--- .../check_finality_violation.go | 66 ++++-- .../consensus_state_manager.go | 48 +++-- ...utxo_set.go => update_pruning_utxo_set.go} | 95 ++++----- .../verify_and_build_utxo.go | 5 +- .../dagtraversalmanager.go | 9 +- .../finalitymanager/finality_manager.go | 25 --- .../headertipsmanager.go | 55 +++++ .../headertipsmanager/headertipsmanager.go | 59 ------ .../headertipsmanager/selected_tip.go | 17 -- .../consensus/processes/pruningmanager/log.go | 5 + .../pruningmanager/pruningmanager.go | 98 ++++++--- .../reachability_external_test.go | 2 +- .../processes/syncmanager/antipast.go | 31 +-- .../processes/syncmanager/syncinfo.go | 69 ++---- .../processes/syncmanager/syncmanager.go | 44 ++-- domain/consensus/ruleerrors/rule_error.go | 2 + domain/consensus/test_consensus_getters.go | 6 +- infrastructure/config/network.go | 5 + infrastructure/logger/logger.go | 10 +- 48 files changed, 769 insertions(+), 800 deletions(-) create mode 100644 domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go delete mode 100644 domain/consensus/datastructures/headertipsstore/headertipsstore.go create mode 100644 domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go create mode 100644 domain/consensus/processes/blockprocessor/validateblock.go create mode 100644 domain/consensus/processes/blockvalidator/log.go rename domain/consensus/processes/consensusstatemanager/{set_pruning_utxo_set.go => update_pruning_utxo_set.go} (53%) create mode 100644 domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go delete mode 100644 domain/consensus/processes/headertipsmanager/headertipsmanager.go delete mode 100644 domain/consensus/processes/headertipsmanager/selected_tip.go create mode 100644 domain/consensus/processes/pruningmanager/log.go diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 3d0546d02..86096196e 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -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 diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index e5fc983c8..62b5fc157 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -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 @@ -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 } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 007e5a7a0..3ecfe1b99 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -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 @@ -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() +} diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index 67662b591..964580e64 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -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) @@ -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) - } }) } diff --git a/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go b/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go new file mode 100644 index 000000000..8926c1c12 --- /dev/null +++ b/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go @@ -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) +} diff --git a/domain/consensus/datastructures/headertipsstore/headertipsstore.go b/domain/consensus/datastructures/headertipsstore/headertipsstore.go deleted file mode 100644 index cb36b6ee1..000000000 --- a/domain/consensus/datastructures/headertipsstore/headertipsstore.go +++ /dev/null @@ -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) -} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index ee8f93414..dcfdf3a81 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -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" @@ -81,7 +81,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 +139,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 +211,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockRelationStore, acceptanceDataStore, blockHeaderStore, - headerTipsStore) + headersSelectedTipStore, + pruningStore) if err != nil { return nil, err } @@ -225,6 +226,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore, pruningStore, blockStatusStore, + headersSelectedTipStore, multisetStore, acceptanceDataStore, blockStore, @@ -236,17 +238,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 +288,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat reachabilityDataStore, utxoDiffStore, blockHeaderStore, - headerTipsStore, + headersSelectedTipStore, finalityStore) c := &consensus{ @@ -312,19 +313,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) diff --git a/domain/consensus/model/externalapi/blockinfo.go b/domain/consensus/model/externalapi/blockinfo.go index 8df85f63f..dcd7128de 100644 --- a/domain/consensus/model/externalapi/blockinfo.go +++ b/domain/consensus/model/externalapi/blockinfo.go @@ -5,6 +5,4 @@ type BlockInfo struct { Exists bool BlockStatus BlockStatus BlueScore uint64 - - IsBlockInHeaderPruningPointFuture bool } diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index ccf94de6b..ef63cd2a2 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -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) diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index 758581dc4..d5f11a499 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -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("", 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 diff --git a/domain/consensus/model/interface_datastructures_headertipsstore.go b/domain/consensus/model/interface_datastructures_headertipsstore.go index df3bc6dca..b4788af75 100644 --- a/domain/consensus/model/interface_datastructures_headertipsstore.go +++ b/domain/consensus/model/interface_datastructures_headertipsstore.go @@ -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) } diff --git a/domain/consensus/model/interface_processes_blockprocessor.go b/domain/consensus/model/interface_processes_blockprocessor.go index 0f7df8090..471358249 100644 --- a/domain/consensus/model/interface_processes_blockprocessor.go +++ b/domain/consensus/model/interface_processes_blockprocessor.go @@ -5,4 +5,5 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockProcessor is responsible for processing incoming blocks type BlockProcessor interface { ValidateAndInsertBlock(block *externalapi.DomainBlock) error + ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error } diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 208eef3ec..78fb0474b 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -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) 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) } diff --git a/domain/consensus/model/interface_processes_finalitymanager.go b/domain/consensus/model/interface_processes_finalitymanager.go index c58a5c339..04efa0ab5 100644 --- a/domain/consensus/model/interface_processes_finalitymanager.go +++ b/domain/consensus/model/interface_processes_finalitymanager.go @@ -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) } diff --git a/domain/consensus/model/interface_processes_headertipsmanager.go b/domain/consensus/model/interface_processes_headertipsmanager.go index deea0f4c8..9ff6ed68e 100644 --- a/domain/consensus/model/interface_processes_headertipsmanager.go +++ b/domain/consensus/model/interface_processes_headertipsmanager.go @@ -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) } diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index 09322ebad..6df77895b 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -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) } diff --git a/domain/consensus/model/interface_processes_syncmanager.go b/domain/consensus/model/interface_processes_syncmanager.go index cc0a32567..165659c53 100644 --- a/domain/consensus/model/interface_processes_syncmanager.go +++ b/domain/consensus/model/interface_processes_syncmanager.go @@ -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) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 9800400ab..e361bff40 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -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 diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index e3e9ed460..926952c30 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -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, }, } @@ -128,3 +128,10 @@ func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) 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) +} diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 0cdff5ec7..5ab0aba0d 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -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 { 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 } - if insertMode == insertModeHeader { + isHeaderOnlyBlock := isHeaderOnlyBlock(block) + if isHeaderOnlyBlock { bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) } else { bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) @@ -54,43 +34,38 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } 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 } } - 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 err + } + + if !isHeaderOnlyBlock { // Attempt to add the block to the virtual - err = bp.consensusStateManager.AddBlockToVirtual(blockHash) + err = bp.consensusStateManager.AddBlock(blockHash) if err != nil { return 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 } } - 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 } @@ -115,8 +90,8 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) 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) + return fmt.Sprintf("New virtual's blue score: %d. Is awaiting UTXO set: %t. Block count: %d. Header count: %d", + virtualGhostDAGData.BlueScore(), syncInfo.IsAwaitingUTXOSet, syncInfo.BlockCount, syncInfo.HeaderCount) })) if logClosureErr != nil { return logClosureErr @@ -125,64 +100,12 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) 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 -} - func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool { return len(block.Transactions) == 0 } 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 diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go new file mode 100644 index 000000000..f900bd96e --- /dev/null +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go @@ -0,0 +1,38 @@ +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 + } + + return bp.ValidateAndInsertBlock(newPruningPoint) +} diff --git a/domain/consensus/processes/blockprocessor/validateblock.go b/domain/consensus/processes/blockprocessor/validateblock.go new file mode 100644 index 000000000..f7bba7966 --- /dev/null +++ b/domain/consensus/processes/blockprocessor/validateblock.go @@ -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 +} diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index 6e577a6ce..dd6fc4540 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -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) } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 0e74e5f4a..5b9367cf1 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -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 diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 0d2f3fdfc..19f92a2a1 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -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 diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 8fe275a82..01622825d 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -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 diff --git a/domain/consensus/processes/blockvalidator/log.go b/domain/consensus/processes/blockvalidator/log.go new file mode 100644 index 000000000..a2c8cf5d3 --- /dev/null +++ b/domain/consensus/processes/blockvalidator/log.go @@ -0,0 +1,7 @@ +package blockvalidator + +import ( + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +var log, _ = logger.Get(logger.SubsystemTags.BLVL) diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index 96426f244..b83076c79 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -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 @@ -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) } } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 11b5d63c0..4fdf3773f 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -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) 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 } - 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 } - 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 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) @@ -64,9 +64,9 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai return 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 "+ diff --git a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go index c8c9e022e..9774276fe 100644 --- a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go +++ b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go @@ -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 } diff --git a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go index c0c8ab738..fddbe7472 100644 --- a/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/consensus_state_manager.go @@ -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, }, } diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go similarity index 53% rename from domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go rename to domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index fd211c9b2..0365b661e 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -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 } @@ -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 -} diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 8a8853b3b..f28ab7ba2 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -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) diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 5a0329fe3..762580ee4 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -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 } diff --git a/domain/consensus/processes/finalitymanager/finality_manager.go b/domain/consensus/processes/finalitymanager/finality_manager.go index 7fd8cf30e..b5fb1ba29 100644 --- a/domain/consensus/processes/finalitymanager/finality_manager.go +++ b/domain/consensus/processes/finalitymanager/finality_manager.go @@ -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") diff --git a/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go b/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go new file mode 100644 index 000000000..4ff750563 --- /dev/null +++ b/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go @@ -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 +} diff --git a/domain/consensus/processes/headertipsmanager/headertipsmanager.go b/domain/consensus/processes/headertipsmanager/headertipsmanager.go deleted file mode 100644 index 5ad81bdbf..000000000 --- a/domain/consensus/processes/headertipsmanager/headertipsmanager.go +++ /dev/null @@ -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 -} diff --git a/domain/consensus/processes/headertipsmanager/selected_tip.go b/domain/consensus/processes/headertipsmanager/selected_tip.go deleted file mode 100644 index a2d28f3df..000000000 --- a/domain/consensus/processes/headertipsmanager/selected_tip.go +++ /dev/null @@ -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 -} diff --git a/domain/consensus/processes/pruningmanager/log.go b/domain/consensus/processes/pruningmanager/log.go new file mode 100644 index 000000000..68109a28e --- /dev/null +++ b/domain/consensus/processes/pruningmanager/log.go @@ -0,0 +1,5 @@ +package pruningmanager + +import "github.com/kaspanet/kaspad/infrastructure/logger" + +var log, _ = logger.Get(logger.SubsystemTags.PRNM) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 57ca1dd12..11a0e7431 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -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 { diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index de8123ba9..62fe0796c 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -159,7 +159,7 @@ 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() diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index c0e1908ec..14d2406be 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -99,26 +99,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 +167,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) -} diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 2738f8e11..90a5009d8 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -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 { diff --git a/domain/consensus/processes/syncmanager/syncmanager.go b/domain/consensus/processes/syncmanager/syncmanager.go index c3edba5d6..1cc7264ed 100644 --- a/domain/consensus/processes/syncmanager/syncmanager.go +++ b/domain/consensus/processes/syncmanager/syncmanager.go @@ -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() diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 051efccaf..6d6c0fe97 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -237,6 +237,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 diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 539bdcb0b..58712718d 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -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 } diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index 4ec22a74e..a2b49033e 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -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 } diff --git a/infrastructure/logger/logger.go b/infrastructure/logger/logger.go index 8e2d952b3..0776fb79d 100644 --- a/infrastructure/logger/logger.go +++ b/infrastructure/logger/logger.go @@ -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. From 77adb6c99f637c886d0092802a66464f36af2633 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 15 Dec 2020 10:11:14 +0200 Subject: [PATCH 129/351] Make consensus.databaseContext a DBManager and allow keeping data dir in TestConsensus * Make consensus.databaseContext a DBManager * Allow keeping data dir in TestConsensus --- domain/consensus/consensus.go | 2 +- domain/consensus/consensus_test.go | 2 +- domain/consensus/factory.go | 18 ++++++++++++------ domain/consensus/finality_test.go | 6 +++--- domain/consensus/log.go | 7 +++++++ .../consensus/model/testapi/test_consensus.go | 2 +- .../block_body_in_isolation_test.go | 4 ++-- .../block_header_in_context_test.go | 4 ++-- .../calculate_past_utxo_test.go | 4 ++-- .../resolve_block_status_test.go | 4 ++-- .../dagtopologymanager_external_test.go | 2 +- .../dagtraversalmanager/window_test.go | 7 ++++--- .../difficultymanager_test.go | 2 +- .../pastmediantimemanager_test.go | 2 +- .../reachability_external_test.go | 11 ++++++----- .../transaction_in_isolation_test.go | 5 +++-- domain/consensus/test_consensus_getters.go | 2 +- 17 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 domain/consensus/log.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 3ecfe1b99..a2e8ec4dc 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -11,7 +11,7 @@ import ( type consensus struct { lock *sync.Mutex - databaseContext model.DBReader + databaseContext model.DBManager blockProcessor model.BlockProcessor blockBuilder model.BlockBuilder diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index 964580e64..254394725 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -19,7 +19,7 @@ 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 { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index dcfdf3a81..44e6a3601 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -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{} @@ -344,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 { @@ -355,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 { @@ -380,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 diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 8eb2c8732..1ee7ac035 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -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) @@ -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 diff --git a/domain/consensus/log.go b/domain/consensus/log.go new file mode 100644 index 000000000..520dcce8d --- /dev/null +++ b/domain/consensus/log.go @@ -0,0 +1,7 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +var log, _ = logger.Get(logger.SubsystemTags.BDAG) diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index e361bff40..33fcc8594 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -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) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 9f9966eeb..31122ccf7 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -24,7 +24,7 @@ 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) if err != nil { @@ -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)) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index e6c8238f9..34390fde5 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -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) @@ -87,7 +87,7 @@ 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) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index b17697017..99ff74d8c 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -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 @@ -119,7 +119,7 @@ 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 diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index ad0f1eaa5..bf0dce418 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -25,7 +25,7 @@ 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) @@ -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} diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go index 9cb4bf34f..3ab33082d 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -16,7 +16,7 @@ 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. diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 2f878ceef..8947c14d5 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -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) diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index 0714e58a6..256ce46df 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -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...) diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index 37f54f51a..21f446122 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -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) diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index 62fe0796c..1c7438c32 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -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) @@ -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) @@ -161,7 +162,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { if err != nil { t.Fatalf("NewTestConsensus: %+v", err) } - defer tearDown() + defer tearDown(false) tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow) @@ -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) diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go index 912d8aa29..15d12ab62 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -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 diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 58712718d..0390be5b6 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -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 } From fddda46d4f6c12a1f49635f259047eb34613baa4 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 15 Dec 2020 10:37:35 +0200 Subject: [PATCH 130/351] Fix infinite loop on antiPastHashesBetween (#1226) * Fix infinite loop on antiPastHashesBetween * Get rid of highBlockBlueScore and lowBlockBlueScore --- .../consensus/processes/syncmanager/antipast.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 14d2406be..feb33c4d3 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -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 From f90d7d796a001b024c6e6ffda8accddfb718f476 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 15 Dec 2020 11:37:52 +0200 Subject: [PATCH 131/351] [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. --- app/appmessage/rpc_notify_chain_changed.go | 4 +- app/protocol/flowcontext/blocks.go | 2 +- app/protocol/flowcontext/orphans.go | 2 +- .../flows/blockrelay/handle_relay_invs.go | 2 +- app/protocol/flows/blockrelay/ibd.go | 4 +- domain/consensus/consensus.go | 2 +- domain/consensus/consensus_test.go | 4 +- domain/consensus/factory.go | 2 +- domain/consensus/finality_test.go | 8 +- .../consensus/model/externalapi/consensus.go | 2 +- .../model/externalapi/insertblockresult.go | 12 + .../interface_processes_blockprocessor.go | 2 +- ...terface_processes_consensusstatemanager.go | 2 +- .../consensus/model/testapi/test_consensus.go | 2 +- .../blockprocessor/blockprocessor.go | 2 +- .../blockprocessor/validateandinsertblock.go | 27 +- .../validateandinsertpruningpoint.go | 3 +- .../block_body_in_isolation_test.go | 8 +- .../block_header_in_context_test.go | 14 +- .../add_block_to_virtual.go | 16 +- .../calculate_past_utxo_test.go | 14 +- .../find_selected_parent_chain_changes.go | 54 ++ ...find_selected_parent_chain_changes_test.go | 109 ++++ .../resolve_block_status_test.go | 22 +- .../consensusstatemanager/update_virtual.go | 42 +- .../dagtopologymanager_external_test.go | 8 +- .../dagtraversalmanager/window_test.go | 2 +- .../difficultymanager_test.go | 2 +- .../pastmediantimemanager_test.go | 2 +- .../reachability_external_test.go | 34 +- domain/consensus/test_consensus.go | 10 +- .../grpcserver/protowire/messages.pb.go | 539 +++++++++--------- .../grpcserver/protowire/messages.proto | 2 +- .../protowire/rpc_notify_chain_changed.go | 8 +- 34 files changed, 587 insertions(+), 381 deletions(-) create mode 100644 domain/consensus/model/externalapi/insertblockresult.go create mode 100644 domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go create mode 100644 domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go diff --git a/app/appmessage/rpc_notify_chain_changed.go b/app/appmessage/rpc_notify_chain_changed.go index 7a4e5173e..d559c138c 100644 --- a/app/appmessage/rpc_notify_chain_changed.go +++ b/app/appmessage/rpc_notify_chain_changed.go @@ -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 diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 78d4ef6eb..66de8bdd0 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -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) diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 8200bbefe..b54dc07cf 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -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) diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 86096196e..266e732ea 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -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) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 62b5fc157..6bd2ad722 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -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) @@ -283,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) } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index a2e8ec4dc..a9dca69f2 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -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() diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index 254394725..d22a6df3e 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -26,7 +26,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) { 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) } @@ -49,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) } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 44e6a3601..21e8bcd8a 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -335,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 } diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 1ee7ac035..d9ffc7f41 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -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) } diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index ef63cd2a2..3a24edc7e 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -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) diff --git a/domain/consensus/model/externalapi/insertblockresult.go b/domain/consensus/model/externalapi/insertblockresult.go new file mode 100644 index 000000000..357492a8f --- /dev/null +++ b/domain/consensus/model/externalapi/insertblockresult.go @@ -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 +} diff --git a/domain/consensus/model/interface_processes_blockprocessor.go b/domain/consensus/model/interface_processes_blockprocessor.go index 471358249..49752a513 100644 --- a/domain/consensus/model/interface_processes_blockprocessor.go +++ b/domain/consensus/model/interface_processes_blockprocessor.go @@ -4,6 +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 } diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 78fb0474b..c7d51c122 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -4,7 +4,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // ConsensusStateManager manages the node's consensus state type ConsensusStateManager interface { - AddBlock(blockHash *externalapi.DomainHash) error + AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 33fcc8594..c8bb736a9 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -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() diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index 926952c30..e1a6c8548 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -122,7 +122,7 @@ 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() diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 5ab0aba0d..d967f8924 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -11,12 +11,12 @@ import ( "github.com/pkg/errors" ) -func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error { +func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) { blockHash := consensushashing.HeaderHash(block.Header) err := bp.validateBlock(block) if err != nil { bp.discardAllChanges() - return err + return nil, err } isHeaderOnlyBlock := isHeaderOnlyBlock(block) @@ -30,7 +30,7 @@ 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 @@ -39,27 +39,28 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) var err error oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext) if err != nil { - return err + return nil, err } } err = bp.headerTipsManager.AddHeaderTip(blockHash) if err != nil { - return err + return nil, err } + var selectedParentChainChanges *externalapi.SelectedParentChainChanges if !isHeaderOnlyBlock { // Attempt to add the block to the virtual - err = bp.consensusStateManager.AddBlock(blockHash) + selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash) if err != nil { - return err + return nil, err } } if isGenesis { err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) if err != nil { - return err + return nil, err } } @@ -67,13 +68,13 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) // Trigger pruning, which will check if the pruning point changed and delete the data if it did. 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) @@ -94,10 +95,12 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) virtualGhostDAGData.BlueScore(), syncInfo.IsAwaitingUTXOSet, syncInfo.BlockCount, syncInfo.HeaderCount) })) if logClosureErr != nil { - return logClosureErr + return nil, logClosureErr } - return nil + return &externalapi.BlockInsertionResult{ + SelectedParentChainChanges: selectedParentChainChanges, + }, nil } func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool { diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go index f900bd96e..902c8ec38 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go @@ -34,5 +34,6 @@ func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externa return err } - return bp.ValidateAndInsertBlock(newPruningPoint) + _, err = bp.ValidateAndInsertBlock(newPruningPoint) + return err } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 31122ccf7..277c05c9c 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -26,7 +26,7 @@ func TestChainedTransactions(t *testing.T) { } 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) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index 34390fde5..165b42df9 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -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) } @@ -89,17 +89,17 @@ func TestCheckParentsIncest(t *testing.T) { } 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) } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 4fdf3773f..58dcec929 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -8,14 +8,14 @@ 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) AddBlock(blockHash *externalapi.DomainHash) error { +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) isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash) if err != nil { - return err + return nil, err } if isCandidateToBeNextVirtualSelectedParent { @@ -26,7 +26,7 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) er "finality", blockHash) isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(blockHash) if err != nil { - return err + return nil, err } if shouldNotify { @@ -38,7 +38,7 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) er log.Tracef("Block %s doesn't violate finality. Resolving its block status", blockHash) blockStatus, err := csm.resolveBlockStatus(blockHash) if err != nil { - return err + return nil, err } log.Debugf("Block %s resolved to status `%s`", blockHash, blockStatus) @@ -51,17 +51,17 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) er 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) isCandidateToBeNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) { diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index 99ff74d8c..a608340e7 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -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) } @@ -124,7 +124,7 @@ func TestPastUTXOMultiset(t *testing.T) { // 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) } diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go new file mode 100644 index 000000000..33cc1dcd4 --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go @@ -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 +} diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go new file mode 100644 index 000000000..f297295c5 --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go @@ -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") + } + }) +} diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index bf0dce418..f825e8025 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -28,11 +28,11 @@ func TestDoubleSpends(t *testing.T) { 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) @@ -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) } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index c87aed315..1d80d2458 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -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 { diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go index 3ab33082d..ab0e713d4 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -20,24 +20,24 @@ func TestIsAncestorOf(t *testing.T) { // 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) } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 8947c14d5..50162c744 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -331,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) } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index 256ce46df..cc66953a8 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -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) } diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index 21f446122..938bfe887 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -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) } diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index 1c7438c32..8d2674955 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -31,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) } @@ -40,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) } @@ -57,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) } @@ -85,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) } @@ -99,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) } @@ -120,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) } @@ -175,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) } @@ -195,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) } @@ -247,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) } @@ -270,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) } @@ -304,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) } @@ -312,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) } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 9088e005a..8c4d002c6 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -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() { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 3eb8fe3f6..739a502a9 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index d39caa5a1..e88ae9c9b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -439,7 +439,7 @@ message ChainBlock{ message AcceptedBlock{ string hash = 1; - repeated string acceptedTxIds = 2; + repeated string acceptedTransactionIds = 2; } message GetBlockRequestMessage{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go index ad503799e..84c00c28d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go @@ -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{ From 12379bedb633a43ab100fcc81d9437c4d5ad35e3 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 16 Dec 2020 11:27:43 +0200 Subject: [PATCH 132/351] Fix UTXO serialization errors (#1233) --- .../consensus/utils/serialization/common.go | 2 +- domain/consensus/utils/utxo/serialization.go | 16 +++------ .../utils/utxo/serialization_test.go | 36 +++++++++++++++++++ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/domain/consensus/utils/serialization/common.go b/domain/consensus/utils/serialization/common.go index ce15bcc3d..c66e6a5c7 100644 --- a/domain/consensus/utils/serialization/common.go +++ b/domain/consensus/utils/serialization/common.go @@ -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) } diff --git a/domain/consensus/utils/utxo/serialization.go b/domain/consensus/utils/utxo/serialization.go index 5ce29c774..19613e64b 100644 --- a/domain/consensus/utils/utxo/serialization.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -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) } diff --git a/domain/consensus/utils/utxo/serialization_test.go b/domain/consensus/utils/utxo/serialization_test.go index cb4c1a78f..928033fbf 100644 --- a/domain/consensus/utils/utxo/serialization_test.go +++ b/domain/consensus/utils/utxo/serialization_test.go @@ -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") + } +} From 1ebda36b179a05e755ed66d42c6963487e0333ad Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 16 Dec 2020 11:33:48 +0200 Subject: [PATCH 133/351] Remove IsAwaitingUTXOSet from validateAndInsertBlock log, to prevent long operation (#1235) --- .../blockprocessor/validateandinsertblock.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index d967f8924..56865f462 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -86,13 +86,10 @@ 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. Is awaiting UTXO set: %t. Block count: %d. Header count: %d", - virtualGhostDAGData.BlueScore(), syncInfo.IsAwaitingUTXOSet, 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 nil, logClosureErr From dc3ae4d3ac6778a4c964f0273b533fc060d0dd24 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 16 Dec 2020 12:50:17 +0200 Subject: [PATCH 134/351] Use pointer receivers when needed (#1237) --- .../coinbasemanager/coinbasemanager.go | 6 ++--- .../processes/coinbasemanager/payload.go | 4 ++-- .../test_consensus_state_manager.go | 4 ++-- .../update_pruning_utxo_set.go | 4 ++-- .../dagtraversalmanager/block_heap.go | 24 +++++++++---------- .../selected_child_iterator.go | 2 +- .../ghostdagmanager/ghostdag_test.go | 2 +- .../mergedepthmanager/merge_depth_manager.go | 2 +- .../test_reachabilitymanager.go | 6 ++--- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index 068b7fb48..268a23421 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -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 } diff --git a/domain/consensus/processes/coinbasemanager/payload.go b/domain/consensus/processes/coinbasemanager/payload.go index a6c989dae..5041072ed 100644 --- a/domain/consensus/processes/coinbasemanager/payload.go +++ b/domain/consensus/processes/coinbasemanager/payload.go @@ -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 diff --git a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go index 8efc08d84..db33399c7 100644 --- a/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go +++ b/domain/consensus/processes/consensusstatemanager/test_consensus_state_manager.go @@ -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) } diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index 0365b661e..cbca2911e 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -137,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) { diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go index 99b5113c0..def48f16e 100644 --- a/domain/consensus/processes/dagtraversalmanager/block_heap.go +++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go @@ -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, diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index 10d3023cc..cdce9fd6a 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -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 } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index f41c9cf16..a2d248cd1 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -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)) } diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index 66bb72a4e..ddb2835df 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -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 diff --git a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go index 8aa3d0660..89ede14e0 100644 --- a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go @@ -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 } From b510fc08a7c26185a8f664108e425cbdcabd8ab2 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 16 Dec 2020 13:33:10 +0200 Subject: [PATCH 135/351] Change PoW error (#1234) * Use proper error for invalid PoW * Add comment --- domain/consensus/processes/blockvalidator/proof_of_work.go | 2 +- domain/consensus/ruleerrors/rule_error.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index b83076c79..ffb38ba8a 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -97,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 diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 6d6c0fe97..4cd5e99d5 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -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 From 99a14c5999918054c6dfc8b2a48741dc5fd16b1b Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Wed, 16 Dec 2020 14:00:09 +0200 Subject: [PATCH 136/351] Update to version 0.8.4 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 76800bbe7..cd730c4fa 100644 --- a/version/version.go +++ b/version/version.go @@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 appMinor uint = 8 - appPatch uint = 3 + appPatch uint = 4 ) // appBuild is defined as a variable so it can be overridden during the build From bf67c6351e9ad966696fd01bf0f09ad6b9492c31 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 16 Dec 2020 14:49:55 +0200 Subject: [PATCH 137/351] Add TestPruning (#1222) * Add TestPruning * Add missing argument to teardown * Add missing return value to AddBlock --- .../processes/pruningmanager/pruning_test.go | 176 + .../testdata/chain-for-test-pruning.json | 3004 ++++ .../testdata/dag-for-test-pruning.json | 14196 ++++++++++++++++ 3 files changed, 17376 insertions(+) create mode 100644 domain/consensus/processes/pruningmanager/pruning_test.go create mode 100644 domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json create mode 100644 domain/consensus/processes/pruningmanager/testdata/dag-for-test-pruning.json diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go new file mode 100644 index 000000000..86ad3d352 --- /dev/null +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -0,0 +1,176 @@ +package pruningmanager_test + +import ( + "encoding/json" + "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" + "os" + "path/filepath" + "testing" + "time" +) + +type jsonBlock struct { + ID string `json:"ID"` + Parents []string `json:"Parents"` +} + +type testJSON struct { + MergeSetSizeLimit uint64 `json:"mergeSetSizeLimit"` + FinalityDepth uint64 `json:"finalityDepth"` + Blocks []*jsonBlock `json:"blocks"` +} + +func TestPruning(t *testing.T) { + expectedPruningPointByNet := map[string]map[string]string{ + "chain-for-test-pruning.json": { + "kaspa-mainnet": "84", + "kaspa-simnet": "84", + "kaspa-devnet": "84", + "kaspa-testnet": "84", + }, + "dag-for-test-pruning.json": { + "kaspa-mainnet": "503", + "kaspa-simnet": "502", + "kaspa-devnet": "502", + "kaspa-testnet": "502", + }, + } + + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + err := filepath.Walk("./testdata", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + + jsonFile, err := os.Open(path) + if err != nil { + t.Fatalf("TestPruning : failed opening json file %s: %s", path, err) + } + defer jsonFile.Close() + + test := &testJSON{} + decoder := json.NewDecoder(jsonFile) + decoder.DisallowUnknownFields() + err = decoder.Decode(&test) + if err != nil { + t.Fatalf("TestPruning: failed decoding json: %v", err) + } + + params.FinalityDuration = time.Duration(test.FinalityDepth) * params.TargetTimePerBlock + params.MergeSetSizeLimit = test.MergeSetSizeLimit + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, "TestPruning") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + blockIDToHash := map[string]*externalapi.DomainHash{ + "0": params.GenesisHash, + } + + blockHashToID := map[externalapi.DomainHash]string{ + *params.GenesisHash: "0", + } + + for _, dagBlock := range test.Blocks { + if dagBlock.ID == "0" { + continue + } + parentHashes := make([]*externalapi.DomainHash, 0, len(dagBlock.Parents)) + for _, parentID := range dagBlock.Parents { + parentHash, ok := blockIDToHash[parentID] + if !ok { + t.Fatalf("No hash was found for block with ID %s", parentID) + } + parentHashes = append(parentHashes, parentHash) + } + + blockHash, _, err := tc.AddBlock(parentHashes, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + blockIDToHash[dagBlock.ID] = blockHash + blockHashToID[*blockHash] = dagBlock.ID + } + + pruningPoint, err := tc.PruningStore().PruningPoint(tc.DatabaseContext()) + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + pruningPointID := blockHashToID[*pruningPoint] + expectedPruningPoint := expectedPruningPointByNet[info.Name()][params.Name] + if expectedPruningPoint != pruningPointID { + t.Fatalf("%s: Expected pruning point to be %s but got %s", info.Name(), expectedPruningPoint, pruningPointID) + } + + for _, jsonBlock := range test.Blocks { + id := jsonBlock.ID + blockHash := blockIDToHash[id] + + isPruningPointAncestorOfBlock, err := tc.DAGTopologyManager().IsAncestorOf(pruningPoint, blockHash) + if err != nil { + t.Fatalf("IsAncestorOf: %+v", err) + } + + expectsBlock := true + if !isPruningPointAncestorOfBlock { + isBlockAncestorOfPruningPoint, err := tc.DAGTopologyManager().IsAncestorOf(blockHash, pruningPoint) + if err != nil { + t.Fatalf("IsAncestorOf: %+v", err) + } + + if isBlockAncestorOfPruningPoint { + expectsBlock = false + } else { + virtualInfo, err := tc.GetVirtualInfo() + if err != nil { + t.Fatalf("GetVirtualInfo: %+v", err) + } + + isInPastOfVirtual := false + for _, virtualParent := range virtualInfo.ParentHashes { + isAncestorOfVirtualParent, err := tc.DAGTopologyManager().IsAncestorOf(blockHash, virtualParent) + if err != nil { + t.Fatalf("IsAncestorOf: %+v", err) + } + + if isAncestorOfVirtualParent { + isInPastOfVirtual = true + break + } + } + + if !isInPastOfVirtual { + expectsBlock = false + } + } + + } + + hasBlock, err := tc.BlockStore().HasBlock(tc.DatabaseContext(), blockHash) + if err != nil { + t.Fatalf("HasBlock: %+v", err) + } + + if expectsBlock != hasBlock { + t.Fatalf("expected hasBlock to be %t for block %s but got %t", expectsBlock, id, hasBlock) + } + } + + return nil + }) + if err != nil { + t.Fatalf("Walk: %+v", err) + } + }) +} diff --git a/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json b/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json new file mode 100644 index 000000000..3689af435 --- /dev/null +++ b/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json @@ -0,0 +1,3004 @@ +{ + "mergeSetSizeLimit": 5, + "finalityDepth": 7, + "blocks": [ + { + "id": "0", + "parents": [] + }, + { + "id": "1", + "parents": [ + "0" + ] + }, + { + "id": "2", + "parents": [ + "1" + ] + }, + { + "id": "3", + "parents": [ + "2" + ] + }, + { + "id": "4", + "parents": [ + "3" + ] + }, + { + "id": "5", + "parents": [ + "4" + ] + }, + { + "id": "6", + "parents": [ + "5" + ] + }, + { + "id": "7", + "parents": [ + "6" + ] + }, + { + "id": "8", + "parents": [ + "7" + ] + }, + { + "id": "9", + "parents": [ + "8" + ] + }, + { + "id": "10", + "parents": [ + "9" + ] + }, + { + "id": "11", + "parents": [ + "10" + ] + }, + { + "id": "12", + "parents": [ + "11" + ] + }, + { + "id": "13", + "parents": [ + "12" + ] + }, + { + "id": "14", + "parents": [ + "13" + ] + }, + { + "id": "15", + "parents": [ + "14" + ] + }, + { + "id": "16", + "parents": [ + "15" + ] + }, + { + "id": "17", + "parents": [ + "16" + ] + }, + { + "id": "18", + "parents": [ + "17" + ] + }, + { + "id": "19", + "parents": [ + "18" + ] + }, + { + "id": "20", + "parents": [ + "19" + ] + }, + { + "id": "21", + "parents": [ + "20" + ] + }, + { + "id": "22", + "parents": [ + "21" + ] + }, + { + "id": "23", + "parents": [ + "22" + ] + }, + { + "id": "24", + "parents": [ + "23" + ] + }, + { + "id": "25", + "parents": [ + "24" + ] + }, + { + "id": "26", + "parents": [ + "25" + ] + }, + { + "id": "27", + "parents": [ + "26" + ] + }, + { + "id": "28", + "parents": [ + "27" + ] + }, + { + "id": "29", + "parents": [ + "28" + ] + }, + { + "id": "30", + "parents": [ + "29" + ] + }, + { + "id": "31", + "parents": [ + "30" + ] + }, + { + "id": "32", + "parents": [ + "31" + ] + }, + { + "id": "33", + "parents": [ + "32" + ] + }, + { + "id": "34", + "parents": [ + "33" + ] + }, + { + "id": "35", + "parents": [ + "34" + ] + }, + { + "id": "36", + "parents": [ + "35" + ] + }, + { + "id": "37", + "parents": [ + "36" + ] + }, + { + "id": "38", + "parents": [ + "37" + ] + }, + { + "id": "39", + "parents": [ + "38" + ] + }, + { + "id": "40", + "parents": [ + "39" + ] + }, + { + "id": "41", + "parents": [ + "40" + ] + }, + { + "id": "42", + "parents": [ + "41" + ] + }, + { + "id": "43", + "parents": [ + "42" + ] + }, + { + "id": "44", + "parents": [ + "43" + ] + }, + { + "id": "45", + "parents": [ + "44" + ] + }, + { + "id": "46", + "parents": [ + "45" + ] + }, + { + "id": "47", + "parents": [ + "46" + ] + }, + { + "id": "48", + "parents": [ + "47" + ] + }, + { + "id": "49", + "parents": [ + "48" + ] + }, + { + "id": "50", + "parents": [ + "49" + ] + }, + { + "id": "51", + "parents": [ + "50" + ] + }, + { + "id": "52", + "parents": [ + "51" + ] + }, + { + "id": "53", + "parents": [ + "52" + ] + }, + { + "id": "54", + "parents": [ + "53" + ] + }, + { + "id": "55", + "parents": [ + "54" + ] + }, + { + "id": "56", + "parents": [ + "55" + ] + }, + { + "id": "57", + "parents": [ + "56" + ] + }, + { + "id": "58", + "parents": [ + "57" + ] + }, + { + "id": "59", + "parents": [ + "58" + ] + }, + { + "id": "60", + "parents": [ + "59" + ] + }, + { + "id": "61", + "parents": [ + "60" + ] + }, + { + "id": "62", + "parents": [ + "61" + ] + }, + { + "id": "63", + "parents": [ + "62" + ] + }, + { + "id": "64", + "parents": [ + "63" + ] + }, + { + "id": "65", + "parents": [ + "64" + ] + }, + { + "id": "66", + "parents": [ + "65" + ] + }, + { + "id": "67", + "parents": [ + "66" + ] + }, + { + "id": "68", + "parents": [ + "67" + ] + }, + { + "id": "69", + "parents": [ + "68" + ] + }, + { + "id": "70", + "parents": [ + "69" + ] + }, + { + "id": "71", + "parents": [ + "70" + ] + }, + { + "id": "72", + "parents": [ + "71" + ] + }, + { + "id": "73", + "parents": [ + "72" + ] + }, + { + "id": "74", + "parents": [ + "73" + ] + }, + { + "id": "75", + "parents": [ + "74" + ] + }, + { + "id": "76", + "parents": [ + "75" + ] + }, + { + "id": "77", + "parents": [ + "76" + ] + }, + { + "id": "78", + "parents": [ + "77" + ] + }, + { + "id": "79", + "parents": [ + "78" + ] + }, + { + "id": "80", + "parents": [ + "79" + ] + }, + { + "id": "81", + "parents": [ + "80" + ] + }, + { + "id": "82", + "parents": [ + "81" + ] + }, + { + "id": "83", + "parents": [ + "82" + ] + }, + { + "id": "84", + "parents": [ + "83" + ] + }, + { + "id": "85", + "parents": [ + "84" + ] + }, + { + "id": "86", + "parents": [ + "85" + ] + }, + { + "id": "87", + "parents": [ + "86" + ] + }, + { + "id": "88", + "parents": [ + "87" + ] + }, + { + "id": "89", + "parents": [ + "88" + ] + }, + { + "id": "90", + "parents": [ + "89" + ] + }, + { + "id": "91", + "parents": [ + "90" + ] + }, + { + "id": "92", + "parents": [ + "91" + ] + }, + { + "id": "93", + "parents": [ + "92" + ] + }, + { + "id": "94", + "parents": [ + "93" + ] + }, + { + "id": "95", + "parents": [ + "94" + ] + }, + { + "id": "96", + "parents": [ + "95" + ] + }, + { + "id": "97", + "parents": [ + "96" + ] + }, + { + "id": "98", + "parents": [ + "97" + ] + }, + { + "id": "99", + "parents": [ + "98" + ] + }, + { + "id": "100", + "parents": [ + "99" + ] + }, + { + "id": "101", + "parents": [ + "100" + ] + }, + { + "id": "102", + "parents": [ + "101" + ] + }, + { + "id": "103", + "parents": [ + "102" + ] + }, + { + "id": "104", + "parents": [ + "103" + ] + }, + { + "id": "105", + "parents": [ + "104" + ] + }, + { + "id": "106", + "parents": [ + "105" + ] + }, + { + "id": "107", + "parents": [ + "106" + ] + }, + { + "id": "108", + "parents": [ + "107" + ] + }, + { + "id": "109", + "parents": [ + "108" + ] + }, + { + "id": "110", + "parents": [ + "109" + ] + }, + { + "id": "111", + "parents": [ + "110" + ] + }, + { + "id": "112", + "parents": [ + "111" + ] + }, + { + "id": "113", + "parents": [ + "112" + ] + }, + { + "id": "114", + "parents": [ + "113" + ] + }, + { + "id": "115", + "parents": [ + "114" + ] + }, + { + "id": "116", + "parents": [ + "115" + ] + }, + { + "id": "117", + "parents": [ + "116" + ] + }, + { + "id": "118", + "parents": [ + "117" + ] + }, + { + "id": "119", + "parents": [ + "118" + ] + }, + { + "id": "120", + "parents": [ + "119" + ] + }, + { + "id": "121", + "parents": [ + "120" + ] + }, + { + "id": "122", + "parents": [ + "121" + ] + }, + { + "id": "123", + "parents": [ + "122" + ] + }, + { + "id": "124", + "parents": [ + "123" + ] + }, + { + "id": "125", + "parents": [ + "124" + ] + }, + { + "id": "126", + "parents": [ + "125" + ] + }, + { + "id": "127", + "parents": [ + "126" + ] + }, + { + "id": "128", + "parents": [ + "127" + ] + }, + { + "id": "129", + "parents": [ + "128" + ] + }, + { + "id": "130", + "parents": [ + "129" + ] + }, + { + "id": "131", + "parents": [ + "130" + ] + }, + { + "id": "132", + "parents": [ + "131" + ] + }, + { + "id": "133", + "parents": [ + "132" + ] + }, + { + "id": "134", + "parents": [ + "133" + ] + }, + { + "id": "135", + "parents": [ + "134" + ] + }, + { + "id": "136", + "parents": [ + "135" + ] + }, + { + "id": "137", + "parents": [ + "136" + ] + }, + { + "id": "138", + "parents": [ + "137" + ] + }, + { + "id": "139", + "parents": [ + "138" + ] + }, + { + "id": "140", + "parents": [ + "139" + ] + }, + { + "id": "141", + "parents": [ + "140" + ] + }, + { + "id": "142", + "parents": [ + "141" + ] + }, + { + "id": "143", + "parents": [ + "142" + ] + }, + { + "id": "144", + "parents": [ + "143" + ] + }, + { + "id": "145", + "parents": [ + "144" + ] + }, + { + "id": "146", + "parents": [ + "145" + ] + }, + { + "id": "147", + "parents": [ + "146" + ] + }, + { + "id": "148", + "parents": [ + "147" + ] + }, + { + "id": "149", + "parents": [ + "148" + ] + }, + { + "id": "150", + "parents": [ + "149" + ] + }, + { + "id": "151", + "parents": [ + "150" + ] + }, + { + "id": "152", + "parents": [ + "151" + ] + }, + { + "id": "153", + "parents": [ + "152" + ] + }, + { + "id": "154", + "parents": [ + "153" + ] + }, + { + "id": "155", + "parents": [ + "154" + ] + }, + { + "id": "156", + "parents": [ + "155" + ] + }, + { + "id": "157", + "parents": [ + "156" + ] + }, + { + "id": "158", + "parents": [ + "157" + ] + }, + { + "id": "159", + "parents": [ + "158" + ] + }, + { + "id": "160", + "parents": [ + "159" + ] + }, + { + "id": "161", + "parents": [ + "160" + ] + }, + { + "id": "162", + "parents": [ + "161" + ] + }, + { + "id": "163", + "parents": [ + "162" + ] + }, + { + "id": "164", + "parents": [ + "163" + ] + }, + { + "id": "165", + "parents": [ + "164" + ] + }, + { + "id": "166", + "parents": [ + "165" + ] + }, + { + "id": "167", + "parents": [ + "166" + ] + }, + { + "id": "168", + "parents": [ + "167" + ] + }, + { + "id": "169", + "parents": [ + "168" + ] + }, + { + "id": "170", + "parents": [ + "169" + ] + }, + { + "id": "171", + "parents": [ + "170" + ] + }, + { + "id": "172", + "parents": [ + "171" + ] + }, + { + "id": "173", + "parents": [ + "172" + ] + }, + { + "id": "174", + "parents": [ + "173" + ] + }, + { + "id": "175", + "parents": [ + "174" + ] + }, + { + "id": "176", + "parents": [ + "175" + ] + }, + { + "id": "177", + "parents": [ + "176" + ] + }, + { + "id": "178", + "parents": [ + "177" + ] + }, + { + "id": "179", + "parents": [ + "178" + ] + }, + { + "id": "180", + "parents": [ + "179" + ] + }, + { + "id": "181", + "parents": [ + "180" + ] + }, + { + "id": "182", + "parents": [ + "181" + ] + }, + { + "id": "183", + "parents": [ + "182" + ] + }, + { + "id": "184", + "parents": [ + "183" + ] + }, + { + "id": "185", + "parents": [ + "184" + ] + }, + { + "id": "186", + "parents": [ + "185" + ] + }, + { + "id": "187", + "parents": [ + "186" + ] + }, + { + "id": "188", + "parents": [ + "187" + ] + }, + { + "id": "189", + "parents": [ + "188" + ] + }, + { + "id": "190", + "parents": [ + "189" + ] + }, + { + "id": "191", + "parents": [ + "190" + ] + }, + { + "id": "192", + "parents": [ + "191" + ] + }, + { + "id": "193", + "parents": [ + "192" + ] + }, + { + "id": "194", + "parents": [ + "193" + ] + }, + { + "id": "195", + "parents": [ + "194" + ] + }, + { + "id": "196", + "parents": [ + "195" + ] + }, + { + "id": "197", + "parents": [ + "196" + ] + }, + { + "id": "198", + "parents": [ + "197" + ] + }, + { + "id": "199", + "parents": [ + "198" + ] + }, + { + "id": "200", + "parents": [ + "199" + ] + }, + { + "id": "201", + "parents": [ + "200" + ] + }, + { + "id": "202", + "parents": [ + "201" + ] + }, + { + "id": "203", + "parents": [ + "202" + ] + }, + { + "id": "204", + "parents": [ + "203" + ] + }, + { + "id": "205", + "parents": [ + "204" + ] + }, + { + "id": "206", + "parents": [ + "205" + ] + }, + { + "id": "207", + "parents": [ + "206" + ] + }, + { + "id": "208", + "parents": [ + "207" + ] + }, + { + "id": "209", + "parents": [ + "208" + ] + }, + { + "id": "210", + "parents": [ + "209" + ] + }, + { + "id": "211", + "parents": [ + "210" + ] + }, + { + "id": "212", + "parents": [ + "211" + ] + }, + { + "id": "213", + "parents": [ + "212" + ] + }, + { + "id": "214", + "parents": [ + "213" + ] + }, + { + "id": "215", + "parents": [ + "214" + ] + }, + { + "id": "216", + "parents": [ + "215" + ] + }, + { + "id": "217", + "parents": [ + "216" + ] + }, + { + "id": "218", + "parents": [ + "217" + ] + }, + { + "id": "219", + "parents": [ + "218" + ] + }, + { + "id": "220", + "parents": [ + "219" + ] + }, + { + "id": "221", + "parents": [ + "220" + ] + }, + { + "id": "222", + "parents": [ + "221" + ] + }, + { + "id": "223", + "parents": [ + "222" + ] + }, + { + "id": "224", + "parents": [ + "223" + ] + }, + { + "id": "225", + "parents": [ + "224" + ] + }, + { + "id": "226", + "parents": [ + "225" + ] + }, + { + "id": "227", + "parents": [ + "226" + ] + }, + { + "id": "228", + "parents": [ + "227" + ] + }, + { + "id": "229", + "parents": [ + "228" + ] + }, + { + "id": "230", + "parents": [ + "229" + ] + }, + { + "id": "231", + "parents": [ + "230" + ] + }, + { + "id": "232", + "parents": [ + "231" + ] + }, + { + "id": "233", + "parents": [ + "232" + ] + }, + { + "id": "234", + "parents": [ + "233" + ] + }, + { + "id": "235", + "parents": [ + "234" + ] + }, + { + "id": "236", + "parents": [ + "235" + ] + }, + { + "id": "237", + "parents": [ + "236" + ] + }, + { + "id": "238", + "parents": [ + "237" + ] + }, + { + "id": "239", + "parents": [ + "238" + ] + }, + { + "id": "240", + "parents": [ + "239" + ] + }, + { + "id": "241", + "parents": [ + "240" + ] + }, + { + "id": "242", + "parents": [ + "241" + ] + }, + { + "id": "243", + "parents": [ + "242" + ] + }, + { + "id": "244", + "parents": [ + "243" + ] + }, + { + "id": "245", + "parents": [ + "244" + ] + }, + { + "id": "246", + "parents": [ + "245" + ] + }, + { + "id": "247", + "parents": [ + "246" + ] + }, + { + "id": "248", + "parents": [ + "247" + ] + }, + { + "id": "249", + "parents": [ + "248" + ] + }, + { + "id": "250", + "parents": [ + "249" + ] + }, + { + "id": "251", + "parents": [ + "250" + ] + }, + { + "id": "252", + "parents": [ + "251" + ] + }, + { + "id": "253", + "parents": [ + "252" + ] + }, + { + "id": "254", + "parents": [ + "253" + ] + }, + { + "id": "255", + "parents": [ + "254" + ] + }, + { + "id": "256", + "parents": [ + "255" + ] + }, + { + "id": "257", + "parents": [ + "256" + ] + }, + { + "id": "258", + "parents": [ + "257" + ] + }, + { + "id": "259", + "parents": [ + "258" + ] + }, + { + "id": "260", + "parents": [ + "259" + ] + }, + { + "id": "261", + "parents": [ + "260" + ] + }, + { + "id": "262", + "parents": [ + "261" + ] + }, + { + "id": "263", + "parents": [ + "262" + ] + }, + { + "id": "264", + "parents": [ + "263" + ] + }, + { + "id": "265", + "parents": [ + "264" + ] + }, + { + "id": "266", + "parents": [ + "265" + ] + }, + { + "id": "267", + "parents": [ + "266" + ] + }, + { + "id": "268", + "parents": [ + "267" + ] + }, + { + "id": "269", + "parents": [ + "268" + ] + }, + { + "id": "270", + "parents": [ + "269" + ] + }, + { + "id": "271", + "parents": [ + "270" + ] + }, + { + "id": "272", + "parents": [ + "271" + ] + }, + { + "id": "273", + "parents": [ + "272" + ] + }, + { + "id": "274", + "parents": [ + "273" + ] + }, + { + "id": "275", + "parents": [ + "274" + ] + }, + { + "id": "276", + "parents": [ + "275" + ] + }, + { + "id": "277", + "parents": [ + "276" + ] + }, + { + "id": "278", + "parents": [ + "277" + ] + }, + { + "id": "279", + "parents": [ + "278" + ] + }, + { + "id": "280", + "parents": [ + "279" + ] + }, + { + "id": "281", + "parents": [ + "280" + ] + }, + { + "id": "282", + "parents": [ + "281" + ] + }, + { + "id": "283", + "parents": [ + "282" + ] + }, + { + "id": "284", + "parents": [ + "283" + ] + }, + { + "id": "285", + "parents": [ + "284" + ] + }, + { + "id": "286", + "parents": [ + "285" + ] + }, + { + "id": "287", + "parents": [ + "286" + ] + }, + { + "id": "288", + "parents": [ + "287" + ] + }, + { + "id": "289", + "parents": [ + "288" + ] + }, + { + "id": "290", + "parents": [ + "289" + ] + }, + { + "id": "291", + "parents": [ + "290" + ] + }, + { + "id": "292", + "parents": [ + "291" + ] + }, + { + "id": "293", + "parents": [ + "292" + ] + }, + { + "id": "294", + "parents": [ + "293" + ] + }, + { + "id": "295", + "parents": [ + "294" + ] + }, + { + "id": "296", + "parents": [ + "295" + ] + }, + { + "id": "297", + "parents": [ + "296" + ] + }, + { + "id": "298", + "parents": [ + "297" + ] + }, + { + "id": "299", + "parents": [ + "298" + ] + }, + { + "id": "300", + "parents": [ + "299" + ] + }, + { + "id": "301", + "parents": [ + "300" + ] + }, + { + "id": "302", + "parents": [ + "301" + ] + }, + { + "id": "303", + "parents": [ + "302" + ] + }, + { + "id": "304", + "parents": [ + "303" + ] + }, + { + "id": "305", + "parents": [ + "304" + ] + }, + { + "id": "306", + "parents": [ + "305" + ] + }, + { + "id": "307", + "parents": [ + "306" + ] + }, + { + "id": "308", + "parents": [ + "307" + ] + }, + { + "id": "309", + "parents": [ + "308" + ] + }, + { + "id": "310", + "parents": [ + "309" + ] + }, + { + "id": "311", + "parents": [ + "310" + ] + }, + { + "id": "312", + "parents": [ + "311" + ] + }, + { + "id": "313", + "parents": [ + "312" + ] + }, + { + "id": "314", + "parents": [ + "313" + ] + }, + { + "id": "315", + "parents": [ + "314" + ] + }, + { + "id": "316", + "parents": [ + "315" + ] + }, + { + "id": "317", + "parents": [ + "316" + ] + }, + { + "id": "318", + "parents": [ + "317" + ] + }, + { + "id": "319", + "parents": [ + "318" + ] + }, + { + "id": "320", + "parents": [ + "319" + ] + }, + { + "id": "321", + "parents": [ + "320" + ] + }, + { + "id": "322", + "parents": [ + "321" + ] + }, + { + "id": "323", + "parents": [ + "322" + ] + }, + { + "id": "324", + "parents": [ + "323" + ] + }, + { + "id": "325", + "parents": [ + "324" + ] + }, + { + "id": "326", + "parents": [ + "325" + ] + }, + { + "id": "327", + "parents": [ + "326" + ] + }, + { + "id": "328", + "parents": [ + "327" + ] + }, + { + "id": "329", + "parents": [ + "328" + ] + }, + { + "id": "330", + "parents": [ + "329" + ] + }, + { + "id": "331", + "parents": [ + "330" + ] + }, + { + "id": "332", + "parents": [ + "331" + ] + }, + { + "id": "333", + "parents": [ + "332" + ] + }, + { + "id": "334", + "parents": [ + "333" + ] + }, + { + "id": "335", + "parents": [ + "334" + ] + }, + { + "id": "336", + "parents": [ + "335" + ] + }, + { + "id": "337", + "parents": [ + "336" + ] + }, + { + "id": "338", + "parents": [ + "337" + ] + }, + { + "id": "339", + "parents": [ + "338" + ] + }, + { + "id": "340", + "parents": [ + "339" + ] + }, + { + "id": "341", + "parents": [ + "340" + ] + }, + { + "id": "342", + "parents": [ + "341" + ] + }, + { + "id": "343", + "parents": [ + "342" + ] + }, + { + "id": "344", + "parents": [ + "343" + ] + }, + { + "id": "345", + "parents": [ + "344" + ] + }, + { + "id": "346", + "parents": [ + "345" + ] + }, + { + "id": "347", + "parents": [ + "346" + ] + }, + { + "id": "348", + "parents": [ + "347" + ] + }, + { + "id": "349", + "parents": [ + "348" + ] + }, + { + "id": "350", + "parents": [ + "349" + ] + }, + { + "id": "351", + "parents": [ + "350" + ] + }, + { + "id": "352", + "parents": [ + "351" + ] + }, + { + "id": "353", + "parents": [ + "352" + ] + }, + { + "id": "354", + "parents": [ + "353" + ] + }, + { + "id": "355", + "parents": [ + "354" + ] + }, + { + "id": "356", + "parents": [ + "355" + ] + }, + { + "id": "357", + "parents": [ + "356" + ] + }, + { + "id": "358", + "parents": [ + "357" + ] + }, + { + "id": "359", + "parents": [ + "358" + ] + }, + { + "id": "360", + "parents": [ + "359" + ] + }, + { + "id": "361", + "parents": [ + "360" + ] + }, + { + "id": "362", + "parents": [ + "361" + ] + }, + { + "id": "363", + "parents": [ + "362" + ] + }, + { + "id": "364", + "parents": [ + "363" + ] + }, + { + "id": "365", + "parents": [ + "364" + ] + }, + { + "id": "366", + "parents": [ + "365" + ] + }, + { + "id": "367", + "parents": [ + "366" + ] + }, + { + "id": "368", + "parents": [ + "367" + ] + }, + { + "id": "369", + "parents": [ + "368" + ] + }, + { + "id": "370", + "parents": [ + "369" + ] + }, + { + "id": "371", + "parents": [ + "370" + ] + }, + { + "id": "372", + "parents": [ + "371" + ] + }, + { + "id": "373", + "parents": [ + "372" + ] + }, + { + "id": "374", + "parents": [ + "373" + ] + }, + { + "id": "375", + "parents": [ + "374" + ] + }, + { + "id": "376", + "parents": [ + "375" + ] + }, + { + "id": "377", + "parents": [ + "376" + ] + }, + { + "id": "378", + "parents": [ + "377" + ] + }, + { + "id": "379", + "parents": [ + "378" + ] + }, + { + "id": "380", + "parents": [ + "379" + ] + }, + { + "id": "381", + "parents": [ + "380" + ] + }, + { + "id": "382", + "parents": [ + "381" + ] + }, + { + "id": "383", + "parents": [ + "382" + ] + }, + { + "id": "384", + "parents": [ + "383" + ] + }, + { + "id": "385", + "parents": [ + "384" + ] + }, + { + "id": "386", + "parents": [ + "385" + ] + }, + { + "id": "387", + "parents": [ + "386" + ] + }, + { + "id": "388", + "parents": [ + "387" + ] + }, + { + "id": "389", + "parents": [ + "388" + ] + }, + { + "id": "390", + "parents": [ + "389" + ] + }, + { + "id": "391", + "parents": [ + "390" + ] + }, + { + "id": "392", + "parents": [ + "391" + ] + }, + { + "id": "393", + "parents": [ + "392" + ] + }, + { + "id": "394", + "parents": [ + "393" + ] + }, + { + "id": "395", + "parents": [ + "394" + ] + }, + { + "id": "396", + "parents": [ + "395" + ] + }, + { + "id": "397", + "parents": [ + "396" + ] + }, + { + "id": "398", + "parents": [ + "397" + ] + }, + { + "id": "399", + "parents": [ + "398" + ] + }, + { + "id": "400", + "parents": [ + "399" + ] + }, + { + "id": "401", + "parents": [ + "400" + ] + }, + { + "id": "402", + "parents": [ + "401" + ] + }, + { + "id": "403", + "parents": [ + "402" + ] + }, + { + "id": "404", + "parents": [ + "403" + ] + }, + { + "id": "405", + "parents": [ + "404" + ] + }, + { + "id": "406", + "parents": [ + "405" + ] + }, + { + "id": "407", + "parents": [ + "406" + ] + }, + { + "id": "408", + "parents": [ + "407" + ] + }, + { + "id": "409", + "parents": [ + "408" + ] + }, + { + "id": "410", + "parents": [ + "409" + ] + }, + { + "id": "411", + "parents": [ + "410" + ] + }, + { + "id": "412", + "parents": [ + "411" + ] + }, + { + "id": "413", + "parents": [ + "412" + ] + }, + { + "id": "414", + "parents": [ + "413" + ] + }, + { + "id": "415", + "parents": [ + "414" + ] + }, + { + "id": "416", + "parents": [ + "415" + ] + }, + { + "id": "417", + "parents": [ + "416" + ] + }, + { + "id": "418", + "parents": [ + "417" + ] + }, + { + "id": "419", + "parents": [ + "418" + ] + }, + { + "id": "420", + "parents": [ + "419" + ] + }, + { + "id": "421", + "parents": [ + "420" + ] + }, + { + "id": "422", + "parents": [ + "421" + ] + }, + { + "id": "423", + "parents": [ + "422" + ] + }, + { + "id": "424", + "parents": [ + "423" + ] + }, + { + "id": "425", + "parents": [ + "424" + ] + }, + { + "id": "426", + "parents": [ + "425" + ] + }, + { + "id": "427", + "parents": [ + "426" + ] + }, + { + "id": "428", + "parents": [ + "427" + ] + }, + { + "id": "429", + "parents": [ + "428" + ] + }, + { + "id": "430", + "parents": [ + "429" + ] + }, + { + "id": "431", + "parents": [ + "430" + ] + }, + { + "id": "432", + "parents": [ + "431" + ] + }, + { + "id": "433", + "parents": [ + "432" + ] + }, + { + "id": "434", + "parents": [ + "433" + ] + }, + { + "id": "435", + "parents": [ + "434" + ] + }, + { + "id": "436", + "parents": [ + "435" + ] + }, + { + "id": "437", + "parents": [ + "436" + ] + }, + { + "id": "438", + "parents": [ + "437" + ] + }, + { + "id": "439", + "parents": [ + "438" + ] + }, + { + "id": "440", + "parents": [ + "439" + ] + }, + { + "id": "441", + "parents": [ + "440" + ] + }, + { + "id": "442", + "parents": [ + "441" + ] + }, + { + "id": "443", + "parents": [ + "442" + ] + }, + { + "id": "444", + "parents": [ + "443" + ] + }, + { + "id": "445", + "parents": [ + "444" + ] + }, + { + "id": "446", + "parents": [ + "445" + ] + }, + { + "id": "447", + "parents": [ + "446" + ] + }, + { + "id": "448", + "parents": [ + "447" + ] + }, + { + "id": "449", + "parents": [ + "448" + ] + }, + { + "id": "450", + "parents": [ + "449" + ] + }, + { + "id": "451", + "parents": [ + "450" + ] + }, + { + "id": "452", + "parents": [ + "451" + ] + }, + { + "id": "453", + "parents": [ + "452" + ] + }, + { + "id": "454", + "parents": [ + "453" + ] + }, + { + "id": "455", + "parents": [ + "454" + ] + }, + { + "id": "456", + "parents": [ + "455" + ] + }, + { + "id": "457", + "parents": [ + "456" + ] + }, + { + "id": "458", + "parents": [ + "457" + ] + }, + { + "id": "459", + "parents": [ + "458" + ] + }, + { + "id": "460", + "parents": [ + "459" + ] + }, + { + "id": "461", + "parents": [ + "460" + ] + }, + { + "id": "462", + "parents": [ + "461" + ] + }, + { + "id": "463", + "parents": [ + "462" + ] + }, + { + "id": "464", + "parents": [ + "463" + ] + }, + { + "id": "465", + "parents": [ + "464" + ] + }, + { + "id": "466", + "parents": [ + "465" + ] + }, + { + "id": "467", + "parents": [ + "466" + ] + }, + { + "id": "468", + "parents": [ + "467" + ] + }, + { + "id": "469", + "parents": [ + "468" + ] + }, + { + "id": "470", + "parents": [ + "469" + ] + }, + { + "id": "471", + "parents": [ + "470" + ] + }, + { + "id": "472", + "parents": [ + "471" + ] + }, + { + "id": "473", + "parents": [ + "472" + ] + }, + { + "id": "474", + "parents": [ + "473" + ] + }, + { + "id": "475", + "parents": [ + "474" + ] + }, + { + "id": "476", + "parents": [ + "475" + ] + }, + { + "id": "477", + "parents": [ + "476" + ] + }, + { + "id": "478", + "parents": [ + "477" + ] + }, + { + "id": "479", + "parents": [ + "478" + ] + }, + { + "id": "480", + "parents": [ + "479" + ] + }, + { + "id": "481", + "parents": [ + "480" + ] + }, + { + "id": "482", + "parents": [ + "481" + ] + }, + { + "id": "483", + "parents": [ + "482" + ] + }, + { + "id": "484", + "parents": [ + "483" + ] + }, + { + "id": "485", + "parents": [ + "484" + ] + }, + { + "id": "486", + "parents": [ + "485" + ] + }, + { + "id": "487", + "parents": [ + "486" + ] + }, + { + "id": "488", + "parents": [ + "487" + ] + }, + { + "id": "489", + "parents": [ + "488" + ] + }, + { + "id": "490", + "parents": [ + "489" + ] + }, + { + "id": "491", + "parents": [ + "490" + ] + }, + { + "id": "492", + "parents": [ + "491" + ] + }, + { + "id": "493", + "parents": [ + "492" + ] + }, + { + "id": "494", + "parents": [ + "493" + ] + }, + { + "id": "495", + "parents": [ + "494" + ] + }, + { + "id": "496", + "parents": [ + "495" + ] + }, + { + "id": "497", + "parents": [ + "496" + ] + }, + { + "id": "498", + "parents": [ + "497" + ] + }, + { + "id": "499", + "parents": [ + "498" + ] + } + ] +} \ No newline at end of file diff --git a/domain/consensus/processes/pruningmanager/testdata/dag-for-test-pruning.json b/domain/consensus/processes/pruningmanager/testdata/dag-for-test-pruning.json new file mode 100644 index 000000000..8d0d5c8b5 --- /dev/null +++ b/domain/consensus/processes/pruningmanager/testdata/dag-for-test-pruning.json @@ -0,0 +1,14196 @@ +{ + "mergeSetSizeLimit": 20, + "finalityDepth": 20, + "blocks": [ + { + "id": "0", + "parents": [] + }, + { + "id": "1", + "parents": [ + "0" + ] + }, + { + "id": "2", + "parents": [ + "0" + ] + }, + { + "id": "3", + "parents": [ + "0" + ] + }, + { + "id": "4", + "parents": [ + "2", + "1", + "3" + ] + }, + { + "id": "5", + "parents": [ + "4" + ] + }, + { + "id": "6", + "parents": [ + "5" + ] + }, + { + "id": "7", + "parents": [ + "4" + ] + }, + { + "id": "8", + "parents": [ + "5", + "7" + ] + }, + { + "id": "9", + "parents": [ + "5" + ] + }, + { + "id": "10", + "parents": [ + "7" + ] + }, + { + "id": "11", + "parents": [ + "5", + "10" + ] + }, + { + "id": "12", + "parents": [ + "6", + "11", + "9", + "8" + ] + }, + { + "id": "13", + "parents": [ + "11", + "8", + "6", + "9" + ] + }, + { + "id": "14", + "parents": [ + "13" + ] + }, + { + "id": "15", + "parents": [ + "6", + "8", + "11", + "9" + ] + }, + { + "id": "16", + "parents": [ + "13", + "12" + ] + }, + { + "id": "17", + "parents": [ + "14", + "12" + ] + }, + { + "id": "18", + "parents": [ + "12", + "13" + ] + }, + { + "id": "19", + "parents": [ + "16", + "17", + "15" + ] + }, + { + "id": "20", + "parents": [ + "18", + "19" + ] + }, + { + "id": "21", + "parents": [ + "14", + "15", + "16" + ] + }, + { + "id": "22", + "parents": [ + "18", + "17", + "21" + ] + }, + { + "id": "23", + "parents": [ + "22", + "20" + ] + }, + { + "id": "24", + "parents": [ + "23" + ] + }, + { + "id": "25", + "parents": [ + "23" + ] + }, + { + "id": "26", + "parents": [ + "25" + ] + }, + { + "id": "27", + "parents": [ + "24", + "25" + ] + }, + { + "id": "28", + "parents": [ + "26" + ] + }, + { + "id": "29", + "parents": [ + "25", + "24" + ] + }, + { + "id": "30", + "parents": [ + "24", + "28" + ] + }, + { + "id": "31", + "parents": [ + "30" + ] + }, + { + "id": "32", + "parents": [ + "31", + "29", + "27" + ] + }, + { + "id": "33", + "parents": [ + "32" + ] + }, + { + "id": "34", + "parents": [ + "32" + ] + }, + { + "id": "35", + "parents": [ + "34", + "33" + ] + }, + { + "id": "36", + "parents": [ + "34", + "33" + ] + }, + { + "id": "37", + "parents": [ + "35" + ] + }, + { + "id": "38", + "parents": [ + "36" + ] + }, + { + "id": "39", + "parents": [ + "36", + "35" + ] + }, + { + "id": "40", + "parents": [ + "39" + ] + }, + { + "id": "41", + "parents": [ + "37", + "38" + ] + }, + { + "id": "42", + "parents": [ + "41" + ] + }, + { + "id": "43", + "parents": [ + "38" + ] + }, + { + "id": "44", + "parents": [ + "43", + "39", + "41" + ] + }, + { + "id": "45", + "parents": [ + "41", + "40", + "43" + ] + }, + { + "id": "46", + "parents": [ + "42", + "44", + "45" + ] + }, + { + "id": "47", + "parents": [ + "42", + "44", + "45" + ] + }, + { + "id": "48", + "parents": [ + "46", + "47" + ] + }, + { + "id": "49", + "parents": [ + "47" + ] + }, + { + "id": "50", + "parents": [ + "39", + "41", + "43" + ] + }, + { + "id": "51", + "parents": [ + "50", + "46" + ] + }, + { + "id": "52", + "parents": [ + "48", + "51", + "49" + ] + }, + { + "id": "53", + "parents": [ + "48", + "51", + "49" + ] + }, + { + "id": "54", + "parents": [ + "53", + "52" + ] + }, + { + "id": "55", + "parents": [ + "54" + ] + }, + { + "id": "56", + "parents": [ + "54" + ] + }, + { + "id": "57", + "parents": [ + "54" + ] + }, + { + "id": "58", + "parents": [ + "57", + "55", + "56" + ] + }, + { + "id": "59", + "parents": [ + "56", + "57", + "55" + ] + }, + { + "id": "60", + "parents": [ + "58", + "59" + ] + }, + { + "id": "61", + "parents": [ + "59", + "58" + ] + }, + { + "id": "62", + "parents": [ + "61", + "60" + ] + }, + { + "id": "63", + "parents": [ + "62" + ] + }, + { + "id": "64", + "parents": [ + "61", + "60" + ] + }, + { + "id": "65", + "parents": [ + "64", + "63" + ] + }, + { + "id": "66", + "parents": [ + "65" + ] + }, + { + "id": "67", + "parents": [ + "63", + "64" + ] + }, + { + "id": "68", + "parents": [ + "63", + "64" + ] + }, + { + "id": "69", + "parents": [ + "66", + "68", + "67" + ] + }, + { + "id": "70", + "parents": [ + "69" + ] + }, + { + "id": "71", + "parents": [ + "69" + ] + }, + { + "id": "72", + "parents": [ + "71", + "70" + ] + }, + { + "id": "73", + "parents": [ + "69" + ] + }, + { + "id": "74", + "parents": [ + "72", + "73" + ] + }, + { + "id": "75", + "parents": [ + "72", + "73" + ] + }, + { + "id": "76", + "parents": [ + "73", + "72" + ] + }, + { + "id": "77", + "parents": [ + "75" + ] + }, + { + "id": "78", + "parents": [ + "77", + "74", + "76" + ] + }, + { + "id": "79", + "parents": [ + "74", + "75", + "76" + ] + }, + { + "id": "80", + "parents": [ + "74", + "76", + "77" + ] + }, + { + "id": "81", + "parents": [ + "79", + "80" + ] + }, + { + "id": "82", + "parents": [ + "78", + "81" + ] + }, + { + "id": "83", + "parents": [ + "79", + "80", + "78" + ] + }, + { + "id": "84", + "parents": [ + "78", + "79", + "80" + ] + }, + { + "id": "85", + "parents": [ + "84" + ] + }, + { + "id": "86", + "parents": [ + "82", + "84" + ] + }, + { + "id": "87", + "parents": [ + "82" + ] + }, + { + "id": "88", + "parents": [ + "85" + ] + }, + { + "id": "89", + "parents": [ + "86", + "87", + "88", + "83" + ] + }, + { + "id": "90", + "parents": [ + "86", + "87", + "88", + "83" + ] + }, + { + "id": "91", + "parents": [ + "89" + ] + }, + { + "id": "92", + "parents": [ + "91", + "90" + ] + }, + { + "id": "93", + "parents": [ + "89" + ] + }, + { + "id": "94", + "parents": [ + "91", + "90" + ] + }, + { + "id": "95", + "parents": [ + "93" + ] + }, + { + "id": "96", + "parents": [ + "91", + "90", + "93" + ] + }, + { + "id": "97", + "parents": [ + "93", + "91", + "90" + ] + }, + { + "id": "98", + "parents": [ + "94" + ] + }, + { + "id": "99", + "parents": [ + "97", + "96", + "95", + "98" + ] + }, + { + "id": "100", + "parents": [ + "99" + ] + }, + { + "id": "101", + "parents": [ + "99", + "92" + ] + }, + { + "id": "102", + "parents": [ + "96", + "95", + "98", + "92", + "97" + ] + }, + { + "id": "103", + "parents": [ + "100", + "92" + ] + }, + { + "id": "104", + "parents": [ + "103", + "102", + "101" + ] + }, + { + "id": "105", + "parents": [ + "101", + "103", + "102" + ] + }, + { + "id": "106", + "parents": [ + "105", + "104" + ] + }, + { + "id": "107", + "parents": [ + "104", + "105" + ] + }, + { + "id": "108", + "parents": [ + "104", + "105" + ] + }, + { + "id": "109", + "parents": [ + "104", + "105" + ] + }, + { + "id": "110", + "parents": [ + "109" + ] + }, + { + "id": "111", + "parents": [ + "105", + "104" + ] + }, + { + "id": "112", + "parents": [ + "108", + "111", + "107" + ] + }, + { + "id": "113", + "parents": [ + "112", + "110", + "106" + ] + }, + { + "id": "114", + "parents": [ + "113" + ] + }, + { + "id": "115", + "parents": [ + "113" + ] + }, + { + "id": "116", + "parents": [ + "110", + "106", + "112" + ] + }, + { + "id": "117", + "parents": [ + "116", + "114", + "115" + ] + }, + { + "id": "118", + "parents": [ + "115", + "114", + "116" + ] + }, + { + "id": "119", + "parents": [ + "117", + "118" + ] + }, + { + "id": "120", + "parents": [ + "119" + ] + }, + { + "id": "121", + "parents": [ + "120" + ] + }, + { + "id": "122", + "parents": [ + "114", + "116", + "115" + ] + }, + { + "id": "123", + "parents": [ + "122", + "121" + ] + }, + { + "id": "124", + "parents": [ + "122", + "119" + ] + }, + { + "id": "125", + "parents": [ + "122", + "119" + ] + }, + { + "id": "126", + "parents": [ + "125" + ] + }, + { + "id": "127", + "parents": [ + "123", + "124", + "125" + ] + }, + { + "id": "128", + "parents": [ + "126", + "127" + ] + }, + { + "id": "129", + "parents": [ + "128" + ] + }, + { + "id": "130", + "parents": [ + "126", + "127" + ] + }, + { + "id": "131", + "parents": [ + "130", + "129" + ] + }, + { + "id": "132", + "parents": [ + "129", + "130" + ] + }, + { + "id": "133", + "parents": [ + "130", + "129" + ] + }, + { + "id": "134", + "parents": [ + "132", + "133" + ] + }, + { + "id": "135", + "parents": [ + "132", + "131", + "133" + ] + }, + { + "id": "136", + "parents": [ + "131", + "134" + ] + }, + { + "id": "137", + "parents": [ + "134", + "135" + ] + }, + { + "id": "138", + "parents": [ + "136", + "137" + ] + }, + { + "id": "139", + "parents": [ + "136", + "137" + ] + }, + { + "id": "140", + "parents": [ + "136", + "135" + ] + }, + { + "id": "141", + "parents": [ + "138", + "139", + "140" + ] + }, + { + "id": "142", + "parents": [ + "141" + ] + }, + { + "id": "143", + "parents": [ + "141" + ] + }, + { + "id": "144", + "parents": [ + "141" + ] + }, + { + "id": "145", + "parents": [ + "142", + "144" + ] + }, + { + "id": "146", + "parents": [ + "145", + "143" + ] + }, + { + "id": "147", + "parents": [ + "146" + ] + }, + { + "id": "148", + "parents": [ + "146" + ] + }, + { + "id": "149", + "parents": [ + "147" + ] + }, + { + "id": "150", + "parents": [ + "148", + "149" + ] + }, + { + "id": "151", + "parents": [ + "149" + ] + }, + { + "id": "152", + "parents": [ + "147", + "148" + ] + }, + { + "id": "153", + "parents": [ + "148" + ] + }, + { + "id": "154", + "parents": [ + "148", + "149" + ] + }, + { + "id": "155", + "parents": [ + "147" + ] + }, + { + "id": "156", + "parents": [ + "155", + "153", + "150", + "151" + ] + }, + { + "id": "157", + "parents": [ + "150", + "153", + "151" + ] + }, + { + "id": "158", + "parents": [ + "156", + "157", + "154", + "152" + ] + }, + { + "id": "159", + "parents": [ + "158" + ] + }, + { + "id": "160", + "parents": [ + "158" + ] + }, + { + "id": "161", + "parents": [ + "160" + ] + }, + { + "id": "162", + "parents": [ + "160" + ] + }, + { + "id": "163", + "parents": [ + "161", + "159", + "162" + ] + }, + { + "id": "164", + "parents": [ + "163" + ] + }, + { + "id": "165", + "parents": [ + "161", + "162", + "159" + ] + }, + { + "id": "166", + "parents": [ + "162", + "159", + "161" + ] + }, + { + "id": "167", + "parents": [ + "166" + ] + }, + { + "id": "168", + "parents": [ + "164", + "167", + "165" + ] + }, + { + "id": "169", + "parents": [ + "168" + ] + }, + { + "id": "170", + "parents": [ + "168" + ] + }, + { + "id": "171", + "parents": [ + "169" + ] + }, + { + "id": "172", + "parents": [ + "171", + "170" + ] + }, + { + "id": "173", + "parents": [ + "172" + ] + }, + { + "id": "174", + "parents": [ + "172" + ] + }, + { + "id": "175", + "parents": [ + "172" + ] + }, + { + "id": "176", + "parents": [ + "173", + "174" + ] + }, + { + "id": "177", + "parents": [ + "175", + "176" + ] + }, + { + "id": "178", + "parents": [ + "174", + "173" + ] + }, + { + "id": "179", + "parents": [ + "178", + "177" + ] + }, + { + "id": "180", + "parents": [ + "179" + ] + }, + { + "id": "181", + "parents": [ + "180" + ] + }, + { + "id": "182", + "parents": [ + "179" + ] + }, + { + "id": "183", + "parents": [ + "181", + "182" + ] + }, + { + "id": "184", + "parents": [ + "182", + "181" + ] + }, + { + "id": "185", + "parents": [ + "184" + ] + }, + { + "id": "186", + "parents": [ + "183", + "185" + ] + }, + { + "id": "187", + "parents": [ + "181", + "182" + ] + }, + { + "id": "188", + "parents": [ + "187", + "186" + ] + }, + { + "id": "189", + "parents": [ + "187", + "186" + ] + }, + { + "id": "190", + "parents": [ + "189" + ] + }, + { + "id": "191", + "parents": [ + "190", + "188" + ] + }, + { + "id": "192", + "parents": [ + "191" + ] + }, + { + "id": "193", + "parents": [ + "192" + ] + }, + { + "id": "194", + "parents": [ + "192" + ] + }, + { + "id": "195", + "parents": [ + "193", + "194" + ] + }, + { + "id": "196", + "parents": [ + "195" + ] + }, + { + "id": "197", + "parents": [ + "196" + ] + }, + { + "id": "198", + "parents": [ + "195" + ] + }, + { + "id": "199", + "parents": [ + "198" + ] + }, + { + "id": "200", + "parents": [ + "197", + "198" + ] + }, + { + "id": "201", + "parents": [ + "199", + "197" + ] + }, + { + "id": "202", + "parents": [ + "201", + "200" + ] + }, + { + "id": "203", + "parents": [ + "200", + "201" + ] + }, + { + "id": "204", + "parents": [ + "203" + ] + }, + { + "id": "205", + "parents": [ + "204" + ] + }, + { + "id": "206", + "parents": [ + "201", + "200" + ] + }, + { + "id": "207", + "parents": [ + "201", + "200" + ] + }, + { + "id": "208", + "parents": [ + "202", + "205", + "207", + "206" + ] + }, + { + "id": "209", + "parents": [ + "205", + "202", + "206", + "207" + ] + }, + { + "id": "210", + "parents": [ + "208", + "209" + ] + }, + { + "id": "211", + "parents": [ + "209", + "208" + ] + }, + { + "id": "212", + "parents": [ + "208", + "209" + ] + }, + { + "id": "213", + "parents": [ + "211", + "210" + ] + }, + { + "id": "214", + "parents": [ + "212", + "210" + ] + }, + { + "id": "215", + "parents": [ + "214", + "211" + ] + }, + { + "id": "216", + "parents": [ + "213", + "212" + ] + }, + { + "id": "217", + "parents": [ + "212" + ] + }, + { + "id": "218", + "parents": [ + "214", + "211", + "217" + ] + }, + { + "id": "219", + "parents": [ + "215", + "213", + "218" + ] + }, + { + "id": "220", + "parents": [ + "216", + "219" + ] + }, + { + "id": "221", + "parents": [ + "220" + ] + }, + { + "id": "222", + "parents": [ + "216", + "219" + ] + }, + { + "id": "223", + "parents": [ + "220", + "222" + ] + }, + { + "id": "224", + "parents": [ + "223", + "221" + ] + }, + { + "id": "225", + "parents": [ + "222", + "220" + ] + }, + { + "id": "226", + "parents": [ + "225", + "221", + "223" + ] + }, + { + "id": "227", + "parents": [ + "221", + "225", + "223" + ] + }, + { + "id": "228", + "parents": [ + "227", + "226" + ] + }, + { + "id": "229", + "parents": [ + "228", + "224" + ] + }, + { + "id": "230", + "parents": [ + "224", + "227", + "226" + ] + }, + { + "id": "231", + "parents": [ + "224", + "227", + "226" + ] + }, + { + "id": "232", + "parents": [ + "230", + "231", + "229" + ] + }, + { + "id": "233", + "parents": [ + "228", + "224" + ] + }, + { + "id": "234", + "parents": [ + "226", + "224" + ] + }, + { + "id": "235", + "parents": [ + "233", + "232" + ] + }, + { + "id": "236", + "parents": [ + "230", + "233", + "234", + "231" + ] + }, + { + "id": "237", + "parents": [ + "236", + "235" + ] + }, + { + "id": "238", + "parents": [ + "235", + "236" + ] + }, + { + "id": "239", + "parents": [ + "236", + "235" + ] + }, + { + "id": "240", + "parents": [ + "237" + ] + }, + { + "id": "241", + "parents": [ + "240" + ] + }, + { + "id": "242", + "parents": [ + "239", + "241" + ] + }, + { + "id": "243", + "parents": [ + "241", + "238" + ] + }, + { + "id": "244", + "parents": [ + "242", + "238" + ] + }, + { + "id": "245", + "parents": [ + "238", + "242" + ] + }, + { + "id": "246", + "parents": [ + "245", + "243", + "244" + ] + }, + { + "id": "247", + "parents": [ + "245", + "243", + "244" + ] + }, + { + "id": "248", + "parents": [ + "247", + "246" + ] + }, + { + "id": "249", + "parents": [ + "248" + ] + }, + { + "id": "250", + "parents": [ + "247" + ] + }, + { + "id": "251", + "parents": [ + "246", + "250" + ] + }, + { + "id": "252", + "parents": [ + "251" + ] + }, + { + "id": "253", + "parents": [ + "252" + ] + }, + { + "id": "254", + "parents": [ + "249", + "253" + ] + }, + { + "id": "255", + "parents": [ + "253", + "249" + ] + }, + { + "id": "256", + "parents": [ + "255", + "254" + ] + }, + { + "id": "257", + "parents": [ + "256" + ] + }, + { + "id": "258", + "parents": [ + "257" + ] + }, + { + "id": "259", + "parents": [ + "257" + ] + }, + { + "id": "260", + "parents": [ + "259" + ] + }, + { + "id": "261", + "parents": [ + "258", + "259" + ] + }, + { + "id": "262", + "parents": [ + "258", + "259" + ] + }, + { + "id": "263", + "parents": [ + "261", + "262", + "260" + ] + }, + { + "id": "264", + "parents": [ + "263" + ] + }, + { + "id": "265", + "parents": [ + "261", + "260", + "262" + ] + }, + { + "id": "266", + "parents": [ + "264" + ] + }, + { + "id": "267", + "parents": [ + "264" + ] + }, + { + "id": "268", + "parents": [ + "265", + "267", + "266" + ] + }, + { + "id": "269", + "parents": [ + "267", + "265", + "266" + ] + }, + { + "id": "270", + "parents": [ + "268" + ] + }, + { + "id": "271", + "parents": [ + "269", + "268" + ] + }, + { + "id": "272", + "parents": [ + "268", + "269" + ] + }, + { + "id": "273", + "parents": [ + "272" + ] + }, + { + "id": "274", + "parents": [ + "269", + "268" + ] + }, + { + "id": "275", + "parents": [ + "274", + "273", + "270", + "271" + ] + }, + { + "id": "276", + "parents": [ + "274", + "270", + "273", + "271" + ] + }, + { + "id": "277", + "parents": [ + "275", + "276" + ] + }, + { + "id": "278", + "parents": [ + "276" + ] + }, + { + "id": "279", + "parents": [ + "275", + "278" + ] + }, + { + "id": "280", + "parents": [ + "279" + ] + }, + { + "id": "281", + "parents": [ + "277", + "278" + ] + }, + { + "id": "282", + "parents": [ + "280", + "281" + ] + }, + { + "id": "283", + "parents": [ + "281", + "280" + ] + }, + { + "id": "284", + "parents": [ + "283" + ] + }, + { + "id": "285", + "parents": [ + "277", + "280" + ] + }, + { + "id": "286", + "parents": [ + "282", + "285", + "284" + ] + }, + { + "id": "287", + "parents": [ + "282", + "285", + "284" + ] + }, + { + "id": "288", + "parents": [ + "286" + ] + }, + { + "id": "289", + "parents": [ + "287", + "288" + ] + }, + { + "id": "290", + "parents": [ + "282", + "285", + "284" + ] + }, + { + "id": "291", + "parents": [ + "287", + "288" + ] + }, + { + "id": "292", + "parents": [ + "285", + "284", + "282" + ] + }, + { + "id": "293", + "parents": [ + "288", + "290" + ] + }, + { + "id": "294", + "parents": [ + "293", + "291", + "292" + ] + }, + { + "id": "295", + "parents": [ + "294", + "289" + ] + }, + { + "id": "296", + "parents": [ + "294", + "289" + ] + }, + { + "id": "297", + "parents": [ + "295", + "296" + ] + }, + { + "id": "298", + "parents": [ + "294", + "289" + ] + }, + { + "id": "299", + "parents": [ + "298", + "295", + "296" + ] + }, + { + "id": "300", + "parents": [ + "298", + "295", + "296" + ] + }, + { + "id": "301", + "parents": [ + "300", + "297", + "299" + ] + }, + { + "id": "302", + "parents": [ + "299" + ] + }, + { + "id": "303", + "parents": [ + "297", + "302", + "300" + ] + }, + { + "id": "304", + "parents": [ + "301", + "302" + ] + }, + { + "id": "305", + "parents": [ + "301", + "303" + ] + }, + { + "id": "306", + "parents": [ + "303", + "304" + ] + }, + { + "id": "307", + "parents": [ + "304", + "305" + ] + }, + { + "id": "308", + "parents": [ + "306", + "307" + ] + }, + { + "id": "309", + "parents": [ + "306", + "305" + ] + }, + { + "id": "310", + "parents": [ + "307", + "309" + ] + }, + { + "id": "311", + "parents": [ + "310" + ] + }, + { + "id": "312", + "parents": [ + "310" + ] + }, + { + "id": "313", + "parents": [ + "312", + "308" + ] + }, + { + "id": "314", + "parents": [ + "311", + "313" + ] + }, + { + "id": "315", + "parents": [ + "311", + "313" + ] + }, + { + "id": "316", + "parents": [ + "315", + "314" + ] + }, + { + "id": "317", + "parents": [ + "314", + "315" + ] + }, + { + "id": "318", + "parents": [ + "316" + ] + }, + { + "id": "319", + "parents": [ + "318", + "317" + ] + }, + { + "id": "320", + "parents": [ + "317", + "318" + ] + }, + { + "id": "321", + "parents": [ + "317", + "318" + ] + }, + { + "id": "322", + "parents": [ + "317", + "318" + ] + }, + { + "id": "323", + "parents": [ + "319" + ] + }, + { + "id": "324", + "parents": [ + "323", + "321", + "320" + ] + }, + { + "id": "325", + "parents": [ + "324", + "322" + ] + }, + { + "id": "326", + "parents": [ + "325" + ] + }, + { + "id": "327", + "parents": [ + "321", + "322", + "319", + "320" + ] + }, + { + "id": "328", + "parents": [ + "327" + ] + }, + { + "id": "329", + "parents": [ + "322", + "324" + ] + }, + { + "id": "330", + "parents": [ + "323", + "322", + "320", + "321" + ] + }, + { + "id": "331", + "parents": [ + "330", + "327", + "329" + ] + }, + { + "id": "332", + "parents": [ + "331", + "328", + "325" + ] + }, + { + "id": "333", + "parents": [ + "329", + "328", + "326", + "330" + ] + }, + { + "id": "334", + "parents": [ + "328" + ] + }, + { + "id": "335", + "parents": [ + "329", + "326", + "330" + ] + }, + { + "id": "336", + "parents": [ + "334", + "333", + "335", + "332" + ] + }, + { + "id": "337", + "parents": [ + "335", + "333", + "332", + "334" + ] + }, + { + "id": "338", + "parents": [ + "336", + "337" + ] + }, + { + "id": "339", + "parents": [ + "337", + "336" + ] + }, + { + "id": "340", + "parents": [ + "338", + "339" + ] + }, + { + "id": "341", + "parents": [ + "337", + "336" + ] + }, + { + "id": "342", + "parents": [ + "339" + ] + }, + { + "id": "343", + "parents": [ + "337", + "336" + ] + }, + { + "id": "344", + "parents": [ + "343", + "340", + "342", + "341" + ] + }, + { + "id": "345", + "parents": [ + "341", + "340", + "342" + ] + }, + { + "id": "346", + "parents": [ + "344", + "345" + ] + }, + { + "id": "347", + "parents": [ + "345", + "344" + ] + }, + { + "id": "348", + "parents": [ + "347" + ] + }, + { + "id": "349", + "parents": [ + "346", + "348" + ] + }, + { + "id": "350", + "parents": [ + "349" + ] + }, + { + "id": "351", + "parents": [ + "350" + ] + }, + { + "id": "352", + "parents": [ + "348", + "346" + ] + }, + { + "id": "353", + "parents": [ + "349" + ] + }, + { + "id": "354", + "parents": [ + "353", + "352", + "351" + ] + }, + { + "id": "355", + "parents": [ + "351", + "352", + "353" + ] + }, + { + "id": "356", + "parents": [ + "355" + ] + }, + { + "id": "357", + "parents": [ + "354" + ] + }, + { + "id": "358", + "parents": [ + "356" + ] + }, + { + "id": "359", + "parents": [ + "357", + "356" + ] + }, + { + "id": "360", + "parents": [ + "358", + "357" + ] + }, + { + "id": "361", + "parents": [ + "359", + "360" + ] + }, + { + "id": "362", + "parents": [ + "361" + ] + }, + { + "id": "363", + "parents": [ + "360" + ] + }, + { + "id": "364", + "parents": [ + "360", + "359" + ] + }, + { + "id": "365", + "parents": [ + "360", + "359" + ] + }, + { + "id": "366", + "parents": [ + "365" + ] + }, + { + "id": "367", + "parents": [ + "365" + ] + }, + { + "id": "368", + "parents": [ + "362", + "363", + "364", + "365" + ] + }, + { + "id": "369", + "parents": [ + "368", + "366", + "367" + ] + }, + { + "id": "370", + "parents": [ + "366", + "362", + "367", + "363" + ] + }, + { + "id": "371", + "parents": [ + "368", + "370" + ] + }, + { + "id": "372", + "parents": [ + "369", + "371" + ] + }, + { + "id": "373", + "parents": [ + "372" + ] + }, + { + "id": "374", + "parents": [ + "371", + "369" + ] + }, + { + "id": "375", + "parents": [ + "374", + "373" + ] + }, + { + "id": "376", + "parents": [ + "374", + "373" + ] + }, + { + "id": "377", + "parents": [ + "373" + ] + }, + { + "id": "378", + "parents": [ + "377", + "376" + ] + }, + { + "id": "379", + "parents": [ + "373", + "374" + ] + }, + { + "id": "380", + "parents": [ + "376" + ] + }, + { + "id": "381", + "parents": [ + "378", + "379", + "380", + "375" + ] + }, + { + "id": "382", + "parents": [ + "375", + "380", + "377" + ] + }, + { + "id": "383", + "parents": [ + "381", + "382" + ] + }, + { + "id": "384", + "parents": [ + "382", + "381" + ] + }, + { + "id": "385", + "parents": [ + "382", + "381" + ] + }, + { + "id": "386", + "parents": [ + "385", + "383", + "384" + ] + }, + { + "id": "387", + "parents": [ + "385", + "384" + ] + }, + { + "id": "388", + "parents": [ + "385", + "384" + ] + }, + { + "id": "389", + "parents": [ + "388" + ] + }, + { + "id": "390", + "parents": [ + "387", + "389", + "386" + ] + }, + { + "id": "391", + "parents": [ + "387", + "386", + "389" + ] + }, + { + "id": "392", + "parents": [ + "390", + "391" + ] + }, + { + "id": "393", + "parents": [ + "390" + ] + }, + { + "id": "394", + "parents": [ + "390" + ] + }, + { + "id": "395", + "parents": [ + "394" + ] + }, + { + "id": "396", + "parents": [ + "395", + "393", + "392" + ] + }, + { + "id": "397", + "parents": [ + "393" + ] + }, + { + "id": "398", + "parents": [ + "392", + "397", + "395" + ] + }, + { + "id": "399", + "parents": [ + "398", + "396" + ] + }, + { + "id": "400", + "parents": [ + "398", + "396" + ] + }, + { + "id": "401", + "parents": [ + "399", + "400" + ] + }, + { + "id": "402", + "parents": [ + "401" + ] + }, + { + "id": "403", + "parents": [ + "402" + ] + }, + { + "id": "404", + "parents": [ + "402" + ] + }, + { + "id": "405", + "parents": [ + "403" + ] + }, + { + "id": "406", + "parents": [ + "405" + ] + }, + { + "id": "407", + "parents": [ + "403", + "404" + ] + }, + { + "id": "408", + "parents": [ + "406" + ] + }, + { + "id": "409", + "parents": [ + "403", + "404" + ] + }, + { + "id": "410", + "parents": [ + "407", + "408" + ] + }, + { + "id": "411", + "parents": [ + "407", + "406" + ] + }, + { + "id": "412", + "parents": [ + "409", + "411", + "410" + ] + }, + { + "id": "413", + "parents": [ + "409", + "411", + "410" + ] + }, + { + "id": "414", + "parents": [ + "412" + ] + }, + { + "id": "415", + "parents": [ + "409", + "408", + "411" + ] + }, + { + "id": "416", + "parents": [ + "412", + "413", + "415" + ] + }, + { + "id": "417", + "parents": [ + "412", + "413", + "415" + ] + }, + { + "id": "418", + "parents": [ + "414", + "417", + "416" + ] + }, + { + "id": "419", + "parents": [ + "412", + "413", + "415" + ] + }, + { + "id": "420", + "parents": [ + "418", + "419" + ] + }, + { + "id": "421", + "parents": [ + "417", + "416", + "414", + "419" + ] + }, + { + "id": "422", + "parents": [ + "413", + "412", + "415" + ] + }, + { + "id": "423", + "parents": [ + "416", + "422", + "417", + "414", + "419" + ] + }, + { + "id": "424", + "parents": [ + "421" + ] + }, + { + "id": "425", + "parents": [ + "419", + "416", + "414", + "422", + "417" + ] + }, + { + "id": "426", + "parents": [ + "418", + "423" + ] + }, + { + "id": "427", + "parents": [ + "425", + "423", + "420", + "424" + ] + }, + { + "id": "428", + "parents": [ + "420", + "426", + "425", + "424" + ] + }, + { + "id": "429", + "parents": [ + "428" + ] + }, + { + "id": "430", + "parents": [ + "427", + "428" + ] + }, + { + "id": "431", + "parents": [ + "426", + "427" + ] + }, + { + "id": "432", + "parents": [ + "431", + "429", + "430" + ] + }, + { + "id": "433", + "parents": [ + "430", + "429" + ] + }, + { + "id": "434", + "parents": [ + "429", + "430" + ] + }, + { + "id": "435", + "parents": [ + "431", + "434" + ] + }, + { + "id": "436", + "parents": [ + "429", + "430" + ] + }, + { + "id": "437", + "parents": [ + "432", + "436", + "435", + "433" + ] + }, + { + "id": "438", + "parents": [ + "433", + "432", + "435", + "436" + ] + }, + { + "id": "439", + "parents": [ + "435", + "433", + "436", + "432" + ] + }, + { + "id": "440", + "parents": [ + "437", + "438", + "439" + ] + }, + { + "id": "441", + "parents": [ + "437", + "438" + ] + }, + { + "id": "442", + "parents": [ + "432", + "433", + "436", + "435" + ] + }, + { + "id": "443", + "parents": [ + "441", + "442", + "440" + ] + }, + { + "id": "444", + "parents": [ + "439", + "441", + "442" + ] + }, + { + "id": "445", + "parents": [ + "444", + "443" + ] + }, + { + "id": "446", + "parents": [ + "443", + "444" + ] + }, + { + "id": "447", + "parents": [ + "445" + ] + }, + { + "id": "448", + "parents": [ + "444", + "443" + ] + }, + { + "id": "449", + "parents": [ + "447", + "446" + ] + }, + { + "id": "450", + "parents": [ + "445" + ] + }, + { + "id": "451", + "parents": [ + "449" + ] + }, + { + "id": "452", + "parents": [ + "451", + "450", + "448" + ] + }, + { + "id": "453", + "parents": [ + "448", + "450", + "451" + ] + }, + { + "id": "454", + "parents": [ + "450", + "448", + "451" + ] + }, + { + "id": "455", + "parents": [ + "451", + "448", + "450" + ] + }, + { + "id": "456", + "parents": [ + "455", + "452", + "453", + "454" + ] + }, + { + "id": "457", + "parents": [ + "456" + ] + }, + { + "id": "458", + "parents": [ + "457" + ] + }, + { + "id": "459", + "parents": [ + "456" + ] + }, + { + "id": "460", + "parents": [ + "458", + "459" + ] + }, + { + "id": "461", + "parents": [ + "460" + ] + }, + { + "id": "462", + "parents": [ + "460" + ] + }, + { + "id": "463", + "parents": [ + "461", + "462" + ] + }, + { + "id": "464", + "parents": [ + "462", + "461" + ] + }, + { + "id": "465", + "parents": [ + "463", + "464" + ] + }, + { + "id": "466", + "parents": [ + "463" + ] + }, + { + "id": "467", + "parents": [ + "466", + "465" + ] + }, + { + "id": "468", + "parents": [ + "461" + ] + }, + { + "id": "469", + "parents": [ + "468" + ] + }, + { + "id": "470", + "parents": [ + "464", + "463", + "469" + ] + }, + { + "id": "471", + "parents": [ + "466", + "464" + ] + }, + { + "id": "472", + "parents": [ + "467", + "469", + "471" + ] + }, + { + "id": "473", + "parents": [ + "465", + "470", + "471" + ] + }, + { + "id": "474", + "parents": [ + "471", + "467", + "470" + ] + }, + { + "id": "475", + "parents": [ + "465", + "470", + "471" + ] + }, + { + "id": "476", + "parents": [ + "475", + "473", + "474", + "472" + ] + }, + { + "id": "477", + "parents": [ + "472", + "475", + "473", + "474" + ] + }, + { + "id": "478", + "parents": [ + "476" + ] + }, + { + "id": "479", + "parents": [ + "478" + ] + }, + { + "id": "480", + "parents": [ + "479", + "477" + ] + }, + { + "id": "481", + "parents": [ + "477", + "478" + ] + }, + { + "id": "482", + "parents": [ + "481" + ] + }, + { + "id": "483", + "parents": [ + "482", + "479" + ] + }, + { + "id": "484", + "parents": [ + "481", + "479" + ] + }, + { + "id": "485", + "parents": [ + "484", + "483", + "480" + ] + }, + { + "id": "486", + "parents": [ + "482", + "480" + ] + }, + { + "id": "487", + "parents": [ + "480", + "483" + ] + }, + { + "id": "488", + "parents": [ + "486" + ] + }, + { + "id": "489", + "parents": [ + "487", + "484" + ] + }, + { + "id": "490", + "parents": [ + "483", + "480" + ] + }, + { + "id": "491", + "parents": [ + "488", + "487" + ] + }, + { + "id": "492", + "parents": [ + "488", + "485", + "490", + "489" + ] + }, + { + "id": "493", + "parents": [ + "491", + "490", + "485", + "489" + ] + }, + { + "id": "494", + "parents": [ + "492", + "493" + ] + }, + { + "id": "495", + "parents": [ + "493", + "492" + ] + }, + { + "id": "496", + "parents": [ + "495", + "494" + ] + }, + { + "id": "497", + "parents": [ + "496" + ] + }, + { + "id": "498", + "parents": [ + "496" + ] + }, + { + "id": "499", + "parents": [ + "496" + ] + }, + { + "id": "500", + "parents": [ + "496" + ] + }, + { + "id": "501", + "parents": [ + "496" + ] + }, + { + "id": "502", + "parents": [ + "499", + "501", + "500", + "497", + "498" + ] + }, + { + "id": "503", + "parents": [ + "497", + "499", + "500", + "498", + "501" + ] + }, + { + "id": "504", + "parents": [ + "503", + "502" + ] + }, + { + "id": "505", + "parents": [ + "503" + ] + }, + { + "id": "506", + "parents": [ + "503", + "502" + ] + }, + { + "id": "507", + "parents": [ + "506", + "505" + ] + }, + { + "id": "508", + "parents": [ + "505", + "502" + ] + }, + { + "id": "509", + "parents": [ + "506" + ] + }, + { + "id": "510", + "parents": [ + "504", + "507", + "509" + ] + }, + { + "id": "511", + "parents": [ + "510", + "508" + ] + }, + { + "id": "512", + "parents": [ + "504", + "508", + "507" + ] + }, + { + "id": "513", + "parents": [ + "512", + "511" + ] + }, + { + "id": "514", + "parents": [ + "508", + "510" + ] + }, + { + "id": "515", + "parents": [ + "513", + "514" + ] + }, + { + "id": "516", + "parents": [ + "513" + ] + }, + { + "id": "517", + "parents": [ + "515" + ] + }, + { + "id": "518", + "parents": [ + "516", + "514" + ] + }, + { + "id": "519", + "parents": [ + "518", + "517" + ] + }, + { + "id": "520", + "parents": [ + "519" + ] + }, + { + "id": "521", + "parents": [ + "520" + ] + }, + { + "id": "522", + "parents": [ + "521" + ] + }, + { + "id": "523", + "parents": [ + "519" + ] + }, + { + "id": "524", + "parents": [ + "523" + ] + }, + { + "id": "525", + "parents": [ + "524" + ] + }, + { + "id": "526", + "parents": [ + "525", + "522" + ] + }, + { + "id": "527", + "parents": [ + "526" + ] + }, + { + "id": "528", + "parents": [ + "527" + ] + }, + { + "id": "529", + "parents": [ + "527" + ] + }, + { + "id": "530", + "parents": [ + "528" + ] + }, + { + "id": "531", + "parents": [ + "526" + ] + }, + { + "id": "532", + "parents": [ + "527", + "531" + ] + }, + { + "id": "533", + "parents": [ + "530", + "532", + "529" + ] + }, + { + "id": "534", + "parents": [ + "529", + "528", + "531" + ] + }, + { + "id": "535", + "parents": [ + "534", + "533" + ] + }, + { + "id": "536", + "parents": [ + "534", + "533" + ] + }, + { + "id": "537", + "parents": [ + "534", + "533" + ] + }, + { + "id": "538", + "parents": [ + "537", + "535", + "536" + ] + }, + { + "id": "539", + "parents": [ + "536", + "537", + "535" + ] + }, + { + "id": "540", + "parents": [ + "539", + "538" + ] + }, + { + "id": "541", + "parents": [ + "539", + "538" + ] + }, + { + "id": "542", + "parents": [ + "541" + ] + }, + { + "id": "543", + "parents": [ + "542", + "540" + ] + }, + { + "id": "544", + "parents": [ + "540" + ] + }, + { + "id": "545", + "parents": [ + "542", + "540" + ] + }, + { + "id": "546", + "parents": [ + "542" + ] + }, + { + "id": "547", + "parents": [ + "546", + "544", + "543" + ] + }, + { + "id": "548", + "parents": [ + "546", + "543", + "544", + "545" + ] + }, + { + "id": "549", + "parents": [ + "548" + ] + }, + { + "id": "550", + "parents": [ + "545", + "544", + "546", + "543" + ] + }, + { + "id": "551", + "parents": [ + "547", + "550", + "549" + ] + }, + { + "id": "552", + "parents": [ + "550", + "547", + "549" + ] + }, + { + "id": "553", + "parents": [ + "549", + "547", + "550" + ] + }, + { + "id": "554", + "parents": [ + "549", + "550", + "547" + ] + }, + { + "id": "555", + "parents": [ + "552", + "551", + "554", + "553" + ] + }, + { + "id": "556", + "parents": [ + "555" + ] + }, + { + "id": "557", + "parents": [ + "556" + ] + }, + { + "id": "558", + "parents": [ + "555" + ] + }, + { + "id": "559", + "parents": [ + "556", + "558" + ] + }, + { + "id": "560", + "parents": [ + "559" + ] + }, + { + "id": "561", + "parents": [ + "560", + "557" + ] + }, + { + "id": "562", + "parents": [ + "561" + ] + }, + { + "id": "563", + "parents": [ + "561" + ] + }, + { + "id": "564", + "parents": [ + "561" + ] + }, + { + "id": "565", + "parents": [ + "561" + ] + }, + { + "id": "566", + "parents": [ + "563", + "562" + ] + }, + { + "id": "567", + "parents": [ + "565", + "566", + "564" + ] + }, + { + "id": "568", + "parents": [ + "565", + "563", + "562", + "564" + ] + }, + { + "id": "569", + "parents": [ + "565" + ] + }, + { + "id": "570", + "parents": [ + "568", + "566" + ] + }, + { + "id": "571", + "parents": [ + "564", + "565", + "566" + ] + }, + { + "id": "572", + "parents": [ + "570", + "569", + "571", + "567" + ] + }, + { + "id": "573", + "parents": [ + "567", + "569", + "568" + ] + }, + { + "id": "574", + "parents": [ + "568", + "569", + "566" + ] + }, + { + "id": "575", + "parents": [ + "574", + "573", + "572" + ] + }, + { + "id": "576", + "parents": [ + "572", + "574", + "573" + ] + }, + { + "id": "577", + "parents": [ + "576" + ] + }, + { + "id": "578", + "parents": [ + "575", + "577" + ] + }, + { + "id": "579", + "parents": [ + "578" + ] + }, + { + "id": "580", + "parents": [ + "578" + ] + }, + { + "id": "581", + "parents": [ + "580", + "579" + ] + }, + { + "id": "582", + "parents": [ + "580" + ] + }, + { + "id": "583", + "parents": [ + "579", + "582" + ] + }, + { + "id": "584", + "parents": [ + "581", + "582" + ] + }, + { + "id": "585", + "parents": [ + "582", + "581" + ] + }, + { + "id": "586", + "parents": [ + "579", + "582" + ] + }, + { + "id": "587", + "parents": [ + "586", + "585" + ] + }, + { + "id": "588", + "parents": [ + "585", + "586" + ] + }, + { + "id": "589", + "parents": [ + "583", + "584", + "588" + ] + }, + { + "id": "590", + "parents": [ + "589", + "587" + ] + }, + { + "id": "591", + "parents": [ + "589", + "587" + ] + }, + { + "id": "592", + "parents": [ + "590", + "591" + ] + }, + { + "id": "593", + "parents": [ + "592" + ] + }, + { + "id": "594", + "parents": [ + "592" + ] + }, + { + "id": "595", + "parents": [ + "594", + "593" + ] + }, + { + "id": "596", + "parents": [ + "595" + ] + }, + { + "id": "597", + "parents": [ + "595" + ] + }, + { + "id": "598", + "parents": [ + "595" + ] + }, + { + "id": "599", + "parents": [ + "597", + "598" + ] + }, + { + "id": "600", + "parents": [ + "599", + "596" + ] + }, + { + "id": "601", + "parents": [ + "596", + "599" + ] + }, + { + "id": "602", + "parents": [ + "600", + "601" + ] + }, + { + "id": "603", + "parents": [ + "602" + ] + }, + { + "id": "604", + "parents": [ + "602" + ] + }, + { + "id": "605", + "parents": [ + "604" + ] + }, + { + "id": "606", + "parents": [ + "603", + "605" + ] + }, + { + "id": "607", + "parents": [ + "603", + "604" + ] + }, + { + "id": "608", + "parents": [ + "607" + ] + }, + { + "id": "609", + "parents": [ + "604", + "603" + ] + }, + { + "id": "610", + "parents": [ + "607", + "605" + ] + }, + { + "id": "611", + "parents": [ + "606", + "608", + "609", + "610" + ] + }, + { + "id": "612", + "parents": [ + "610", + "609", + "606", + "608" + ] + }, + { + "id": "613", + "parents": [ + "611" + ] + }, + { + "id": "614", + "parents": [ + "612", + "613" + ] + }, + { + "id": "615", + "parents": [ + "614" + ] + }, + { + "id": "616", + "parents": [ + "612", + "613" + ] + }, + { + "id": "617", + "parents": [ + "614" + ] + }, + { + "id": "618", + "parents": [ + "614", + "616" + ] + }, + { + "id": "619", + "parents": [ + "614" + ] + }, + { + "id": "620", + "parents": [ + "612", + "613" + ] + }, + { + "id": "621", + "parents": [ + "616", + "619", + "620", + "617" + ] + }, + { + "id": "622", + "parents": [ + "615", + "618", + "621" + ] + }, + { + "id": "623", + "parents": [ + "621", + "615", + "618" + ] + }, + { + "id": "624", + "parents": [ + "615", + "621", + "618" + ] + }, + { + "id": "625", + "parents": [ + "623", + "624" + ] + }, + { + "id": "626", + "parents": [ + "622", + "625" + ] + }, + { + "id": "627", + "parents": [ + "626" + ] + }, + { + "id": "628", + "parents": [ + "626" + ] + }, + { + "id": "629", + "parents": [ + "628", + "627" + ] + }, + { + "id": "630", + "parents": [ + "623", + "622", + "624" + ] + }, + { + "id": "631", + "parents": [ + "630" + ] + }, + { + "id": "632", + "parents": [ + "625", + "622" + ] + }, + { + "id": "633", + "parents": [ + "629", + "631", + "632" + ] + }, + { + "id": "634", + "parents": [ + "631", + "625" + ] + }, + { + "id": "635", + "parents": [ + "627", + "634", + "632" + ] + }, + { + "id": "636", + "parents": [ + "632", + "634", + "628", + "627" + ] + }, + { + "id": "637", + "parents": [ + "636", + "633", + "635" + ] + }, + { + "id": "638", + "parents": [ + "637" + ] + }, + { + "id": "639", + "parents": [ + "638" + ] + }, + { + "id": "640", + "parents": [ + "637" + ] + }, + { + "id": "641", + "parents": [ + "637" + ] + }, + { + "id": "642", + "parents": [ + "639", + "641", + "640" + ] + }, + { + "id": "643", + "parents": [ + "640", + "641", + "639" + ] + }, + { + "id": "644", + "parents": [ + "642", + "643" + ] + }, + { + "id": "645", + "parents": [ + "642", + "643" + ] + }, + { + "id": "646", + "parents": [ + "643", + "642" + ] + }, + { + "id": "647", + "parents": [ + "644" + ] + }, + { + "id": "648", + "parents": [ + "647", + "645", + "646" + ] + }, + { + "id": "649", + "parents": [ + "648" + ] + }, + { + "id": "650", + "parents": [ + "649" + ] + }, + { + "id": "651", + "parents": [ + "648" + ] + }, + { + "id": "652", + "parents": [ + "646", + "647", + "645" + ] + }, + { + "id": "653", + "parents": [ + "651", + "649", + "652" + ] + }, + { + "id": "654", + "parents": [ + "650", + "653" + ] + }, + { + "id": "655", + "parents": [ + "650", + "653" + ] + }, + { + "id": "656", + "parents": [ + "653", + "650" + ] + }, + { + "id": "657", + "parents": [ + "650", + "653" + ] + }, + { + "id": "658", + "parents": [ + "653", + "650" + ] + }, + { + "id": "659", + "parents": [ + "655", + "658" + ] + }, + { + "id": "660", + "parents": [ + "657", + "656", + "654", + "658", + "655" + ] + }, + { + "id": "661", + "parents": [ + "660" + ] + }, + { + "id": "662", + "parents": [ + "656", + "654", + "657", + "659" + ] + }, + { + "id": "663", + "parents": [ + "662" + ] + }, + { + "id": "664", + "parents": [ + "663", + "661" + ] + }, + { + "id": "665", + "parents": [ + "661", + "662" + ] + }, + { + "id": "666", + "parents": [ + "661", + "663" + ] + }, + { + "id": "667", + "parents": [ + "661", + "659" + ] + }, + { + "id": "668", + "parents": [ + "667", + "663" + ] + }, + { + "id": "669", + "parents": [ + "662", + "667" + ] + }, + { + "id": "670", + "parents": [ + "668", + "666", + "664", + "665" + ] + }, + { + "id": "671", + "parents": [ + "666", + "669", + "664", + "665", + "668" + ] + }, + { + "id": "672", + "parents": [ + "670", + "669" + ] + }, + { + "id": "673", + "parents": [ + "672", + "671" + ] + }, + { + "id": "674", + "parents": [ + "669", + "670" + ] + }, + { + "id": "675", + "parents": [ + "672", + "671" + ] + }, + { + "id": "676", + "parents": [ + "672" + ] + }, + { + "id": "677", + "parents": [ + "676", + "675", + "674", + "673" + ] + }, + { + "id": "678", + "parents": [ + "675", + "676", + "674" + ] + }, + { + "id": "679", + "parents": [ + "673", + "678" + ] + }, + { + "id": "680", + "parents": [ + "679" + ] + }, + { + "id": "681", + "parents": [ + "680", + "677" + ] + }, + { + "id": "682", + "parents": [ + "681" + ] + }, + { + "id": "683", + "parents": [ + "682" + ] + }, + { + "id": "684", + "parents": [ + "681" + ] + }, + { + "id": "685", + "parents": [ + "682" + ] + }, + { + "id": "686", + "parents": [ + "685" + ] + }, + { + "id": "687", + "parents": [ + "685", + "684", + "683" + ] + }, + { + "id": "688", + "parents": [ + "683", + "686" + ] + }, + { + "id": "689", + "parents": [ + "688", + "684" + ] + }, + { + "id": "690", + "parents": [ + "687", + "689" + ] + }, + { + "id": "691", + "parents": [ + "689" + ] + }, + { + "id": "692", + "parents": [ + "691", + "690" + ] + }, + { + "id": "693", + "parents": [ + "687", + "689" + ] + }, + { + "id": "694", + "parents": [ + "690", + "693", + "691" + ] + }, + { + "id": "695", + "parents": [ + "694" + ] + }, + { + "id": "696", + "parents": [ + "692", + "694" + ] + }, + { + "id": "697", + "parents": [ + "693", + "691", + "690" + ] + }, + { + "id": "698", + "parents": [ + "696", + "697", + "695" + ] + }, + { + "id": "699", + "parents": [ + "698" + ] + }, + { + "id": "700", + "parents": [ + "696", + "695", + "697" + ] + }, + { + "id": "701", + "parents": [ + "697", + "696", + "695" + ] + }, + { + "id": "702", + "parents": [ + "701", + "700", + "699" + ] + }, + { + "id": "703", + "parents": [ + "698", + "701" + ] + }, + { + "id": "704", + "parents": [ + "703", + "699", + "700" + ] + }, + { + "id": "705", + "parents": [ + "703", + "702" + ] + }, + { + "id": "706", + "parents": [ + "702", + "703" + ] + }, + { + "id": "707", + "parents": [ + "704", + "705", + "706" + ] + }, + { + "id": "708", + "parents": [ + "704" + ] + }, + { + "id": "709", + "parents": [ + "707", + "708" + ] + }, + { + "id": "710", + "parents": [ + "707", + "708" + ] + }, + { + "id": "711", + "parents": [ + "709" + ] + }, + { + "id": "712", + "parents": [ + "711", + "710" + ] + }, + { + "id": "713", + "parents": [ + "709" + ] + }, + { + "id": "714", + "parents": [ + "711", + "713", + "710" + ] + }, + { + "id": "715", + "parents": [ + "714", + "712" + ] + }, + { + "id": "716", + "parents": [ + "715" + ] + }, + { + "id": "717", + "parents": [ + "716" + ] + }, + { + "id": "718", + "parents": [ + "714", + "712" + ] + }, + { + "id": "719", + "parents": [ + "716" + ] + }, + { + "id": "720", + "parents": [ + "719" + ] + }, + { + "id": "721", + "parents": [ + "717", + "718", + "720" + ] + }, + { + "id": "722", + "parents": [ + "721" + ] + }, + { + "id": "723", + "parents": [ + "720", + "718", + "717" + ] + }, + { + "id": "724", + "parents": [ + "716", + "718" + ] + }, + { + "id": "725", + "parents": [ + "720", + "718" + ] + }, + { + "id": "726", + "parents": [ + "725", + "717", + "724" + ] + }, + { + "id": "727", + "parents": [ + "726" + ] + }, + { + "id": "728", + "parents": [ + "725", + "724", + "721", + "723" + ] + }, + { + "id": "729", + "parents": [ + "722", + "727", + "723" + ] + }, + { + "id": "730", + "parents": [ + "727", + "723", + "722" + ] + }, + { + "id": "731", + "parents": [ + "722", + "723", + "727" + ] + }, + { + "id": "732", + "parents": [ + "730" + ] + }, + { + "id": "733", + "parents": [ + "728", + "731", + "729", + "732" + ] + }, + { + "id": "734", + "parents": [ + "728", + "729", + "732", + "731" + ] + }, + { + "id": "735", + "parents": [ + "729", + "732", + "731", + "728" + ] + }, + { + "id": "736", + "parents": [ + "733", + "734", + "735" + ] + }, + { + "id": "737", + "parents": [ + "731", + "728", + "732", + "729" + ] + }, + { + "id": "738", + "parents": [ + "737", + "736" + ] + }, + { + "id": "739", + "parents": [ + "738" + ] + }, + { + "id": "740", + "parents": [ + "739" + ] + }, + { + "id": "741", + "parents": [ + "739" + ] + }, + { + "id": "742", + "parents": [ + "739" + ] + }, + { + "id": "743", + "parents": [ + "739" + ] + }, + { + "id": "744", + "parents": [ + "740", + "743", + "741" + ] + }, + { + "id": "745", + "parents": [ + "743", + "741", + "742", + "740" + ] + }, + { + "id": "746", + "parents": [ + "744", + "745" + ] + }, + { + "id": "747", + "parents": [ + "746" + ] + }, + { + "id": "748", + "parents": [ + "747" + ] + }, + { + "id": "749", + "parents": [ + "748" + ] + }, + { + "id": "750", + "parents": [ + "746" + ] + }, + { + "id": "751", + "parents": [ + "746" + ] + }, + { + "id": "752", + "parents": [ + "751", + "750", + "749" + ] + }, + { + "id": "753", + "parents": [ + "749", + "751", + "750" + ] + }, + { + "id": "754", + "parents": [ + "753" + ] + }, + { + "id": "755", + "parents": [ + "754", + "752" + ] + }, + { + "id": "756", + "parents": [ + "752", + "753" + ] + }, + { + "id": "757", + "parents": [ + "752" + ] + }, + { + "id": "758", + "parents": [ + "753", + "757" + ] + }, + { + "id": "759", + "parents": [ + "755", + "756" + ] + }, + { + "id": "760", + "parents": [ + "755", + "757", + "756" + ] + }, + { + "id": "761", + "parents": [ + "760", + "759" + ] + }, + { + "id": "762", + "parents": [ + "761", + "758" + ] + }, + { + "id": "763", + "parents": [ + "762" + ] + }, + { + "id": "764", + "parents": [ + "762" + ] + }, + { + "id": "765", + "parents": [ + "762" + ] + }, + { + "id": "766", + "parents": [ + "764", + "765", + "763" + ] + }, + { + "id": "767", + "parents": [ + "766" + ] + }, + { + "id": "768", + "parents": [ + "763", + "765", + "764" + ] + }, + { + "id": "769", + "parents": [ + "763", + "765", + "764" + ] + }, + { + "id": "770", + "parents": [ + "766", + "769" + ] + }, + { + "id": "771", + "parents": [ + "769" + ] + }, + { + "id": "772", + "parents": [ + "768", + "771", + "770" + ] + }, + { + "id": "773", + "parents": [ + "772", + "767" + ] + }, + { + "id": "774", + "parents": [ + "772", + "767" + ] + }, + { + "id": "775", + "parents": [ + "772", + "767" + ] + }, + { + "id": "776", + "parents": [ + "773" + ] + }, + { + "id": "777", + "parents": [ + "773", + "774" + ] + }, + { + "id": "778", + "parents": [ + "775", + "777", + "776" + ] + }, + { + "id": "779", + "parents": [ + "774", + "776" + ] + }, + { + "id": "780", + "parents": [ + "779", + "778" + ] + }, + { + "id": "781", + "parents": [ + "780" + ] + }, + { + "id": "782", + "parents": [ + "775", + "777", + "779" + ] + }, + { + "id": "783", + "parents": [ + "781", + "782" + ] + }, + { + "id": "784", + "parents": [ + "782", + "780" + ] + }, + { + "id": "785", + "parents": [ + "783", + "784" + ] + }, + { + "id": "786", + "parents": [ + "783", + "784" + ] + }, + { + "id": "787", + "parents": [ + "786" + ] + }, + { + "id": "788", + "parents": [ + "786" + ] + }, + { + "id": "789", + "parents": [ + "785", + "786" + ] + }, + { + "id": "790", + "parents": [ + "787", + "788", + "789" + ] + }, + { + "id": "791", + "parents": [ + "788", + "785", + "787" + ] + }, + { + "id": "792", + "parents": [ + "790" + ] + }, + { + "id": "793", + "parents": [ + "792", + "791" + ] + }, + { + "id": "794", + "parents": [ + "791", + "792" + ] + }, + { + "id": "795", + "parents": [ + "793" + ] + }, + { + "id": "796", + "parents": [ + "794", + "795" + ] + }, + { + "id": "797", + "parents": [ + "795", + "794" + ] + }, + { + "id": "798", + "parents": [ + "794", + "795" + ] + }, + { + "id": "799", + "parents": [ + "798" + ] + }, + { + "id": "800", + "parents": [ + "797", + "799", + "796" + ] + }, + { + "id": "801", + "parents": [ + "796", + "799", + "797" + ] + }, + { + "id": "802", + "parents": [ + "801", + "800" + ] + }, + { + "id": "803", + "parents": [ + "801", + "800" + ] + }, + { + "id": "804", + "parents": [ + "803" + ] + }, + { + "id": "805", + "parents": [ + "802", + "804" + ] + }, + { + "id": "806", + "parents": [ + "802", + "804" + ] + }, + { + "id": "807", + "parents": [ + "805" + ] + }, + { + "id": "808", + "parents": [ + "807", + "806" + ] + }, + { + "id": "809", + "parents": [ + "806", + "807" + ] + }, + { + "id": "810", + "parents": [ + "808", + "809" + ] + }, + { + "id": "811", + "parents": [ + "808", + "809" + ] + }, + { + "id": "812", + "parents": [ + "810", + "811" + ] + }, + { + "id": "813", + "parents": [ + "811" + ] + }, + { + "id": "814", + "parents": [ + "812", + "813" + ] + }, + { + "id": "815", + "parents": [ + "810", + "813" + ] + }, + { + "id": "816", + "parents": [ + "815", + "814" + ] + }, + { + "id": "817", + "parents": [ + "812", + "813" + ] + }, + { + "id": "818", + "parents": [ + "817", + "814", + "815" + ] + }, + { + "id": "819", + "parents": [ + "816", + "818" + ] + }, + { + "id": "820", + "parents": [ + "819" + ] + }, + { + "id": "821", + "parents": [ + "820" + ] + }, + { + "id": "822", + "parents": [ + "816", + "818" + ] + }, + { + "id": "823", + "parents": [ + "822", + "820" + ] + }, + { + "id": "824", + "parents": [ + "823", + "821" + ] + }, + { + "id": "825", + "parents": [ + "824" + ] + }, + { + "id": "826", + "parents": [ + "821", + "823" + ] + }, + { + "id": "827", + "parents": [ + "826", + "824" + ] + }, + { + "id": "828", + "parents": [ + "824", + "826" + ] + }, + { + "id": "829", + "parents": [ + "826", + "825" + ] + }, + { + "id": "830", + "parents": [ + "824" + ] + }, + { + "id": "831", + "parents": [ + "829", + "828", + "830", + "827" + ] + }, + { + "id": "832", + "parents": [ + "831" + ] + }, + { + "id": "833", + "parents": [ + "831" + ] + }, + { + "id": "834", + "parents": [ + "831" + ] + }, + { + "id": "835", + "parents": [ + "832", + "834", + "833" + ] + }, + { + "id": "836", + "parents": [ + "834", + "832", + "833" + ] + }, + { + "id": "837", + "parents": [ + "832", + "833", + "834" + ] + }, + { + "id": "838", + "parents": [ + "832", + "833", + "834" + ] + }, + { + "id": "839", + "parents": [ + "837", + "835", + "838" + ] + }, + { + "id": "840", + "parents": [ + "837" + ] + }, + { + "id": "841", + "parents": [ + "836", + "835", + "840", + "838" + ] + }, + { + "id": "842", + "parents": [ + "838", + "837", + "835" + ] + }, + { + "id": "843", + "parents": [ + "841", + "839", + "842" + ] + }, + { + "id": "844", + "parents": [ + "842", + "839", + "841" + ] + }, + { + "id": "845", + "parents": [ + "844" + ] + }, + { + "id": "846", + "parents": [ + "844" + ] + }, + { + "id": "847", + "parents": [ + "845", + "846" + ] + }, + { + "id": "848", + "parents": [ + "847", + "843" + ] + }, + { + "id": "849", + "parents": [ + "848" + ] + }, + { + "id": "850", + "parents": [ + "849" + ] + }, + { + "id": "851", + "parents": [ + "848" + ] + }, + { + "id": "852", + "parents": [ + "851", + "850" + ] + }, + { + "id": "853", + "parents": [ + "852" + ] + }, + { + "id": "854", + "parents": [ + "850", + "851" + ] + }, + { + "id": "855", + "parents": [ + "853", + "854" + ] + }, + { + "id": "856", + "parents": [ + "855" + ] + }, + { + "id": "857", + "parents": [ + "850", + "851" + ] + }, + { + "id": "858", + "parents": [ + "857" + ] + }, + { + "id": "859", + "parents": [ + "858" + ] + }, + { + "id": "860", + "parents": [ + "858" + ] + }, + { + "id": "861", + "parents": [ + "860", + "859", + "856" + ] + }, + { + "id": "862", + "parents": [ + "861" + ] + }, + { + "id": "863", + "parents": [ + "861" + ] + }, + { + "id": "864", + "parents": [ + "861" + ] + }, + { + "id": "865", + "parents": [ + "864", + "863", + "862" + ] + }, + { + "id": "866", + "parents": [ + "863", + "862" + ] + }, + { + "id": "867", + "parents": [ + "863", + "864", + "862" + ] + }, + { + "id": "868", + "parents": [ + "865", + "866", + "867" + ] + }, + { + "id": "869", + "parents": [ + "867", + "866" + ] + }, + { + "id": "870", + "parents": [ + "867", + "865", + "866" + ] + }, + { + "id": "871", + "parents": [ + "868", + "869", + "870" + ] + }, + { + "id": "872", + "parents": [ + "868", + "870", + "869" + ] + }, + { + "id": "873", + "parents": [ + "871", + "872" + ] + }, + { + "id": "874", + "parents": [ + "873" + ] + }, + { + "id": "875", + "parents": [ + "874" + ] + }, + { + "id": "876", + "parents": [ + "874" + ] + }, + { + "id": "877", + "parents": [ + "874" + ] + }, + { + "id": "878", + "parents": [ + "874" + ] + }, + { + "id": "879", + "parents": [ + "875", + "877" + ] + }, + { + "id": "880", + "parents": [ + "878", + "879", + "876" + ] + }, + { + "id": "881", + "parents": [ + "879", + "876", + "878" + ] + }, + { + "id": "882", + "parents": [ + "880" + ] + }, + { + "id": "883", + "parents": [ + "880", + "881" + ] + }, + { + "id": "884", + "parents": [ + "882" + ] + }, + { + "id": "885", + "parents": [ + "883", + "884" + ] + }, + { + "id": "886", + "parents": [ + "882", + "883" + ] + }, + { + "id": "887", + "parents": [ + "886" + ] + }, + { + "id": "888", + "parents": [ + "887", + "885" + ] + }, + { + "id": "889", + "parents": [ + "888" + ] + }, + { + "id": "890", + "parents": [ + "888" + ] + }, + { + "id": "891", + "parents": [ + "888" + ] + }, + { + "id": "892", + "parents": [ + "889", + "891", + "890" + ] + }, + { + "id": "893", + "parents": [ + "891", + "889", + "890" + ] + }, + { + "id": "894", + "parents": [ + "893", + "892" + ] + }, + { + "id": "895", + "parents": [ + "892", + "893" + ] + }, + { + "id": "896", + "parents": [ + "894", + "895" + ] + }, + { + "id": "897", + "parents": [ + "895", + "894" + ] + }, + { + "id": "898", + "parents": [ + "896", + "897" + ] + }, + { + "id": "899", + "parents": [ + "896", + "897" + ] + }, + { + "id": "900", + "parents": [ + "899" + ] + }, + { + "id": "901", + "parents": [ + "898", + "900" + ] + }, + { + "id": "902", + "parents": [ + "898", + "900" + ] + }, + { + "id": "903", + "parents": [ + "901", + "902" + ] + }, + { + "id": "904", + "parents": [ + "902", + "901" + ] + }, + { + "id": "905", + "parents": [ + "902", + "901" + ] + }, + { + "id": "906", + "parents": [ + "903", + "905" + ] + }, + { + "id": "907", + "parents": [ + "904", + "906" + ] + }, + { + "id": "908", + "parents": [ + "904", + "906" + ] + }, + { + "id": "909", + "parents": [ + "906", + "904" + ] + }, + { + "id": "910", + "parents": [ + "907", + "908" + ] + }, + { + "id": "911", + "parents": [ + "909", + "910" + ] + }, + { + "id": "912", + "parents": [ + "911" + ] + }, + { + "id": "913", + "parents": [ + "909", + "910" + ] + }, + { + "id": "914", + "parents": [ + "913", + "912" + ] + }, + { + "id": "915", + "parents": [ + "914" + ] + }, + { + "id": "916", + "parents": [ + "914" + ] + }, + { + "id": "917", + "parents": [ + "916", + "915" + ] + }, + { + "id": "918", + "parents": [ + "916" + ] + }, + { + "id": "919", + "parents": [ + "918", + "917" + ] + }, + { + "id": "920", + "parents": [ + "916", + "915" + ] + }, + { + "id": "921", + "parents": [ + "919", + "920" + ] + }, + { + "id": "922", + "parents": [ + "921" + ] + }, + { + "id": "923", + "parents": [ + "922" + ] + }, + { + "id": "924", + "parents": [ + "922" + ] + }, + { + "id": "925", + "parents": [ + "924", + "923" + ] + }, + { + "id": "926", + "parents": [ + "925" + ] + }, + { + "id": "927", + "parents": [ + "926" + ] + }, + { + "id": "928", + "parents": [ + "927" + ] + }, + { + "id": "929", + "parents": [ + "928" + ] + }, + { + "id": "930", + "parents": [ + "927" + ] + }, + { + "id": "931", + "parents": [ + "930", + "928" + ] + }, + { + "id": "932", + "parents": [ + "929", + "931" + ] + }, + { + "id": "933", + "parents": [ + "930", + "928" + ] + }, + { + "id": "934", + "parents": [ + "933", + "932" + ] + }, + { + "id": "935", + "parents": [ + "930", + "928" + ] + }, + { + "id": "936", + "parents": [ + "929", + "931", + "933", + "935" + ] + }, + { + "id": "937", + "parents": [ + "936" + ] + }, + { + "id": "938", + "parents": [ + "934", + "936" + ] + }, + { + "id": "939", + "parents": [ + "931", + "929", + "933" + ] + }, + { + "id": "940", + "parents": [ + "939", + "937", + "932" + ] + }, + { + "id": "941", + "parents": [ + "937", + "939", + "938" + ] + }, + { + "id": "942", + "parents": [ + "938", + "940" + ] + }, + { + "id": "943", + "parents": [ + "941", + "942" + ] + }, + { + "id": "944", + "parents": [ + "940", + "938" + ] + }, + { + "id": "945", + "parents": [ + "944", + "943" + ] + }, + { + "id": "946", + "parents": [ + "941", + "942", + "944" + ] + }, + { + "id": "947", + "parents": [ + "945", + "946" + ] + }, + { + "id": "948", + "parents": [ + "946", + "943" + ] + }, + { + "id": "949", + "parents": [ + "943", + "944" + ] + }, + { + "id": "950", + "parents": [ + "948" + ] + }, + { + "id": "951", + "parents": [ + "948", + "945" + ] + }, + { + "id": "952", + "parents": [ + "943", + "944" + ] + }, + { + "id": "953", + "parents": [ + "948", + "952" + ] + }, + { + "id": "954", + "parents": [ + "948", + "952" + ] + }, + { + "id": "955", + "parents": [ + "954", + "953", + "949", + "950", + "951", + "947" + ] + }, + { + "id": "956", + "parents": [ + "955" + ] + }, + { + "id": "957", + "parents": [ + "956" + ] + }, + { + "id": "958", + "parents": [ + "957" + ] + }, + { + "id": "959", + "parents": [ + "957" + ] + }, + { + "id": "960", + "parents": [ + "956" + ] + }, + { + "id": "961", + "parents": [ + "960", + "959", + "958" + ] + }, + { + "id": "962", + "parents": [ + "958", + "960", + "959" + ] + }, + { + "id": "963", + "parents": [ + "959", + "958", + "960" + ] + }, + { + "id": "964", + "parents": [ + "961" + ] + }, + { + "id": "965", + "parents": [ + "963", + "962", + "961" + ] + }, + { + "id": "966", + "parents": [ + "961", + "962" + ] + }, + { + "id": "967", + "parents": [ + "966", + "965", + "964" + ] + }, + { + "id": "968", + "parents": [ + "963", + "962", + "964" + ] + }, + { + "id": "969", + "parents": [ + "965", + "966" + ] + }, + { + "id": "970", + "parents": [ + "968", + "965", + "966" + ] + }, + { + "id": "971", + "parents": [ + "970", + "969" + ] + }, + { + "id": "972", + "parents": [ + "971", + "967" + ] + }, + { + "id": "973", + "parents": [ + "972" + ] + }, + { + "id": "974", + "parents": [ + "971" + ] + }, + { + "id": "975", + "parents": [ + "971", + "967" + ] + }, + { + "id": "976", + "parents": [ + "967", + "974" + ] + }, + { + "id": "977", + "parents": [ + "972", + "975", + "974" + ] + }, + { + "id": "978", + "parents": [ + "976", + "977", + "973" + ] + }, + { + "id": "979", + "parents": [ + "976", + "973", + "977" + ] + }, + { + "id": "980", + "parents": [ + "979", + "978" + ] + }, + { + "id": "981", + "parents": [ + "979", + "978" + ] + }, + { + "id": "982", + "parents": [ + "981" + ] + }, + { + "id": "983", + "parents": [ + "982", + "980" + ] + }, + { + "id": "984", + "parents": [ + "983" + ] + }, + { + "id": "985", + "parents": [ + "984" + ] + }, + { + "id": "986", + "parents": [ + "985" + ] + }, + { + "id": "987", + "parents": [ + "985" + ] + }, + { + "id": "988", + "parents": [ + "987" + ] + }, + { + "id": "989", + "parents": [ + "987" + ] + }, + { + "id": "990", + "parents": [ + "989" + ] + }, + { + "id": "991", + "parents": [ + "988", + "986" + ] + }, + { + "id": "992", + "parents": [ + "986", + "988" + ] + }, + { + "id": "993", + "parents": [ + "988", + "986", + "990" + ] + }, + { + "id": "994", + "parents": [ + "993", + "991", + "992" + ] + }, + { + "id": "995", + "parents": [ + "989", + "991", + "992" + ] + }, + { + "id": "996", + "parents": [ + "994", + "995" + ] + }, + { + "id": "997", + "parents": [ + "992", + "993", + "991" + ] + }, + { + "id": "998", + "parents": [ + "994", + "995", + "997" + ] + }, + { + "id": "999", + "parents": [ + "998", + "996" + ] + }, + { + "id": "1000", + "parents": [ + "996", + "998" + ] + }, + { + "id": "1001", + "parents": [ + "996", + "998" + ] + }, + { + "id": "1002", + "parents": [ + "998", + "996" + ] + }, + { + "id": "1003", + "parents": [ + "999", + "1000", + "1001" + ] + }, + { + "id": "1004", + "parents": [ + "1001", + "1000", + "1002", + "999" + ] + }, + { + "id": "1005", + "parents": [ + "1004", + "1003" + ] + }, + { + "id": "1006", + "parents": [ + "1004", + "1003" + ] + }, + { + "id": "1007", + "parents": [ + "1006", + "1005" + ] + }, + { + "id": "1008", + "parents": [ + "1005", + "1006" + ] + }, + { + "id": "1009", + "parents": [ + "1006" + ] + }, + { + "id": "1010", + "parents": [ + "1005", + "1006" + ] + }, + { + "id": "1011", + "parents": [ + "1007", + "1009", + "1008" + ] + }, + { + "id": "1012", + "parents": [ + "1011", + "1010" + ] + }, + { + "id": "1013", + "parents": [ + "1010", + "1011" + ] + }, + { + "id": "1014", + "parents": [ + "1013" + ] + }, + { + "id": "1015", + "parents": [ + "1014" + ] + }, + { + "id": "1016", + "parents": [ + "1012", + "1015" + ] + }, + { + "id": "1017", + "parents": [ + "1011", + "1010" + ] + }, + { + "id": "1018", + "parents": [ + "1017", + "1016" + ] + }, + { + "id": "1019", + "parents": [ + "1018" + ] + }, + { + "id": "1020", + "parents": [ + "1019" + ] + }, + { + "id": "1021", + "parents": [ + "1019" + ] + }, + { + "id": "1022", + "parents": [ + "1018" + ] + }, + { + "id": "1023", + "parents": [ + "1022" + ] + }, + { + "id": "1024", + "parents": [ + "1021", + "1020", + "1023" + ] + }, + { + "id": "1025", + "parents": [ + "1023", + "1020", + "1021" + ] + }, + { + "id": "1026", + "parents": [ + "1023", + "1021", + "1020" + ] + }, + { + "id": "1027", + "parents": [ + "1024" + ] + }, + { + "id": "1028", + "parents": [ + "1026", + "1025", + "1027" + ] + }, + { + "id": "1029", + "parents": [ + "1027", + "1025", + "1026" + ] + }, + { + "id": "1030", + "parents": [ + "1029" + ] + }, + { + "id": "1031", + "parents": [ + "1030" + ] + }, + { + "id": "1032", + "parents": [ + "1031", + "1028" + ] + }, + { + "id": "1033", + "parents": [ + "1032" + ] + }, + { + "id": "1034", + "parents": [ + "1033" + ] + }, + { + "id": "1035", + "parents": [ + "1032" + ] + }, + { + "id": "1036", + "parents": [ + "1033", + "1035" + ] + }, + { + "id": "1037", + "parents": [ + "1033" + ] + }, + { + "id": "1038", + "parents": [ + "1033", + "1035" + ] + }, + { + "id": "1039", + "parents": [ + "1035" + ] + }, + { + "id": "1040", + "parents": [ + "1039", + "1038" + ] + }, + { + "id": "1041", + "parents": [ + "1039" + ] + }, + { + "id": "1042", + "parents": [ + "1034", + "1037", + "1040", + "1036", + "1041" + ] + }, + { + "id": "1043", + "parents": [ + "1034", + "1041", + "1037", + "1040", + "1036" + ] + }, + { + "id": "1044", + "parents": [ + "1041", + "1037", + "1040", + "1036", + "1034" + ] + }, + { + "id": "1045", + "parents": [ + "1044", + "1043", + "1042" + ] + }, + { + "id": "1046", + "parents": [ + "1044", + "1043" + ] + }, + { + "id": "1047", + "parents": [ + "1043", + "1044" + ] + }, + { + "id": "1048", + "parents": [ + "1042", + "1046", + "1047" + ] + }, + { + "id": "1049", + "parents": [ + "1048", + "1045" + ] + }, + { + "id": "1050", + "parents": [ + "1046", + "1047", + "1045" + ] + }, + { + "id": "1051", + "parents": [ + "1050", + "1049" + ] + }, + { + "id": "1052", + "parents": [ + "1050", + "1049" + ] + }, + { + "id": "1053", + "parents": [ + "1052", + "1051" + ] + }, + { + "id": "1054", + "parents": [ + "1053" + ] + }, + { + "id": "1055", + "parents": [ + "1054" + ] + }, + { + "id": "1056", + "parents": [ + "1053" + ] + }, + { + "id": "1057", + "parents": [ + "1053" + ] + }, + { + "id": "1058", + "parents": [ + "1055", + "1056", + "1057" + ] + }, + { + "id": "1059", + "parents": [ + "1058" + ] + }, + { + "id": "1060", + "parents": [ + "1056", + "1057", + "1055" + ] + }, + { + "id": "1061", + "parents": [ + "1060" + ] + }, + { + "id": "1062", + "parents": [ + "1058", + "1060" + ] + }, + { + "id": "1063", + "parents": [ + "1062", + "1061", + "1059" + ] + }, + { + "id": "1064", + "parents": [ + "1061", + "1059", + "1062" + ] + }, + { + "id": "1065", + "parents": [ + "1063", + "1064" + ] + }, + { + "id": "1066", + "parents": [ + "1063", + "1064" + ] + }, + { + "id": "1067", + "parents": [ + "1066", + "1065" + ] + }, + { + "id": "1068", + "parents": [ + "1066", + "1065" + ] + }, + { + "id": "1069", + "parents": [ + "1067", + "1068" + ] + }, + { + "id": "1070", + "parents": [ + "1069" + ] + }, + { + "id": "1071", + "parents": [ + "1070" + ] + }, + { + "id": "1072", + "parents": [ + "1069" + ] + }, + { + "id": "1073", + "parents": [ + "1072", + "1070" + ] + }, + { + "id": "1074", + "parents": [ + "1073", + "1071" + ] + }, + { + "id": "1075", + "parents": [ + "1074" + ] + }, + { + "id": "1076", + "parents": [ + "1074" + ] + }, + { + "id": "1077", + "parents": [ + "1075", + "1076" + ] + }, + { + "id": "1078", + "parents": [ + "1077" + ] + }, + { + "id": "1079", + "parents": [ + "1075" + ] + }, + { + "id": "1080", + "parents": [ + "1079", + "1077" + ] + }, + { + "id": "1081", + "parents": [ + "1080" + ] + }, + { + "id": "1082", + "parents": [ + "1076", + "1079" + ] + }, + { + "id": "1083", + "parents": [ + "1082" + ] + }, + { + "id": "1084", + "parents": [ + "1083", + "1080" + ] + }, + { + "id": "1085", + "parents": [ + "1083", + "1081", + "1078" + ] + }, + { + "id": "1086", + "parents": [ + "1085", + "1084" + ] + }, + { + "id": "1087", + "parents": [ + "1085" + ] + }, + { + "id": "1088", + "parents": [ + "1085", + "1084" + ] + }, + { + "id": "1089", + "parents": [ + "1086", + "1088", + "1087" + ] + }, + { + "id": "1090", + "parents": [ + "1086", + "1088", + "1087" + ] + }, + { + "id": "1091", + "parents": [ + "1090" + ] + }, + { + "id": "1092", + "parents": [ + "1091" + ] + }, + { + "id": "1093", + "parents": [ + "1090", + "1089" + ] + }, + { + "id": "1094", + "parents": [ + "1090", + "1089" + ] + }, + { + "id": "1095", + "parents": [ + "1091", + "1093" + ] + }, + { + "id": "1096", + "parents": [ + "1092", + "1095", + "1094" + ] + }, + { + "id": "1097", + "parents": [ + "1092", + "1095", + "1094" + ] + }, + { + "id": "1098", + "parents": [ + "1097" + ] + }, + { + "id": "1099", + "parents": [ + "1097" + ] + }, + { + "id": "1100", + "parents": [ + "1098" + ] + }, + { + "id": "1101", + "parents": [ + "1099", + "1100" + ] + }, + { + "id": "1102", + "parents": [ + "1098", + "1096" + ] + }, + { + "id": "1103", + "parents": [ + "1102", + "1101" + ] + }, + { + "id": "1104", + "parents": [ + "1101", + "1102" + ] + }, + { + "id": "1105", + "parents": [ + "1102", + "1101" + ] + }, + { + "id": "1106", + "parents": [ + "1105", + "1103" + ] + }, + { + "id": "1107", + "parents": [ + "1106" + ] + }, + { + "id": "1108", + "parents": [ + "1103" + ] + }, + { + "id": "1109", + "parents": [ + "1104", + "1107", + "1108" + ] + }, + { + "id": "1110", + "parents": [ + "1104", + "1107", + "1108" + ] + }, + { + "id": "1111", + "parents": [ + "1107", + "1104", + "1108" + ] + }, + { + "id": "1112", + "parents": [ + "1110", + "1109", + "1111" + ] + }, + { + "id": "1113", + "parents": [ + "1110" + ] + }, + { + "id": "1114", + "parents": [ + "1111", + "1113", + "1109" + ] + }, + { + "id": "1115", + "parents": [ + "1114" + ] + }, + { + "id": "1116", + "parents": [ + "1112", + "1115" + ] + }, + { + "id": "1117", + "parents": [ + "1113", + "1112" + ] + }, + { + "id": "1118", + "parents": [ + "1117", + "1115" + ] + }, + { + "id": "1119", + "parents": [ + "1116", + "1118" + ] + }, + { + "id": "1120", + "parents": [ + "1117", + "1116" + ] + }, + { + "id": "1121", + "parents": [ + "1118", + "1116" + ] + }, + { + "id": "1122", + "parents": [ + "1116", + "1118" + ] + }, + { + "id": "1123", + "parents": [ + "1122", + "1120", + "1119", + "1121" + ] + }, + { + "id": "1124", + "parents": [ + "1119", + "1120", + "1121", + "1122" + ] + }, + { + "id": "1125", + "parents": [ + "1122", + "1120", + "1121", + "1119" + ] + }, + { + "id": "1126", + "parents": [ + "1123", + "1124" + ] + }, + { + "id": "1127", + "parents": [ + "1123" + ] + }, + { + "id": "1128", + "parents": [ + "1125", + "1124", + "1127" + ] + }, + { + "id": "1129", + "parents": [ + "1126", + "1127" + ] + }, + { + "id": "1130", + "parents": [ + "1129", + "1125" + ] + }, + { + "id": "1131", + "parents": [ + "1130", + "1128" + ] + }, + { + "id": "1132", + "parents": [ + "1128", + "1130" + ] + }, + { + "id": "1133", + "parents": [ + "1128", + "1130" + ] + }, + { + "id": "1134", + "parents": [ + "1132", + "1131", + "1133" + ] + }, + { + "id": "1135", + "parents": [ + "1134" + ] + }, + { + "id": "1136", + "parents": [ + "1135" + ] + }, + { + "id": "1137", + "parents": [ + "1134" + ] + }, + { + "id": "1138", + "parents": [ + "1136", + "1137" + ] + }, + { + "id": "1139", + "parents": [ + "1138" + ] + }, + { + "id": "1140", + "parents": [ + "1138" + ] + }, + { + "id": "1141", + "parents": [ + "1140", + "1139" + ] + }, + { + "id": "1142", + "parents": [ + "1141" + ] + }, + { + "id": "1143", + "parents": [ + "1138" + ] + }, + { + "id": "1144", + "parents": [ + "1140", + "1139", + "1143" + ] + }, + { + "id": "1145", + "parents": [ + "1143", + "1140", + "1139" + ] + }, + { + "id": "1146", + "parents": [ + "1145", + "1144", + "1142" + ] + }, + { + "id": "1147", + "parents": [ + "1141", + "1144", + "1145" + ] + }, + { + "id": "1148", + "parents": [ + "1145", + "1144", + "1142" + ] + }, + { + "id": "1149", + "parents": [ + "1148", + "1147" + ] + }, + { + "id": "1150", + "parents": [ + "1149", + "1146" + ] + }, + { + "id": "1151", + "parents": [ + "1149", + "1146" + ] + }, + { + "id": "1152", + "parents": [ + "1149", + "1146" + ] + }, + { + "id": "1153", + "parents": [ + "1152" + ] + }, + { + "id": "1154", + "parents": [ + "1150", + "1151", + "1153" + ] + }, + { + "id": "1155", + "parents": [ + "1154" + ] + }, + { + "id": "1156", + "parents": [ + "1155" + ] + }, + { + "id": "1157", + "parents": [ + "1156" + ] + }, + { + "id": "1158", + "parents": [ + "1157" + ] + }, + { + "id": "1159", + "parents": [ + "1158" + ] + }, + { + "id": "1160", + "parents": [ + "1158" + ] + }, + { + "id": "1161", + "parents": [ + "1160", + "1159" + ] + }, + { + "id": "1162", + "parents": [ + "1159", + "1160" + ] + }, + { + "id": "1163", + "parents": [ + "1161", + "1162" + ] + }, + { + "id": "1164", + "parents": [ + "1163" + ] + }, + { + "id": "1165", + "parents": [ + "1162", + "1161" + ] + }, + { + "id": "1166", + "parents": [ + "1162", + "1161" + ] + }, + { + "id": "1167", + "parents": [ + "1164", + "1166", + "1165" + ] + }, + { + "id": "1168", + "parents": [ + "1166" + ] + }, + { + "id": "1169", + "parents": [ + "1167", + "1168" + ] + }, + { + "id": "1170", + "parents": [ + "1167", + "1168" + ] + }, + { + "id": "1171", + "parents": [ + "1169", + "1170" + ] + }, + { + "id": "1172", + "parents": [ + "1168", + "1167" + ] + }, + { + "id": "1173", + "parents": [ + "1172", + "1171" + ] + }, + { + "id": "1174", + "parents": [ + "1173" + ] + }, + { + "id": "1175", + "parents": [ + "1172", + "1171" + ] + }, + { + "id": "1176", + "parents": [ + "1173", + "1175" + ] + }, + { + "id": "1177", + "parents": [ + "1170", + "1169", + "1172" + ] + }, + { + "id": "1178", + "parents": [ + "1175", + "1173" + ] + }, + { + "id": "1179", + "parents": [ + "1175", + "1173" + ] + }, + { + "id": "1180", + "parents": [ + "1179" + ] + }, + { + "id": "1181", + "parents": [ + "1177", + "1176", + "1178", + "1180", + "1174" + ] + }, + { + "id": "1182", + "parents": [ + "1181" + ] + }, + { + "id": "1183", + "parents": [ + "1181" + ] + }, + { + "id": "1184", + "parents": [ + "1181" + ] + }, + { + "id": "1185", + "parents": [ + "1184" + ] + }, + { + "id": "1186", + "parents": [ + "1185" + ] + }, + { + "id": "1187", + "parents": [ + "1183", + "1186", + "1182" + ] + }, + { + "id": "1188", + "parents": [ + "1187" + ] + }, + { + "id": "1189", + "parents": [ + "1188" + ] + }, + { + "id": "1190", + "parents": [ + "1189" + ] + }, + { + "id": "1191", + "parents": [ + "1189" + ] + }, + { + "id": "1192", + "parents": [ + "1190" + ] + }, + { + "id": "1193", + "parents": [ + "1192", + "1191" + ] + }, + { + "id": "1194", + "parents": [ + "1193" + ] + }, + { + "id": "1195", + "parents": [ + "1194" + ] + }, + { + "id": "1196", + "parents": [ + "1194" + ] + }, + { + "id": "1197", + "parents": [ + "1195" + ] + }, + { + "id": "1198", + "parents": [ + "1196", + "1197" + ] + }, + { + "id": "1199", + "parents": [ + "1196", + "1195" + ] + }, + { + "id": "1200", + "parents": [ + "1196", + "1195" + ] + }, + { + "id": "1201", + "parents": [ + "1200" + ] + }, + { + "id": "1202", + "parents": [ + "1199", + "1198", + "1201" + ] + }, + { + "id": "1203", + "parents": [ + "1199", + "1198" + ] + }, + { + "id": "1204", + "parents": [ + "1201", + "1199", + "1197" + ] + }, + { + "id": "1205", + "parents": [ + "1201", + "1197", + "1199" + ] + }, + { + "id": "1206", + "parents": [ + "1203", + "1205", + "1204" + ] + }, + { + "id": "1207", + "parents": [ + "1206", + "1202" + ] + }, + { + "id": "1208", + "parents": [ + "1207" + ] + }, + { + "id": "1209", + "parents": [ + "1202", + "1206" + ] + }, + { + "id": "1210", + "parents": [ + "1207", + "1209" + ] + }, + { + "id": "1211", + "parents": [ + "1208", + "1209" + ] + }, + { + "id": "1212", + "parents": [ + "1207", + "1209" + ] + }, + { + "id": "1213", + "parents": [ + "1212", + "1208", + "1210" + ] + }, + { + "id": "1214", + "parents": [ + "1213", + "1211" + ] + }, + { + "id": "1215", + "parents": [ + "1214" + ] + }, + { + "id": "1216", + "parents": [ + "1214" + ] + }, + { + "id": "1217", + "parents": [ + "1216" + ] + }, + { + "id": "1218", + "parents": [ + "1214" + ] + }, + { + "id": "1219", + "parents": [ + "1217", + "1215" + ] + }, + { + "id": "1220", + "parents": [ + "1217", + "1215", + "1218" + ] + }, + { + "id": "1221", + "parents": [ + "1219", + "1220" + ] + }, + { + "id": "1222", + "parents": [ + "1216", + "1215" + ] + }, + { + "id": "1223", + "parents": [ + "1217", + "1215", + "1218" + ] + }, + { + "id": "1224", + "parents": [ + "1220", + "1222", + "1219" + ] + }, + { + "id": "1225", + "parents": [ + "1219", + "1222", + "1223", + "1220" + ] + }, + { + "id": "1226", + "parents": [ + "1224", + "1225", + "1221" + ] + }, + { + "id": "1227", + "parents": [ + "1226" + ] + }, + { + "id": "1228", + "parents": [ + "1226" + ] + }, + { + "id": "1229", + "parents": [ + "1226" + ] + }, + { + "id": "1230", + "parents": [ + "1229", + "1228" + ] + }, + { + "id": "1231", + "parents": [ + "1230", + "1227" + ] + }, + { + "id": "1232", + "parents": [ + "1230", + "1227" + ] + }, + { + "id": "1233", + "parents": [ + "1227", + "1230" + ] + }, + { + "id": "1234", + "parents": [ + "1233", + "1231", + "1232" + ] + }, + { + "id": "1235", + "parents": [ + "1233", + "1231", + "1232" + ] + }, + { + "id": "1236", + "parents": [ + "1235" + ] + }, + { + "id": "1237", + "parents": [ + "1235" + ] + }, + { + "id": "1238", + "parents": [ + "1237", + "1236", + "1234" + ] + }, + { + "id": "1239", + "parents": [ + "1237", + "1236" + ] + }, + { + "id": "1240", + "parents": [ + "1234", + "1236", + "1237" + ] + }, + { + "id": "1241", + "parents": [ + "1234", + "1236" + ] + }, + { + "id": "1242", + "parents": [ + "1238", + "1239", + "1241", + "1240" + ] + }, + { + "id": "1243", + "parents": [ + "1239", + "1238", + "1241", + "1240" + ] + }, + { + "id": "1244", + "parents": [ + "1243", + "1242" + ] + }, + { + "id": "1245", + "parents": [ + "1242", + "1243" + ] + }, + { + "id": "1246", + "parents": [ + "1244", + "1245" + ] + }, + { + "id": "1247", + "parents": [ + "1244" + ] + }, + { + "id": "1248", + "parents": [ + "1244", + "1245" + ] + }, + { + "id": "1249", + "parents": [ + "1247", + "1248" + ] + }, + { + "id": "1250", + "parents": [ + "1249" + ] + }, + { + "id": "1251", + "parents": [ + "1250", + "1246" + ] + }, + { + "id": "1252", + "parents": [ + "1251" + ] + }, + { + "id": "1253", + "parents": [ + "1251" + ] + }, + { + "id": "1254", + "parents": [ + "1252", + "1253" + ] + }, + { + "id": "1255", + "parents": [ + "1254" + ] + }, + { + "id": "1256", + "parents": [ + "1253", + "1252" + ] + }, + { + "id": "1257", + "parents": [ + "1256" + ] + }, + { + "id": "1258", + "parents": [ + "1257", + "1254" + ] + }, + { + "id": "1259", + "parents": [ + "1255", + "1258" + ] + }, + { + "id": "1260", + "parents": [ + "1258" + ] + }, + { + "id": "1261", + "parents": [ + "1255", + "1258" + ] + }, + { + "id": "1262", + "parents": [ + "1258" + ] + }, + { + "id": "1263", + "parents": [ + "1259", + "1260", + "1261", + "1262" + ] + }, + { + "id": "1264", + "parents": [ + "1261", + "1260", + "1259", + "1262" + ] + }, + { + "id": "1265", + "parents": [ + "1259", + "1260", + "1262", + "1261" + ] + }, + { + "id": "1266", + "parents": [ + "1263", + "1265", + "1264" + ] + }, + { + "id": "1267", + "parents": [ + "1266" + ] + }, + { + "id": "1268", + "parents": [ + "1267" + ] + }, + { + "id": "1269", + "parents": [ + "1266" + ] + }, + { + "id": "1270", + "parents": [ + "1268" + ] + }, + { + "id": "1271", + "parents": [ + "1270", + "1269" + ] + }, + { + "id": "1272", + "parents": [ + "1269", + "1270" + ] + }, + { + "id": "1273", + "parents": [ + "1269", + "1268" + ] + }, + { + "id": "1274", + "parents": [ + "1272", + "1273", + "1271" + ] + }, + { + "id": "1275", + "parents": [ + "1272", + "1271", + "1273" + ] + }, + { + "id": "1276", + "parents": [ + "1275" + ] + }, + { + "id": "1277", + "parents": [ + "1274" + ] + }, + { + "id": "1278", + "parents": [ + "1276", + "1274" + ] + }, + { + "id": "1279", + "parents": [ + "1276", + "1274" + ] + }, + { + "id": "1280", + "parents": [ + "1277", + "1276" + ] + }, + { + "id": "1281", + "parents": [ + "1278", + "1280", + "1279" + ] + }, + { + "id": "1282", + "parents": [ + "1281" + ] + }, + { + "id": "1283", + "parents": [ + "1282" + ] + }, + { + "id": "1284", + "parents": [ + "1283" + ] + }, + { + "id": "1285", + "parents": [ + "1281" + ] + }, + { + "id": "1286", + "parents": [ + "1281" + ] + }, + { + "id": "1287", + "parents": [ + "1282" + ] + }, + { + "id": "1288", + "parents": [ + "1284", + "1286", + "1285" + ] + }, + { + "id": "1289", + "parents": [ + "1285", + "1283", + "1286", + "1287" + ] + }, + { + "id": "1290", + "parents": [ + "1284", + "1289" + ] + }, + { + "id": "1291", + "parents": [ + "1287", + "1285", + "1286", + "1284" + ] + }, + { + "id": "1292", + "parents": [ + "1290" + ] + }, + { + "id": "1293", + "parents": [ + "1292" + ] + }, + { + "id": "1294", + "parents": [ + "1288", + "1290", + "1291" + ] + }, + { + "id": "1295", + "parents": [ + "1293", + "1288", + "1291" + ] + }, + { + "id": "1296", + "parents": [ + "1288", + "1291" + ] + }, + { + "id": "1297", + "parents": [ + "1294" + ] + }, + { + "id": "1298", + "parents": [ + "1296", + "1297", + "1295" + ] + }, + { + "id": "1299", + "parents": [ + "1293", + "1288", + "1291" + ] + }, + { + "id": "1300", + "parents": [ + "1295", + "1299", + "1296" + ] + }, + { + "id": "1301", + "parents": [ + "1298", + "1300" + ] + }, + { + "id": "1302", + "parents": [ + "1301" + ] + }, + { + "id": "1303", + "parents": [ + "1302" + ] + }, + { + "id": "1304", + "parents": [ + "1303" + ] + }, + { + "id": "1305", + "parents": [ + "1303" + ] + }, + { + "id": "1306", + "parents": [ + "1305", + "1304" + ] + }, + { + "id": "1307", + "parents": [ + "1303" + ] + }, + { + "id": "1308", + "parents": [ + "1307", + "1304", + "1305" + ] + }, + { + "id": "1309", + "parents": [ + "1305", + "1304" + ] + }, + { + "id": "1310", + "parents": [ + "1309", + "1306", + "1308" + ] + }, + { + "id": "1311", + "parents": [ + "1305", + "1307", + "1304" + ] + }, + { + "id": "1312", + "parents": [ + "1310", + "1311" + ] + }, + { + "id": "1313", + "parents": [ + "1312" + ] + }, + { + "id": "1314", + "parents": [ + "1312" + ] + }, + { + "id": "1315", + "parents": [ + "1312" + ] + }, + { + "id": "1316", + "parents": [ + "1312" + ] + }, + { + "id": "1317", + "parents": [ + "1313", + "1315", + "1314" + ] + }, + { + "id": "1318", + "parents": [ + "1312" + ] + }, + { + "id": "1319", + "parents": [ + "1317", + "1316" + ] + }, + { + "id": "1320", + "parents": [ + "1319", + "1318" + ] + }, + { + "id": "1321", + "parents": [ + "1319", + "1318" + ] + }, + { + "id": "1322", + "parents": [ + "1321" + ] + }, + { + "id": "1323", + "parents": [ + "1322", + "1320" + ] + }, + { + "id": "1324", + "parents": [ + "1322", + "1320" + ] + }, + { + "id": "1325", + "parents": [ + "1323", + "1324" + ] + }, + { + "id": "1326", + "parents": [ + "1320", + "1322" + ] + }, + { + "id": "1327", + "parents": [ + "1320", + "1322" + ] + }, + { + "id": "1328", + "parents": [ + "1323", + "1324", + "1326" + ] + }, + { + "id": "1329", + "parents": [ + "1328" + ] + }, + { + "id": "1330", + "parents": [ + "1323", + "1327" + ] + }, + { + "id": "1331", + "parents": [ + "1327", + "1325", + "1328" + ] + }, + { + "id": "1332", + "parents": [ + "1330", + "1325", + "1329" + ] + }, + { + "id": "1333", + "parents": [ + "1331", + "1332" + ] + }, + { + "id": "1334", + "parents": [ + "1333" + ] + }, + { + "id": "1335", + "parents": [ + "1333" + ] + }, + { + "id": "1336", + "parents": [ + "1333" + ] + }, + { + "id": "1337", + "parents": [ + "1335" + ] + }, + { + "id": "1338", + "parents": [ + "1333" + ] + }, + { + "id": "1339", + "parents": [ + "1334", + "1336", + "1337" + ] + }, + { + "id": "1340", + "parents": [ + "1336", + "1338", + "1334", + "1337" + ] + }, + { + "id": "1341", + "parents": [ + "1339", + "1340" + ] + }, + { + "id": "1342", + "parents": [ + "1339" + ] + }, + { + "id": "1343", + "parents": [ + "1342", + "1338" + ] + }, + { + "id": "1344", + "parents": [ + "1334", + "1337", + "1338", + "1336" + ] + }, + { + "id": "1345", + "parents": [ + "1343", + "1344", + "1340" + ] + }, + { + "id": "1346", + "parents": [ + "1341", + "1345" + ] + }, + { + "id": "1347", + "parents": [ + "1341", + "1345" + ] + }, + { + "id": "1348", + "parents": [ + "1347", + "1346" + ] + }, + { + "id": "1349", + "parents": [ + "1345", + "1341" + ] + }, + { + "id": "1350", + "parents": [ + "1349" + ] + }, + { + "id": "1351", + "parents": [ + "1350", + "1347", + "1346" + ] + }, + { + "id": "1352", + "parents": [ + "1341", + "1345" + ] + }, + { + "id": "1353", + "parents": [ + "1348", + "1352", + "1351" + ] + }, + { + "id": "1354", + "parents": [ + "1346", + "1347", + "1350", + "1352" + ] + }, + { + "id": "1355", + "parents": [ + "1347", + "1350", + "1352" + ] + }, + { + "id": "1356", + "parents": [ + "1355", + "1351", + "1354" + ] + }, + { + "id": "1357", + "parents": [ + "1355", + "1351", + "1354", + "1348" + ] + }, + { + "id": "1358", + "parents": [ + "1356", + "1357", + "1353" + ] + }, + { + "id": "1359", + "parents": [ + "1358" + ] + }, + { + "id": "1360", + "parents": [ + "1357", + "1356", + "1353" + ] + }, + { + "id": "1361", + "parents": [ + "1359" + ] + }, + { + "id": "1362", + "parents": [ + "1359", + "1360" + ] + }, + { + "id": "1363", + "parents": [ + "1361", + "1360" + ] + }, + { + "id": "1364", + "parents": [ + "1363", + "1362" + ] + }, + { + "id": "1365", + "parents": [ + "1363", + "1362" + ] + }, + { + "id": "1366", + "parents": [ + "1364", + "1365" + ] + }, + { + "id": "1367", + "parents": [ + "1365" + ] + }, + { + "id": "1368", + "parents": [ + "1366", + "1367" + ] + }, + { + "id": "1369", + "parents": [ + "1367" + ] + }, + { + "id": "1370", + "parents": [ + "1365" + ] + }, + { + "id": "1371", + "parents": [ + "1370", + "1368", + "1369" + ] + }, + { + "id": "1372", + "parents": [ + "1371" + ] + }, + { + "id": "1373", + "parents": [ + "1371" + ] + }, + { + "id": "1374", + "parents": [ + "1373" + ] + }, + { + "id": "1375", + "parents": [ + "1372", + "1374" + ] + }, + { + "id": "1376", + "parents": [ + "1372", + "1374" + ] + }, + { + "id": "1377", + "parents": [ + "1374", + "1372" + ] + }, + { + "id": "1378", + "parents": [ + "1377" + ] + }, + { + "id": "1379", + "parents": [ + "1374", + "1372" + ] + }, + { + "id": "1380", + "parents": [ + "1379", + "1378", + "1375", + "1376" + ] + }, + { + "id": "1381", + "parents": [ + "1380" + ] + }, + { + "id": "1382", + "parents": [ + "1380" + ] + }, + { + "id": "1383", + "parents": [ + "1382", + "1381" + ] + }, + { + "id": "1384", + "parents": [ + "1381", + "1382" + ] + }, + { + "id": "1385", + "parents": [ + "1381", + "1382" + ] + }, + { + "id": "1386", + "parents": [ + "1384", + "1385" + ] + }, + { + "id": "1387", + "parents": [ + "1384", + "1385" + ] + }, + { + "id": "1388", + "parents": [ + "1387", + "1383" + ] + }, + { + "id": "1389", + "parents": [ + "1384", + "1385", + "1383" + ] + }, + { + "id": "1390", + "parents": [ + "1383", + "1386" + ] + }, + { + "id": "1391", + "parents": [ + "1389", + "1388", + "1386" + ] + }, + { + "id": "1392", + "parents": [ + "1391", + "1390" + ] + }, + { + "id": "1393", + "parents": [ + "1389", + "1390", + "1387" + ] + }, + { + "id": "1394", + "parents": [ + "1393" + ] + }, + { + "id": "1395", + "parents": [ + "1388", + "1390", + "1389" + ] + }, + { + "id": "1396", + "parents": [ + "1391", + "1395", + "1394" + ] + }, + { + "id": "1397", + "parents": [ + "1394", + "1395", + "1392" + ] + }, + { + "id": "1398", + "parents": [ + "1394", + "1395" + ] + }, + { + "id": "1399", + "parents": [ + "1398", + "1391" + ] + }, + { + "id": "1400", + "parents": [ + "1391", + "1398" + ] + }, + { + "id": "1401", + "parents": [ + "1400", + "1392" + ] + }, + { + "id": "1402", + "parents": [ + "1397", + "1401" + ] + }, + { + "id": "1403", + "parents": [ + "1401", + "1396", + "1397", + "1399" + ] + }, + { + "id": "1404", + "parents": [ + "1396", + "1399", + "1392" + ] + }, + { + "id": "1405", + "parents": [ + "1404", + "1402" + ] + }, + { + "id": "1406", + "parents": [ + "1405", + "1403" + ] + }, + { + "id": "1407", + "parents": [ + "1404", + "1402" + ] + }, + { + "id": "1408", + "parents": [ + "1406", + "1407" + ] + }, + { + "id": "1409", + "parents": [ + "1408" + ] + }, + { + "id": "1410", + "parents": [ + "1408" + ] + }, + { + "id": "1411", + "parents": [ + "1409", + "1410" + ] + }, + { + "id": "1412", + "parents": [ + "1411" + ] + }, + { + "id": "1413", + "parents": [ + "1412" + ] + }, + { + "id": "1414", + "parents": [ + "1410", + "1409" + ] + }, + { + "id": "1415", + "parents": [ + "1414" + ] + }, + { + "id": "1416", + "parents": [ + "1414", + "1411" + ] + }, + { + "id": "1417", + "parents": [ + "1415", + "1413" + ] + }, + { + "id": "1418", + "parents": [ + "1417", + "1416" + ] + }, + { + "id": "1419", + "parents": [ + "1416", + "1415", + "1413" + ] + }, + { + "id": "1420", + "parents": [ + "1418", + "1419" + ] + }, + { + "id": "1421", + "parents": [ + "1419" + ] + }, + { + "id": "1422", + "parents": [ + "1421", + "1418" + ] + }, + { + "id": "1423", + "parents": [ + "1418", + "1421" + ] + }, + { + "id": "1424", + "parents": [ + "1419", + "1418" + ] + }, + { + "id": "1425", + "parents": [ + "1421", + "1418" + ] + }, + { + "id": "1426", + "parents": [ + "1425", + "1424", + "1423", + "1422", + "1420" + ] + }, + { + "id": "1427", + "parents": [ + "1424", + "1422", + "1420", + "1425", + "1423" + ] + }, + { + "id": "1428", + "parents": [ + "1427" + ] + }, + { + "id": "1429", + "parents": [ + "1426", + "1427" + ] + }, + { + "id": "1430", + "parents": [ + "1426" + ] + }, + { + "id": "1431", + "parents": [ + "1430" + ] + }, + { + "id": "1432", + "parents": [ + "1430", + "1429" + ] + }, + { + "id": "1433", + "parents": [ + "1430", + "1427" + ] + }, + { + "id": "1434", + "parents": [ + "1433", + "1431", + "1428", + "1429" + ] + }, + { + "id": "1435", + "parents": [ + "1433", + "1428", + "1431" + ] + }, + { + "id": "1436", + "parents": [ + "1432", + "1434" + ] + }, + { + "id": "1437", + "parents": [ + "1435", + "1432" + ] + }, + { + "id": "1438", + "parents": [ + "1432", + "1434", + "1435" + ] + }, + { + "id": "1439", + "parents": [ + "1438", + "1437", + "1436" + ] + }, + { + "id": "1440", + "parents": [ + "1439" + ] + }, + { + "id": "1441", + "parents": [ + "1439" + ] + }, + { + "id": "1442", + "parents": [ + "1439" + ] + }, + { + "id": "1443", + "parents": [ + "1440", + "1441", + "1442" + ] + }, + { + "id": "1444", + "parents": [ + "1440" + ] + }, + { + "id": "1445", + "parents": [ + "1444", + "1443" + ] + }, + { + "id": "1446", + "parents": [ + "1445" + ] + }, + { + "id": "1447", + "parents": [ + "1442", + "1441", + "1440" + ] + }, + { + "id": "1448", + "parents": [ + "1442", + "1440", + "1441" + ] + }, + { + "id": "1449", + "parents": [ + "1444", + "1448", + "1443" + ] + }, + { + "id": "1450", + "parents": [ + "1448", + "1443", + "1447", + "1444" + ] + }, + { + "id": "1451", + "parents": [ + "1449", + "1447", + "1446" + ] + }, + { + "id": "1452", + "parents": [ + "1450" + ] + }, + { + "id": "1453", + "parents": [ + "1452" + ] + }, + { + "id": "1454", + "parents": [ + "1449", + "1453", + "1446" + ] + }, + { + "id": "1455", + "parents": [ + "1446", + "1449", + "1453" + ] + }, + { + "id": "1456", + "parents": [ + "1453", + "1449", + "1446" + ] + }, + { + "id": "1457", + "parents": [ + "1447", + "1449" + ] + }, + { + "id": "1458", + "parents": [ + "1457", + "1455" + ] + }, + { + "id": "1459", + "parents": [ + "1457", + "1455", + "1456", + "1451" + ] + }, + { + "id": "1460", + "parents": [ + "1454", + "1459", + "1458" + ] + }, + { + "id": "1461", + "parents": [ + "1458", + "1459", + "1454" + ] + }, + { + "id": "1462", + "parents": [ + "1454", + "1458", + "1459" + ] + }, + { + "id": "1463", + "parents": [ + "1462" + ] + }, + { + "id": "1464", + "parents": [ + "1461", + "1463", + "1460" + ] + }, + { + "id": "1465", + "parents": [ + "1464" + ] + }, + { + "id": "1466", + "parents": [ + "1465" + ] + }, + { + "id": "1467", + "parents": [ + "1464" + ] + }, + { + "id": "1468", + "parents": [ + "1465" + ] + }, + { + "id": "1469", + "parents": [ + "1468" + ] + }, + { + "id": "1470", + "parents": [ + "1466", + "1469", + "1467" + ] + }, + { + "id": "1471", + "parents": [ + "1470" + ] + }, + { + "id": "1472", + "parents": [ + "1466", + "1469", + "1467" + ] + }, + { + "id": "1473", + "parents": [ + "1466", + "1467", + "1469" + ] + }, + { + "id": "1474", + "parents": [ + "1473", + "1470", + "1472" + ] + }, + { + "id": "1475", + "parents": [ + "1474" + ] + }, + { + "id": "1476", + "parents": [ + "1475", + "1471" + ] + }, + { + "id": "1477", + "parents": [ + "1476" + ] + }, + { + "id": "1478", + "parents": [ + "1475", + "1471" + ] + }, + { + "id": "1479", + "parents": [ + "1471", + "1475" + ] + }, + { + "id": "1480", + "parents": [ + "1475", + "1471" + ] + }, + { + "id": "1481", + "parents": [ + "1478", + "1480", + "1476" + ] + }, + { + "id": "1482", + "parents": [ + "1476", + "1480" + ] + }, + { + "id": "1483", + "parents": [ + "1477", + "1482", + "1481", + "1479" + ] + }, + { + "id": "1484", + "parents": [ + "1481", + "1477", + "1482", + "1479" + ] + }, + { + "id": "1485", + "parents": [ + "1483", + "1484" + ] + }, + { + "id": "1486", + "parents": [ + "1481", + "1477", + "1482", + "1479" + ] + }, + { + "id": "1487", + "parents": [ + "1479", + "1482", + "1477", + "1481" + ] + }, + { + "id": "1488", + "parents": [ + "1479", + "1477", + "1481", + "1482" + ] + }, + { + "id": "1489", + "parents": [ + "1484", + "1483", + "1486" + ] + }, + { + "id": "1490", + "parents": [ + "1487", + "1483", + "1486", + "1488", + "1484" + ] + }, + { + "id": "1491", + "parents": [ + "1484", + "1483" + ] + }, + { + "id": "1492", + "parents": [ + "1489", + "1491", + "1490" + ] + }, + { + "id": "1493", + "parents": [ + "1487", + "1488", + "1486", + "1491" + ] + }, + { + "id": "1494", + "parents": [ + "1485", + "1491", + "1489", + "1490" + ] + }, + { + "id": "1495", + "parents": [ + "1492" + ] + }, + { + "id": "1496", + "parents": [ + "1491", + "1490", + "1489", + "1485" + ] + }, + { + "id": "1497", + "parents": [ + "1485", + "1493", + "1489", + "1490" + ] + }, + { + "id": "1498", + "parents": [ + "1496", + "1497", + "1495", + "1494" + ] + }, + { + "id": "1499", + "parents": [ + "1496", + "1495", + "1497", + "1494" + ] + }, + { + "id": "1500", + "parents": [ + "1495", + "1497", + "1494", + "1496" + ] + }, + { + "id": "1501", + "parents": [ + "1500", + "1499" + ] + }, + { + "id": "1502", + "parents": [ + "1499" + ] + }, + { + "id": "1503", + "parents": [ + "1502", + "1500", + "1498" + ] + }, + { + "id": "1504", + "parents": [ + "1501", + "1503" + ] + }, + { + "id": "1505", + "parents": [ + "1501", + "1503" + ] + }, + { + "id": "1506", + "parents": [ + "1503", + "1501" + ] + }, + { + "id": "1507", + "parents": [ + "1504", + "1505", + "1506" + ] + }, + { + "id": "1508", + "parents": [ + "1507" + ] + }, + { + "id": "1509", + "parents": [ + "1505" + ] + }, + { + "id": "1510", + "parents": [ + "1505" + ] + }, + { + "id": "1511", + "parents": [ + "1508", + "1509", + "1510" + ] + }, + { + "id": "1512", + "parents": [ + "1509", + "1508", + "1510" + ] + }, + { + "id": "1513", + "parents": [ + "1511" + ] + }, + { + "id": "1514", + "parents": [ + "1512", + "1513" + ] + }, + { + "id": "1515", + "parents": [ + "1511", + "1512" + ] + }, + { + "id": "1516", + "parents": [ + "1515", + "1513" + ] + }, + { + "id": "1517", + "parents": [ + "1515", + "1514" + ] + }, + { + "id": "1518", + "parents": [ + "1516", + "1517" + ] + }, + { + "id": "1519", + "parents": [ + "1512", + "1513" + ] + }, + { + "id": "1520", + "parents": [ + "1515", + "1514" + ] + }, + { + "id": "1521", + "parents": [ + "1518", + "1519" + ] + }, + { + "id": "1522", + "parents": [ + "1520", + "1521" + ] + }, + { + "id": "1523", + "parents": [ + "1522" + ] + }, + { + "id": "1524", + "parents": [ + "1521", + "1520" + ] + }, + { + "id": "1525", + "parents": [ + "1524", + "1523" + ] + }, + { + "id": "1526", + "parents": [ + "1523" + ] + }, + { + "id": "1527", + "parents": [ + "1526" + ] + }, + { + "id": "1528", + "parents": [ + "1526", + "1525" + ] + }, + { + "id": "1529", + "parents": [ + "1526", + "1525" + ] + }, + { + "id": "1530", + "parents": [ + "1527", + "1528" + ] + }, + { + "id": "1531", + "parents": [ + "1530", + "1529" + ] + }, + { + "id": "1532", + "parents": [ + "1530", + "1529" + ] + }, + { + "id": "1533", + "parents": [ + "1532" + ] + }, + { + "id": "1534", + "parents": [ + "1531", + "1532" + ] + }, + { + "id": "1535", + "parents": [ + "1534" + ] + }, + { + "id": "1536", + "parents": [ + "1535" + ] + }, + { + "id": "1537", + "parents": [ + "1533", + "1535" + ] + }, + { + "id": "1538", + "parents": [ + "1537" + ] + }, + { + "id": "1539", + "parents": [ + "1533", + "1536" + ] + }, + { + "id": "1540", + "parents": [ + "1536", + "1533" + ] + }, + { + "id": "1541", + "parents": [ + "1536", + "1538" + ] + }, + { + "id": "1542", + "parents": [ + "1540", + "1541" + ] + }, + { + "id": "1543", + "parents": [ + "1538", + "1540", + "1539" + ] + }, + { + "id": "1544", + "parents": [ + "1543", + "1541" + ] + }, + { + "id": "1545", + "parents": [ + "1542" + ] + }, + { + "id": "1546", + "parents": [ + "1544" + ] + }, + { + "id": "1547", + "parents": [ + "1545", + "1546" + ] + }, + { + "id": "1548", + "parents": [ + "1547" + ] + }, + { + "id": "1549", + "parents": [ + "1546", + "1545" + ] + }, + { + "id": "1550", + "parents": [ + "1548" + ] + }, + { + "id": "1551", + "parents": [ + "1549", + "1550" + ] + }, + { + "id": "1552", + "parents": [ + "1549", + "1550" + ] + }, + { + "id": "1553", + "parents": [ + "1551" + ] + }, + { + "id": "1554", + "parents": [ + "1549", + "1550" + ] + }, + { + "id": "1555", + "parents": [ + "1553", + "1554", + "1552" + ] + }, + { + "id": "1556", + "parents": [ + "1551", + "1552" + ] + }, + { + "id": "1557", + "parents": [ + "1551" + ] + }, + { + "id": "1558", + "parents": [ + "1557", + "1552" + ] + }, + { + "id": "1559", + "parents": [ + "1558" + ] + }, + { + "id": "1560", + "parents": [ + "1559" + ] + }, + { + "id": "1561", + "parents": [ + "1551" + ] + }, + { + "id": "1562", + "parents": [ + "1560", + "1555", + "1556", + "1561" + ] + }, + { + "id": "1563", + "parents": [ + "1553", + "1561", + "1558" + ] + }, + { + "id": "1564", + "parents": [ + "1556", + "1560", + "1563", + "1555" + ] + }, + { + "id": "1565", + "parents": [ + "1562", + "1564" + ] + }, + { + "id": "1566", + "parents": [ + "1565" + ] + }, + { + "id": "1567", + "parents": [ + "1566" + ] + }, + { + "id": "1568", + "parents": [ + "1565" + ] + }, + { + "id": "1569", + "parents": [ + "1567" + ] + }, + { + "id": "1570", + "parents": [ + "1568", + "1569" + ] + }, + { + "id": "1571", + "parents": [ + "1570" + ] + }, + { + "id": "1572", + "parents": [ + "1570" + ] + }, + { + "id": "1573", + "parents": [ + "1572" + ] + }, + { + "id": "1574", + "parents": [ + "1573" + ] + }, + { + "id": "1575", + "parents": [ + "1572", + "1571" + ] + }, + { + "id": "1576", + "parents": [ + "1571", + "1574" + ] + }, + { + "id": "1577", + "parents": [ + "1571", + "1573" + ] + }, + { + "id": "1578", + "parents": [ + "1577", + "1574" + ] + }, + { + "id": "1579", + "parents": [ + "1576", + "1575", + "1577" + ] + }, + { + "id": "1580", + "parents": [ + "1578", + "1579" + ] + }, + { + "id": "1581", + "parents": [ + "1575", + "1576", + "1577" + ] + }, + { + "id": "1582", + "parents": [ + "1581", + "1580" + ] + }, + { + "id": "1583", + "parents": [ + "1579", + "1581", + "1578" + ] + }, + { + "id": "1584", + "parents": [ + "1582", + "1583" + ] + }, + { + "id": "1585", + "parents": [ + "1582", + "1583" + ] + }, + { + "id": "1586", + "parents": [ + "1583", + "1582" + ] + }, + { + "id": "1587", + "parents": [ + "1585", + "1584" + ] + }, + { + "id": "1588", + "parents": [ + "1586", + "1587" + ] + }, + { + "id": "1589", + "parents": [ + "1588" + ] + }, + { + "id": "1590", + "parents": [ + "1589" + ] + }, + { + "id": "1591", + "parents": [ + "1588" + ] + }, + { + "id": "1592", + "parents": [ + "1591" + ] + }, + { + "id": "1593", + "parents": [ + "1589", + "1591" + ] + }, + { + "id": "1594", + "parents": [ + "1590", + "1591" + ] + }, + { + "id": "1595", + "parents": [ + "1594" + ] + }, + { + "id": "1596", + "parents": [ + "1593", + "1592", + "1590" + ] + }, + { + "id": "1597", + "parents": [ + "1596", + "1595" + ] + }, + { + "id": "1598", + "parents": [ + "1596", + "1595" + ] + }, + { + "id": "1599", + "parents": [ + "1598", + "1597" + ] + }, + { + "id": "1600", + "parents": [ + "1598", + "1597" + ] + }, + { + "id": "1601", + "parents": [ + "1596", + "1595" + ] + }, + { + "id": "1602", + "parents": [ + "1601", + "1600" + ] + }, + { + "id": "1603", + "parents": [ + "1602", + "1599" + ] + }, + { + "id": "1604", + "parents": [ + "1602", + "1599" + ] + }, + { + "id": "1605", + "parents": [ + "1604", + "1603" + ] + }, + { + "id": "1606", + "parents": [ + "1604" + ] + }, + { + "id": "1607", + "parents": [ + "1605", + "1606" + ] + }, + { + "id": "1608", + "parents": [ + "1606", + "1605" + ] + }, + { + "id": "1609", + "parents": [ + "1607" + ] + }, + { + "id": "1610", + "parents": [ + "1609", + "1608" + ] + }, + { + "id": "1611", + "parents": [ + "1607" + ] + }, + { + "id": "1612", + "parents": [ + "1611", + "1610" + ] + }, + { + "id": "1613", + "parents": [ + "1607" + ] + }, + { + "id": "1614", + "parents": [ + "1610", + "1611", + "1613" + ] + }, + { + "id": "1615", + "parents": [ + "1614" + ] + }, + { + "id": "1616", + "parents": [ + "1615", + "1612" + ] + }, + { + "id": "1617", + "parents": [ + "1612", + "1613" + ] + }, + { + "id": "1618", + "parents": [ + "1615", + "1612" + ] + }, + { + "id": "1619", + "parents": [ + "1616", + "1618", + "1617" + ] + }, + { + "id": "1620", + "parents": [ + "1616", + "1617", + "1618" + ] + }, + { + "id": "1621", + "parents": [ + "1617", + "1618", + "1616" + ] + }, + { + "id": "1622", + "parents": [ + "1616", + "1618", + "1617" + ] + }, + { + "id": "1623", + "parents": [ + "1619", + "1622", + "1620", + "1621" + ] + }, + { + "id": "1624", + "parents": [ + "1620", + "1622", + "1619", + "1621" + ] + }, + { + "id": "1625", + "parents": [ + "1623" + ] + }, + { + "id": "1626", + "parents": [ + "1625", + "1624" + ] + }, + { + "id": "1627", + "parents": [ + "1625", + "1624" + ] + }, + { + "id": "1628", + "parents": [ + "1627", + "1626" + ] + }, + { + "id": "1629", + "parents": [ + "1624", + "1625" + ] + }, + { + "id": "1630", + "parents": [ + "1629" + ] + }, + { + "id": "1631", + "parents": [ + "1625", + "1624" + ] + }, + { + "id": "1632", + "parents": [ + "1631", + "1626", + "1627", + "1630" + ] + }, + { + "id": "1633", + "parents": [ + "1628", + "1632" + ] + }, + { + "id": "1634", + "parents": [ + "1633" + ] + }, + { + "id": "1635", + "parents": [ + "1632", + "1628" + ] + }, + { + "id": "1636", + "parents": [ + "1632", + "1628" + ] + }, + { + "id": "1637", + "parents": [ + "1633" + ] + }, + { + "id": "1638", + "parents": [ + "1633", + "1635", + "1636" + ] + }, + { + "id": "1639", + "parents": [ + "1636", + "1637", + "1634", + "1635" + ] + }, + { + "id": "1640", + "parents": [ + "1638", + "1634" + ] + }, + { + "id": "1641", + "parents": [ + "1638", + "1639" + ] + }, + { + "id": "1642", + "parents": [ + "1639" + ] + }, + { + "id": "1643", + "parents": [ + "1642" + ] + }, + { + "id": "1644", + "parents": [ + "1640", + "1641", + "1643" + ] + }, + { + "id": "1645", + "parents": [ + "1637", + "1635", + "1634", + "1636" + ] + }, + { + "id": "1646", + "parents": [ + "1640", + "1645", + "1643", + "1641" + ] + }, + { + "id": "1647", + "parents": [ + "1640", + "1645", + "1641" + ] + }, + { + "id": "1648", + "parents": [ + "1643", + "1647" + ] + }, + { + "id": "1649", + "parents": [ + "1646", + "1648", + "1644" + ] + }, + { + "id": "1650", + "parents": [ + "1648", + "1646", + "1644" + ] + }, + { + "id": "1651", + "parents": [ + "1650", + "1649" + ] + }, + { + "id": "1652", + "parents": [ + "1650", + "1649" + ] + }, + { + "id": "1653", + "parents": [ + "1652" + ] + }, + { + "id": "1654", + "parents": [ + "1651", + "1653" + ] + }, + { + "id": "1655", + "parents": [ + "1654" + ] + }, + { + "id": "1656", + "parents": [ + "1651" + ] + }, + { + "id": "1657", + "parents": [ + "1656", + "1653" + ] + }, + { + "id": "1658", + "parents": [ + "1657", + "1655" + ] + }, + { + "id": "1659", + "parents": [ + "1657" + ] + }, + { + "id": "1660", + "parents": [ + "1656", + "1655" + ] + }, + { + "id": "1661", + "parents": [ + "1659", + "1658" + ] + }, + { + "id": "1662", + "parents": [ + "1657", + "1655" + ] + }, + { + "id": "1663", + "parents": [ + "1662" + ] + }, + { + "id": "1664", + "parents": [ + "1660", + "1659" + ] + }, + { + "id": "1665", + "parents": [ + "1659", + "1654" + ] + }, + { + "id": "1666", + "parents": [ + "1665", + "1661", + "1663" + ] + }, + { + "id": "1667", + "parents": [ + "1666", + "1664" + ] + }, + { + "id": "1668", + "parents": [ + "1664", + "1666" + ] + }, + { + "id": "1669", + "parents": [ + "1664", + "1666" + ] + }, + { + "id": "1670", + "parents": [ + "1667", + "1668", + "1669" + ] + }, + { + "id": "1671", + "parents": [ + "1670" + ] + }, + { + "id": "1672", + "parents": [ + "1667", + "1668", + "1669" + ] + }, + { + "id": "1673", + "parents": [ + "1672" + ] + }, + { + "id": "1674", + "parents": [ + "1671", + "1673" + ] + }, + { + "id": "1675", + "parents": [ + "1673", + "1670" + ] + }, + { + "id": "1676", + "parents": [ + "1675", + "1671" + ] + }, + { + "id": "1677", + "parents": [ + "1676", + "1674" + ] + }, + { + "id": "1678", + "parents": [ + "1675", + "1671" + ] + }, + { + "id": "1679", + "parents": [ + "1676" + ] + }, + { + "id": "1680", + "parents": [ + "1677", + "1678" + ] + }, + { + "id": "1681", + "parents": [ + "1680", + "1679" + ] + }, + { + "id": "1682", + "parents": [ + "1680", + "1679" + ] + }, + { + "id": "1683", + "parents": [ + "1682" + ] + }, + { + "id": "1684", + "parents": [ + "1679", + "1680" + ] + }, + { + "id": "1685", + "parents": [ + "1684", + "1681", + "1683" + ] + }, + { + "id": "1686", + "parents": [ + "1685" + ] + }, + { + "id": "1687", + "parents": [ + "1685" + ] + }, + { + "id": "1688", + "parents": [ + "1687" + ] + }, + { + "id": "1689", + "parents": [ + "1685" + ] + }, + { + "id": "1690", + "parents": [ + "1689", + "1688" + ] + }, + { + "id": "1691", + "parents": [ + "1685" + ] + }, + { + "id": "1692", + "parents": [ + "1686", + "1690" + ] + }, + { + "id": "1693", + "parents": [ + "1691", + "1688" + ] + }, + { + "id": "1694", + "parents": [ + "1690", + "1686" + ] + }, + { + "id": "1695", + "parents": [ + "1688", + "1689", + "1691" + ] + }, + { + "id": "1696", + "parents": [ + "1694", + "1693", + "1695" + ] + }, + { + "id": "1697", + "parents": [ + "1693", + "1695", + "1694", + "1692" + ] + }, + { + "id": "1698", + "parents": [ + "1692", + "1696" + ] + }, + { + "id": "1699", + "parents": [ + "1697", + "1698" + ] + }, + { + "id": "1700", + "parents": [ + "1699" + ] + }, + { + "id": "1701", + "parents": [ + "1698", + "1697" + ] + }, + { + "id": "1702", + "parents": [ + "1699" + ] + }, + { + "id": "1703", + "parents": [ + "1701", + "1702", + "1700" + ] + }, + { + "id": "1704", + "parents": [ + "1702", + "1701", + "1700" + ] + }, + { + "id": "1705", + "parents": [ + "1701", + "1702", + "1700" + ] + }, + { + "id": "1706", + "parents": [ + "1703", + "1705", + "1704" + ] + }, + { + "id": "1707", + "parents": [ + "1704", + "1705", + "1703" + ] + }, + { + "id": "1708", + "parents": [ + "1706", + "1707" + ] + }, + { + "id": "1709", + "parents": [ + "1707", + "1706" + ] + }, + { + "id": "1710", + "parents": [ + "1706", + "1707" + ] + }, + { + "id": "1711", + "parents": [ + "1706", + "1707" + ] + }, + { + "id": "1712", + "parents": [ + "1711", + "1708" + ] + }, + { + "id": "1713", + "parents": [ + "1712", + "1709", + "1710" + ] + }, + { + "id": "1714", + "parents": [ + "1713" + ] + }, + { + "id": "1715", + "parents": [ + "1709", + "1710", + "1708", + "1711" + ] + }, + { + "id": "1716", + "parents": [ + "1715" + ] + }, + { + "id": "1717", + "parents": [ + "1709", + "1712", + "1710" + ] + }, + { + "id": "1718", + "parents": [ + "1717", + "1714", + "1716" + ] + }, + { + "id": "1719", + "parents": [ + "1718" + ] + }, + { + "id": "1720", + "parents": [ + "1715" + ] + }, + { + "id": "1721", + "parents": [ + "1718" + ] + }, + { + "id": "1722", + "parents": [ + "1720", + "1719", + "1721" + ] + }, + { + "id": "1723", + "parents": [ + "1719", + "1720" + ] + }, + { + "id": "1724", + "parents": [ + "1720", + "1718" + ] + }, + { + "id": "1725", + "parents": [ + "1724", + "1722", + "1723" + ] + }, + { + "id": "1726", + "parents": [ + "1723", + "1724", + "1722" + ] + }, + { + "id": "1727", + "parents": [ + "1726" + ] + }, + { + "id": "1728", + "parents": [ + "1726", + "1725" + ] + }, + { + "id": "1729", + "parents": [ + "1726", + "1725" + ] + }, + { + "id": "1730", + "parents": [ + "1728", + "1727" + ] + }, + { + "id": "1731", + "parents": [ + "1725", + "1727" + ] + }, + { + "id": "1732", + "parents": [ + "1727", + "1725" + ] + }, + { + "id": "1733", + "parents": [ + "1730", + "1729" + ] + }, + { + "id": "1734", + "parents": [ + "1731", + "1732", + "1733" + ] + }, + { + "id": "1735", + "parents": [ + "1728", + "1727" + ] + }, + { + "id": "1736", + "parents": [ + "1733", + "1735", + "1731", + "1732" + ] + }, + { + "id": "1737", + "parents": [ + "1735", + "1734" + ] + }, + { + "id": "1738", + "parents": [ + "1736", + "1737" + ] + }, + { + "id": "1739", + "parents": [ + "1736", + "1737" + ] + }, + { + "id": "1740", + "parents": [ + "1736" + ] + }, + { + "id": "1741", + "parents": [ + "1740", + "1738" + ] + }, + { + "id": "1742", + "parents": [ + "1739", + "1741" + ] + }, + { + "id": "1743", + "parents": [ + "1742" + ] + }, + { + "id": "1744", + "parents": [ + "1743" + ] + }, + { + "id": "1745", + "parents": [ + "1739", + "1738", + "1740" + ] + }, + { + "id": "1746", + "parents": [ + "1744" + ] + }, + { + "id": "1747", + "parents": [ + "1745", + "1746" + ] + }, + { + "id": "1748", + "parents": [ + "1745", + "1741" + ] + }, + { + "id": "1749", + "parents": [ + "1745", + "1744" + ] + }, + { + "id": "1750", + "parents": [ + "1746", + "1749", + "1748" + ] + }, + { + "id": "1751", + "parents": [ + "1750", + "1747" + ] + }, + { + "id": "1752", + "parents": [ + "1750" + ] + }, + { + "id": "1753", + "parents": [ + "1747", + "1752" + ] + }, + { + "id": "1754", + "parents": [ + "1753", + "1751" + ] + }, + { + "id": "1755", + "parents": [ + "1751", + "1753" + ] + }, + { + "id": "1756", + "parents": [ + "1751", + "1753" + ] + }, + { + "id": "1757", + "parents": [ + "1754", + "1755", + "1756" + ] + }, + { + "id": "1758", + "parents": [ + "1757" + ] + }, + { + "id": "1759", + "parents": [ + "1757" + ] + }, + { + "id": "1760", + "parents": [ + "1755", + "1756", + "1754" + ] + }, + { + "id": "1761", + "parents": [ + "1757", + "1760" + ] + }, + { + "id": "1762", + "parents": [ + "1761", + "1758" + ] + }, + { + "id": "1763", + "parents": [ + "1761", + "1759" + ] + }, + { + "id": "1764", + "parents": [ + "1759", + "1758", + "1760" + ] + }, + { + "id": "1765", + "parents": [ + "1763" + ] + }, + { + "id": "1766", + "parents": [ + "1761", + "1758" + ] + }, + { + "id": "1767", + "parents": [ + "1766", + "1765" + ] + }, + { + "id": "1768", + "parents": [ + "1762", + "1765", + "1766" + ] + }, + { + "id": "1769", + "parents": [ + "1767", + "1768", + "1764" + ] + }, + { + "id": "1770", + "parents": [ + "1767", + "1764", + "1768" + ] + }, + { + "id": "1771", + "parents": [ + "1770", + "1769" + ] + }, + { + "id": "1772", + "parents": [ + "1771" + ] + }, + { + "id": "1773", + "parents": [ + "1769", + "1770" + ] + }, + { + "id": "1774", + "parents": [ + "1772", + "1773" + ] + }, + { + "id": "1775", + "parents": [ + "1773", + "1772" + ] + }, + { + "id": "1776", + "parents": [ + "1775" + ] + }, + { + "id": "1777", + "parents": [ + "1774" + ] + }, + { + "id": "1778", + "parents": [ + "1774" + ] + }, + { + "id": "1779", + "parents": [ + "1778" + ] + }, + { + "id": "1780", + "parents": [ + "1778", + "1775" + ] + }, + { + "id": "1781", + "parents": [ + "1779", + "1776" + ] + }, + { + "id": "1782", + "parents": [ + "1780", + "1781", + "1777" + ] + }, + { + "id": "1783", + "parents": [ + "1782" + ] + }, + { + "id": "1784", + "parents": [ + "1782" + ] + }, + { + "id": "1785", + "parents": [ + "1783", + "1784" + ] + }, + { + "id": "1786", + "parents": [ + "1785" + ] + }, + { + "id": "1787", + "parents": [ + "1786" + ] + }, + { + "id": "1788", + "parents": [ + "1784", + "1783" + ] + }, + { + "id": "1789", + "parents": [ + "1784", + "1783" + ] + }, + { + "id": "1790", + "parents": [ + "1788", + "1786", + "1789" + ] + }, + { + "id": "1791", + "parents": [ + "1788", + "1789", + "1786" + ] + }, + { + "id": "1792", + "parents": [ + "1790", + "1787" + ] + }, + { + "id": "1793", + "parents": [ + "1790", + "1787", + "1791" + ] + }, + { + "id": "1794", + "parents": [ + "1792", + "1793" + ] + }, + { + "id": "1795", + "parents": [ + "1794" + ] + }, + { + "id": "1796", + "parents": [ + "1795" + ] + }, + { + "id": "1797", + "parents": [ + "1793" + ] + }, + { + "id": "1798", + "parents": [ + "1796", + "1797" + ] + }, + { + "id": "1799", + "parents": [ + "1792", + "1793" + ] + }, + { + "id": "1800", + "parents": [ + "1795", + "1797" + ] + }, + { + "id": "1801", + "parents": [ + "1792", + "1797" + ] + }, + { + "id": "1802", + "parents": [ + "1794", + "1797" + ] + }, + { + "id": "1803", + "parents": [ + "1801", + "1799", + "1798", + "1800" + ] + }, + { + "id": "1804", + "parents": [ + "1801", + "1799", + "1794" + ] + }, + { + "id": "1805", + "parents": [ + "1800", + "1804" + ] + }, + { + "id": "1806", + "parents": [ + "1802", + "1803", + "1805" + ] + }, + { + "id": "1807", + "parents": [ + "1805" + ] + }, + { + "id": "1808", + "parents": [ + "1802", + "1803", + "1807" + ] + }, + { + "id": "1809", + "parents": [ + "1807", + "1806" + ] + }, + { + "id": "1810", + "parents": [ + "1809", + "1808" + ] + }, + { + "id": "1811", + "parents": [ + "1809", + "1808" + ] + }, + { + "id": "1812", + "parents": [ + "1808", + "1809" + ] + }, + { + "id": "1813", + "parents": [ + "1812", + "1811" + ] + }, + { + "id": "1814", + "parents": [ + "1810", + "1813" + ] + }, + { + "id": "1815", + "parents": [ + "1811", + "1812" + ] + }, + { + "id": "1816", + "parents": [ + "1813", + "1810" + ] + }, + { + "id": "1817", + "parents": [ + "1814" + ] + }, + { + "id": "1818", + "parents": [ + "1810", + "1815", + "1813" + ] + }, + { + "id": "1819", + "parents": [ + "1817", + "1815" + ] + }, + { + "id": "1820", + "parents": [ + "1815", + "1816" + ] + }, + { + "id": "1821", + "parents": [ + "1818", + "1816" + ] + }, + { + "id": "1822", + "parents": [ + "1818", + "1819", + "1816" + ] + }, + { + "id": "1823", + "parents": [ + "1819", + "1820", + "1818" + ] + }, + { + "id": "1824", + "parents": [ + "1820", + "1819", + "1821" + ] + }, + { + "id": "1825", + "parents": [ + "1824", + "1823", + "1822" + ] + }, + { + "id": "1826", + "parents": [ + "1825" + ] + }, + { + "id": "1827", + "parents": [ + "1821", + "1823", + "1822" + ] + }, + { + "id": "1828", + "parents": [ + "1821", + "1822", + "1820" + ] + }, + { + "id": "1829", + "parents": [ + "1823", + "1828" + ] + }, + { + "id": "1830", + "parents": [ + "1825", + "1827", + "1829" + ] + }, + { + "id": "1831", + "parents": [ + "1830" + ] + }, + { + "id": "1832", + "parents": [ + "1830" + ] + }, + { + "id": "1833", + "parents": [ + "1831", + "1826", + "1832" + ] + }, + { + "id": "1834", + "parents": [ + "1833" + ] + }, + { + "id": "1835", + "parents": [ + "1833" + ] + }, + { + "id": "1836", + "parents": [ + "1832", + "1826", + "1831" + ] + }, + { + "id": "1837", + "parents": [ + "1836" + ] + }, + { + "id": "1838", + "parents": [ + "1836", + "1835" + ] + }, + { + "id": "1839", + "parents": [ + "1833", + "1837" + ] + }, + { + "id": "1840", + "parents": [ + "1833", + "1836" + ] + }, + { + "id": "1841", + "parents": [ + "1839", + "1834", + "1838" + ] + }, + { + "id": "1842", + "parents": [ + "1841", + "1840" + ] + }, + { + "id": "1843", + "parents": [ + "1841", + "1840" + ] + }, + { + "id": "1844", + "parents": [ + "1843" + ] + }, + { + "id": "1845", + "parents": [ + "1843" + ] + }, + { + "id": "1846", + "parents": [ + "1843" + ] + }, + { + "id": "1847", + "parents": [ + "1845", + "1844" + ] + }, + { + "id": "1848", + "parents": [ + "1844", + "1846" + ] + }, + { + "id": "1849", + "parents": [ + "1848", + "1847", + "1842" + ] + }, + { + "id": "1850", + "parents": [ + "1842", + "1848", + "1847" + ] + }, + { + "id": "1851", + "parents": [ + "1847", + "1842", + "1848" + ] + }, + { + "id": "1852", + "parents": [ + "1849", + "1850" + ] + }, + { + "id": "1853", + "parents": [ + "1851", + "1852" + ] + }, + { + "id": "1854", + "parents": [ + "1852" + ] + }, + { + "id": "1855", + "parents": [ + "1851", + "1854" + ] + }, + { + "id": "1856", + "parents": [ + "1853", + "1855" + ] + }, + { + "id": "1857", + "parents": [ + "1855", + "1853" + ] + }, + { + "id": "1858", + "parents": [ + "1857" + ] + }, + { + "id": "1859", + "parents": [ + "1855", + "1853" + ] + }, + { + "id": "1860", + "parents": [ + "1859", + "1856" + ] + }, + { + "id": "1861", + "parents": [ + "1860", + "1858" + ] + }, + { + "id": "1862", + "parents": [ + "1861" + ] + }, + { + "id": "1863", + "parents": [ + "1858", + "1859", + "1856" + ] + }, + { + "id": "1864", + "parents": [ + "1862", + "1863" + ] + }, + { + "id": "1865", + "parents": [ + "1863", + "1861" + ] + }, + { + "id": "1866", + "parents": [ + "1865", + "1864" + ] + }, + { + "id": "1867", + "parents": [ + "1865", + "1864" + ] + }, + { + "id": "1868", + "parents": [ + "1864", + "1865" + ] + }, + { + "id": "1869", + "parents": [ + "1866" + ] + }, + { + "id": "1870", + "parents": [ + "1868", + "1867", + "1869" + ] + }, + { + "id": "1871", + "parents": [ + "1868", + "1867", + "1869" + ] + }, + { + "id": "1872", + "parents": [ + "1871" + ] + }, + { + "id": "1873", + "parents": [ + "1872", + "1870" + ] + }, + { + "id": "1874", + "parents": [ + "1872", + "1870" + ] + }, + { + "id": "1875", + "parents": [ + "1874" + ] + }, + { + "id": "1876", + "parents": [ + "1873" + ] + }, + { + "id": "1877", + "parents": [ + "1873" + ] + }, + { + "id": "1878", + "parents": [ + "1877" + ] + }, + { + "id": "1879", + "parents": [ + "1878", + "1876", + "1875" + ] + }, + { + "id": "1880", + "parents": [ + "1879" + ] + }, + { + "id": "1881", + "parents": [ + "1879" + ] + }, + { + "id": "1882", + "parents": [ + "1880", + "1881" + ] + }, + { + "id": "1883", + "parents": [ + "1881", + "1880" + ] + }, + { + "id": "1884", + "parents": [ + "1882", + "1883" + ] + }, + { + "id": "1885", + "parents": [ + "1880" + ] + }, + { + "id": "1886", + "parents": [ + "1881", + "1880" + ] + }, + { + "id": "1887", + "parents": [ + "1886", + "1884", + "1885" + ] + }, + { + "id": "1888", + "parents": [ + "1885", + "1883" + ] + }, + { + "id": "1889", + "parents": [ + "1888" + ] + }, + { + "id": "1890", + "parents": [ + "1887", + "1889" + ] + }, + { + "id": "1891", + "parents": [ + "1886", + "1888", + "1884" + ] + }, + { + "id": "1892", + "parents": [ + "1891", + "1890" + ] + }, + { + "id": "1893", + "parents": [ + "1892" + ] + }, + { + "id": "1894", + "parents": [ + "1893" + ] + }, + { + "id": "1895", + "parents": [ + "1890", + "1891" + ] + }, + { + "id": "1896", + "parents": [ + "1892", + "1895" + ] + }, + { + "id": "1897", + "parents": [ + "1896", + "1894" + ] + }, + { + "id": "1898", + "parents": [ + "1897" + ] + }, + { + "id": "1899", + "parents": [ + "1898" + ] + }, + { + "id": "1900", + "parents": [ + "1897" + ] + }, + { + "id": "1901", + "parents": [ + "1896", + "1894" + ] + }, + { + "id": "1902", + "parents": [ + "1901", + "1897" + ] + }, + { + "id": "1903", + "parents": [ + "1902", + "1900", + "1899" + ] + }, + { + "id": "1904", + "parents": [ + "1903" + ] + }, + { + "id": "1905", + "parents": [ + "1900", + "1899", + "1902" + ] + }, + { + "id": "1906", + "parents": [ + "1903", + "1905" + ] + }, + { + "id": "1907", + "parents": [ + "1905", + "1903" + ] + }, + { + "id": "1908", + "parents": [ + "1903", + "1905" + ] + }, + { + "id": "1909", + "parents": [ + "1904", + "1908", + "1907", + "1906" + ] + }, + { + "id": "1910", + "parents": [ + "1904", + "1906", + "1908", + "1907" + ] + }, + { + "id": "1911", + "parents": [ + "1909" + ] + }, + { + "id": "1912", + "parents": [ + "1909" + ] + }, + { + "id": "1913", + "parents": [ + "1911" + ] + }, + { + "id": "1914", + "parents": [ + "1910", + "1911" + ] + }, + { + "id": "1915", + "parents": [ + "1911", + "1912", + "1910" + ] + }, + { + "id": "1916", + "parents": [ + "1911", + "1910" + ] + }, + { + "id": "1917", + "parents": [ + "1913", + "1916" + ] + }, + { + "id": "1918", + "parents": [ + "1912", + "1917" + ] + }, + { + "id": "1919", + "parents": [ + "1910", + "1911", + "1912" + ] + }, + { + "id": "1920", + "parents": [ + "1918", + "1914" + ] + }, + { + "id": "1921", + "parents": [ + "1914", + "1915", + "1918" + ] + }, + { + "id": "1922", + "parents": [ + "1919", + "1920", + "1921" + ] + }, + { + "id": "1923", + "parents": [ + "1922" + ] + }, + { + "id": "1924", + "parents": [ + "1923" + ] + }, + { + "id": "1925", + "parents": [ + "1923" + ] + }, + { + "id": "1926", + "parents": [ + "1922" + ] + }, + { + "id": "1927", + "parents": [ + "1923" + ] + }, + { + "id": "1928", + "parents": [ + "1925" + ] + }, + { + "id": "1929", + "parents": [ + "1924", + "1928", + "1927", + "1926" + ] + }, + { + "id": "1930", + "parents": [ + "1929" + ] + }, + { + "id": "1931", + "parents": [ + "1926", + "1927", + "1924", + "1928" + ] + }, + { + "id": "1932", + "parents": [ + "1929", + "1931" + ] + }, + { + "id": "1933", + "parents": [ + "1930", + "1932" + ] + }, + { + "id": "1934", + "parents": [ + "1933" + ] + }, + { + "id": "1935", + "parents": [ + "1933" + ] + }, + { + "id": "1936", + "parents": [ + "1935", + "1934" + ] + }, + { + "id": "1937", + "parents": [ + "1934", + "1935" + ] + }, + { + "id": "1938", + "parents": [ + "1934", + "1935" + ] + }, + { + "id": "1939", + "parents": [ + "1937" + ] + }, + { + "id": "1940", + "parents": [ + "1936", + "1939", + "1938" + ] + }, + { + "id": "1941", + "parents": [ + "1940" + ] + }, + { + "id": "1942", + "parents": [ + "1940" + ] + }, + { + "id": "1943", + "parents": [ + "1940" + ] + }, + { + "id": "1944", + "parents": [ + "1942" + ] + }, + { + "id": "1945", + "parents": [ + "1942", + "1941" + ] + }, + { + "id": "1946", + "parents": [ + "1945", + "1943" + ] + }, + { + "id": "1947", + "parents": [ + "1944", + "1946" + ] + }, + { + "id": "1948", + "parents": [ + "1946", + "1944" + ] + }, + { + "id": "1949", + "parents": [ + "1948" + ] + }, + { + "id": "1950", + "parents": [ + "1948" + ] + }, + { + "id": "1951", + "parents": [ + "1945", + "1944", + "1943" + ] + }, + { + "id": "1952", + "parents": [ + "1944", + "1943", + "1945" + ] + }, + { + "id": "1953", + "parents": [ + "1952", + "1949", + "1951" + ] + }, + { + "id": "1954", + "parents": [ + "1952", + "1949", + "1947", + "1951", + "1950" + ] + }, + { + "id": "1955", + "parents": [ + "1954", + "1953" + ] + }, + { + "id": "1956", + "parents": [ + "1953", + "1954" + ] + }, + { + "id": "1957", + "parents": [ + "1953", + "1954" + ] + }, + { + "id": "1958", + "parents": [ + "1956" + ] + }, + { + "id": "1959", + "parents": [ + "1955", + "1957", + "1956" + ] + }, + { + "id": "1960", + "parents": [ + "1957", + "1956", + "1955" + ] + }, + { + "id": "1961", + "parents": [ + "1958", + "1960" + ] + }, + { + "id": "1962", + "parents": [ + "1959", + "1961" + ] + }, + { + "id": "1963", + "parents": [ + "1959", + "1961" + ] + }, + { + "id": "1964", + "parents": [ + "1963" + ] + }, + { + "id": "1965", + "parents": [ + "1959", + "1961" + ] + }, + { + "id": "1966", + "parents": [ + "1965", + "1962", + "1964" + ] + }, + { + "id": "1967", + "parents": [ + "1962", + "1963", + "1965" + ] + }, + { + "id": "1968", + "parents": [ + "1964", + "1965", + "1962" + ] + }, + { + "id": "1969", + "parents": [ + "1967", + "1966", + "1968" + ] + }, + { + "id": "1970", + "parents": [ + "1969" + ] + }, + { + "id": "1971", + "parents": [ + "1964", + "1967" + ] + }, + { + "id": "1972", + "parents": [ + "1969", + "1971" + ] + }, + { + "id": "1973", + "parents": [ + "1970", + "1971" + ] + }, + { + "id": "1974", + "parents": [ + "1972", + "1973" + ] + }, + { + "id": "1975", + "parents": [ + "1971", + "1970" + ] + }, + { + "id": "1976", + "parents": [ + "1973", + "1972" + ] + }, + { + "id": "1977", + "parents": [ + "1975", + "1976" + ] + }, + { + "id": "1978", + "parents": [ + "1977", + "1974" + ] + }, + { + "id": "1979", + "parents": [ + "1977", + "1974" + ] + }, + { + "id": "1980", + "parents": [ + "1978", + "1979" + ] + }, + { + "id": "1981", + "parents": [ + "1977", + "1974" + ] + }, + { + "id": "1982", + "parents": [ + "1979", + "1981" + ] + }, + { + "id": "1983", + "parents": [ + "1982", + "1980" + ] + }, + { + "id": "1984", + "parents": [ + "1982", + "1980" + ] + }, + { + "id": "1985", + "parents": [ + "1981", + "1978", + "1979" + ] + }, + { + "id": "1986", + "parents": [ + "1984", + "1983", + "1985" + ] + }, + { + "id": "1987", + "parents": [ + "1986" + ] + }, + { + "id": "1988", + "parents": [ + "1983", + "1985", + "1984" + ] + }, + { + "id": "1989", + "parents": [ + "1988", + "1986" + ] + }, + { + "id": "1990", + "parents": [ + "1987" + ] + }, + { + "id": "1991", + "parents": [ + "1989", + "1990" + ] + }, + { + "id": "1992", + "parents": [ + "1989", + "1990" + ] + }, + { + "id": "1993", + "parents": [ + "1991" + ] + }, + { + "id": "1994", + "parents": [ + "1989", + "1990" + ] + }, + { + "id": "1995", + "parents": [ + "1992", + "1991" + ] + }, + { + "id": "1996", + "parents": [ + "1993" + ] + }, + { + "id": "1997", + "parents": [ + "1995", + "1996", + "1994" + ] + }, + { + "id": "1998", + "parents": [ + "1997" + ] + }, + { + "id": "1999", + "parents": [ + "1997" + ] + }, + { + "id": "2000", + "parents": [ + "1999" + ] + }, + { + "id": "2001", + "parents": [ + "2000" + ] + }, + { + "id": "2002", + "parents": [ + "1998", + "2000" + ] + }, + { + "id": "2003", + "parents": [ + "2002", + "2001" + ] + }, + { + "id": "2004", + "parents": [ + "2003" + ] + }, + { + "id": "2005", + "parents": [ + "2001", + "2002" + ] + }, + { + "id": "2006", + "parents": [ + "2005" + ] + }, + { + "id": "2007", + "parents": [ + "2006", + "2004" + ] + }, + { + "id": "2008", + "parents": [ + "2003", + "2006" + ] + }, + { + "id": "2009", + "parents": [ + "2006", + "2003" + ] + }, + { + "id": "2010", + "parents": [ + "2007", + "2008", + "2009" + ] + }, + { + "id": "2011", + "parents": [ + "2008", + "2009", + "2007" + ] + }, + { + "id": "2012", + "parents": [ + "2010", + "2011" + ] + }, + { + "id": "2013", + "parents": [ + "2012" + ] + }, + { + "id": "2014", + "parents": [ + "2010", + "2011" + ] + }, + { + "id": "2015", + "parents": [ + "2011", + "2010" + ] + }, + { + "id": "2016", + "parents": [ + "2011", + "2010" + ] + }, + { + "id": "2017", + "parents": [ + "2015", + "2016", + "2014", + "2013" + ] + }, + { + "id": "2018", + "parents": [ + "2017" + ] + }, + { + "id": "2019", + "parents": [ + "2018" + ] + }, + { + "id": "2020", + "parents": [ + "2018" + ] + }, + { + "id": "2021", + "parents": [ + "2017" + ] + }, + { + "id": "2022", + "parents": [ + "2013", + "2014", + "2015", + "2016" + ] + }, + { + "id": "2023", + "parents": [ + "2022", + "2019", + "2020" + ] + }, + { + "id": "2024", + "parents": [ + "2023", + "2021" + ] + }, + { + "id": "2025", + "parents": [ + "2024" + ] + } + ] +} \ No newline at end of file From 6b1e691a578bc0657c98cd124e72567c803f6968 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 17 Dec 2020 15:48:55 +0200 Subject: [PATCH 138/351] Add GitHub actions in preperation for deprecating Jenkins (#1164) * Add a test script * add gh action for build and test * added all the test * Change github workflow to use the new test script * Change the docker file to use the new test script * Add doc comment for ProtocolError.Unwrap() * Use another github action to increase windows page size * Run the action after any edit to the PR metadata/base * Change go version from 1.15 to 1.14 * Rename test.sh to build_and_test.sh Co-authored-by: Isabella Liu --- .github/workflows/SetPageFileSize.ps1 | 196 ++++++++++++++++++ .github/workflows/go.yml | 51 +++++ app/protocol/protocolerrors/protocolerrors.go | 1 + build_and_test.sh | 26 +++ docker/Dockerfile | 14 +- 5 files changed, 275 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/SetPageFileSize.ps1 create mode 100644 .github/workflows/go.yml create mode 100755 build_and_test.sh diff --git a/.github/workflows/SetPageFileSize.ps1 b/.github/workflows/SetPageFileSize.ps1 new file mode 100644 index 000000000..b25eb5cff --- /dev/null +++ b/.github/workflows/SetPageFileSize.ps1 @@ -0,0 +1,196 @@ +<# +# MIT License (MIT) Copyright (c) 2020 Maxim Lobanov and contributors +# Source: https://github.com/al-cheb/configure-pagefile-action/blob/master/scripts/SetPageFileSize.ps1 +.SYNOPSIS + Configure Pagefile on Windows machine +.NOTES + Author: Aleksandr Chebotov + +.EXAMPLE + SetPageFileSize.ps1 -MinimumSize 4GB -MaximumSize 8GB -DiskRoot "D:" +#> + +param( + [System.UInt64] $MinimumSize = 8gb , + [System.UInt64] $MaximumSize = 8gb , + [System.String] $DiskRoot = "D:" +) + +# https://referencesource.microsoft.com/#System.IdentityModel/System/IdentityModel/NativeMethods.cs,619688d876febbe1 +# https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/mm/modwrite/create.htm +# https://referencesource.microsoft.com/#mscorlib/microsoft/win32/safehandles/safefilehandle.cs,9b08210f3be75520 +# https://referencesource.microsoft.com/#mscorlib/system/security/principal/tokenaccesslevels.cs,6eda91f498a38586 +# https://www.autoitscript.com/forum/topic/117993-api-ntcreatepagingfile/ + +$source = @' +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Text; +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; + +namespace Util +{ + class NativeMethods + { + [StructLayout(LayoutKind.Sequential)] + internal struct LUID + { + internal uint LowPart; + internal uint HighPart; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct LUID_AND_ATTRIBUTES + { + internal LUID Luid; + internal uint Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TOKEN_PRIVILEGE + { + internal uint PrivilegeCount; + internal LUID_AND_ATTRIBUTES Privilege; + + internal static readonly uint Size = (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGE)); + } + + [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct UNICODE_STRING + { + internal UInt16 length; + internal UInt16 maximumLength; + internal string buffer; + } + + [DllImport("kernel32.dll", SetLastError=true)] + internal static extern IntPtr LocalFree(IntPtr handle); + + [DllImport("advapi32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)] + internal static extern bool LookupPrivilegeValueW( + [In] string lpSystemName, + [In] string lpName, + [Out] out LUID luid + ); + + [DllImport("advapi32.dll", SetLastError = true, PreserveSig = false)] + internal static extern bool AdjustTokenPrivileges( + [In] SafeCloseHandle tokenHandle, + [In] bool disableAllPrivileges, + [In] ref TOKEN_PRIVILEGE newState, + [In] uint bufferLength, + [Out] out TOKEN_PRIVILEGE previousState, + [Out] out uint returnLength + ); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = false)] + internal static extern bool OpenProcessToken( + [In] IntPtr processToken, + [In] int desiredAccess, + [Out] out SafeCloseHandle tokenHandle + ); + + [DllImport("ntdll.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)] + internal static extern Int32 NtCreatePagingFile( + [In] ref UNICODE_STRING pageFileName, + [In] ref Int64 minimumSize, + [In] ref Int64 maximumSize, + [In] UInt32 flags + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint QueryDosDeviceW( + string lpDeviceName, + StringBuilder lpTargetPath, + int ucchMax + ); + } + + public sealed class SafeCloseHandle: SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] + internal extern static bool CloseHandle(IntPtr handle); + + private SafeCloseHandle() : base(true) + { + } + + public SafeCloseHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) + { + SetHandle(preexistingHandle); + } + + override protected bool ReleaseHandle() + { + return CloseHandle(handle); + } + } + + public class PageFile + { + public static void SetPageFileSize(long minimumValue, long maximumValue, string lpDeviceName) + { + SetPageFilePrivilege(); + StringBuilder lpTargetPath = new StringBuilder(260); + + UInt32 resultQueryDosDevice = NativeMethods.QueryDosDeviceW(lpDeviceName, lpTargetPath, lpTargetPath.Capacity); + if (resultQueryDosDevice == 0) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + string pageFilePath = lpTargetPath.ToString() + "\\pagefile.sys"; + + NativeMethods.UNICODE_STRING pageFileName = new NativeMethods.UNICODE_STRING + { + length = (ushort)(pageFilePath.Length * 2), + maximumLength = (ushort)(2 * (pageFilePath.Length + 1)), + buffer = pageFilePath + }; + + Int32 resultNtCreatePagingFile = NativeMethods.NtCreatePagingFile(ref pageFileName, ref minimumValue, ref maximumValue, 0); + if (resultNtCreatePagingFile != 0) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + + Console.WriteLine("PageFile: {0} / {1} bytes for {2}", minimumValue, maximumValue, pageFilePath); + } + + static void SetPageFilePrivilege() + { + const int SE_PRIVILEGE_ENABLED = 0x00000002; + const int AdjustPrivileges = 0x00000020; + const int Query = 0x00000008; + + NativeMethods.LUID luid; + NativeMethods.LookupPrivilegeValueW(null, "SeCreatePagefilePrivilege", out luid); + + SafeCloseHandle hToken; + NativeMethods.OpenProcessToken( + Process.GetCurrentProcess().Handle, + AdjustPrivileges | Query, + out hToken + ); + + NativeMethods.TOKEN_PRIVILEGE previousState; + NativeMethods.TOKEN_PRIVILEGE newState; + uint previousSize = 0; + newState.PrivilegeCount = 1; + newState.Privilege.Luid = luid; + newState.Privilege.Attributes = SE_PRIVILEGE_ENABLED; + + NativeMethods.AdjustTokenPrivileges(hToken, false, ref newState, NativeMethods.TOKEN_PRIVILEGE.Size, out previousState, out previousSize); + } + } +} +'@ + +Add-Type -TypeDefinition $source + +# Set SetPageFileSize +[Util.PageFile]::SetPageFileSize($minimumSize, $maximumSize, $diskRoot) \ No newline at end of file diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 000000000..97c24090f --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,51 @@ +name: Go + +on: + push: + pull_request: + # edtited - "title, body, or the base branch of the PR is modified" + # synchronize - "commit(s) pushed to the pull request" + types: [opened, synchronize, edited, reopened] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-16.04, windows-2019, macos-10.15 ] + name: Testing on on ${{ matrix.os }} + steps: + + - name: Fix windows CRLF + run: git config --global core.autocrlf false + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + # We need to increase the page size because the tests run out of memory on github CI windows. + # Use the powershell script from this github action: https://github.com/al-cheb/configure-pagefile-action/blob/master/scripts/SetPageFileSize.ps1 + # MIT License (MIT) Copyright (c) 2020 Maxim Lobanov and contributors + - name: Increase page size on windows + if: runner.os == 'Windows' + shell: powershell + run: powershell -command .\.github\workflows\SetPageFileSize.ps1 + + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: 1.14 + + + # Source: https://github.com/actions/cache/blob/main/examples.md#go---modules + - name: Go Cache + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Test + shell: bash + run: ./build_and_test.sh diff --git a/app/protocol/protocolerrors/protocolerrors.go b/app/protocol/protocolerrors/protocolerrors.go index 0c42934cb..5c87a1f85 100644 --- a/app/protocol/protocolerrors/protocolerrors.go +++ b/app/protocol/protocolerrors/protocolerrors.go @@ -16,6 +16,7 @@ func (e *ProtocolError) Error() string { return e.Cause.Error() } +// Unwrap returns the cause of ProtocolError, to be used with `errors.Unwrap()` func (e *ProtocolError) Unwrap() error { return e.Cause } diff --git a/build_and_test.sh b/build_and_test.sh new file mode 100755 index 000000000..1f8fbc0a4 --- /dev/null +++ b/build_and_test.sh @@ -0,0 +1,26 @@ +#!/bin/sh -ex + +FLAGS=$@ + +go version + +go get $FLAGS -t -d ./... +# This is to bypass a go bug: https://github.com/golang/go/issues/27643 +GO111MODULE=off go get $FLAGS golang.org/x/lint/golint \ + honnef.co/go/tools/cmd/staticcheck + +test -z "$(go fmt ./...)" + +golint -set_exit_status ./... + +staticcheck -checks "\ + SA4006,SA4008,SA4009,SA4010,SA5003,SA1004,SA1014,SA1021,SA1023,SA1024,SA1025,SA1026,SA1027,SA1028,SA2000,SA2001, \ + SA2003,SA4000,SA4001,SA4003,SA4004,SA4011,SA4012,SA4013,SA4014,SA4015,SA4016,SA4017,SA4018,SA4019,SA4020,SA4021, \ + SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002, \ + SA9003,SA9004,SA9005,SA9006,ST1019" ./... + +go vet $FLAGS ./... + +go build $FLAGS -o kaspad . + +go test $FLAGS ./... \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 11a1098c0..ab64a07e9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,21 +16,9 @@ RUN go get -u golang.org/x/lint/golint \ COPY go.mod . COPY go.sum . -RUN go mod download - COPY . . -RUN GOFMT_RESULT=`go fmt ./...`; echo $GOFMT_RESULT; test -z "$GOFMT_RESULT" -RUN go vet ./... -RUN golint -set_exit_status ./... -# RUN aligncheck ./... -# RUN structcheck -e ./... -# RUN varcheck -e ./... -RUN staticcheck -checks "SA4006,SA4008,SA4009,SA4010,SA5003,SA1004,SA1014,SA1021,SA1023,SA1024,SA1025,SA1026,SA1027,SA1028,SA2000,SA2001,SA2003,SA4000,SA4001,SA4003,SA4004,SA4011,SA4012,SA4013,SA4014,SA4015,SA4016,SA4017,SA4018,SA4019,SA4020,SA4021,SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002,SA9003,SA9004,SA9005,SA9006,ST1019" ./... -RUN GOOS=linux go build -a -installsuffix cgo -o kaspad . - -# Remove the line below and uncomment the line after it for testing with coverage -RUN go test ./... +RUN ./build_and_test.sh # --- multistage docker build: stage #2: runtime image FROM alpine From bd5f4e8c6a2c7b2cd332004778f61ad409636724 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 17 Dec 2020 17:57:51 +0200 Subject: [PATCH 139/351] Pruning fixes (#1243) * Pruning related fixes * Rename setBlockStatus->setBlockStatusAfterBlockValidation * Rename StatusValid->StatusUTXOValid * Add comment * Fix typo * Rename hasValidatedOnlyHeader->hasValidatedHeader * Rename checkBlockBodiesExist->checkParentBlockBodiesExist * Add comments and logs * Adding logs * Add logs and assert * Add comment * Fix typo * Fix log --- domain/consensus/consensus_test.go | 4 +- domain/consensus/finality_test.go | 20 +-- .../model/externalapi/blockstatus.go | 6 +- .../interface_processes_blockvalidator.go | 2 +- .../blockprocessor/blockprocessor.go | 2 +- .../blockprocessor/validateandinsertblock.go | 115 +++++++++++++----- .../validateandinsertpruningpoint.go | 17 ++- .../processes/blockprocessor/validateblock.go | 24 ++-- .../blockvalidator/block_body_in_context.go | 62 +++++++++- .../processes/blockvalidator/proof_of_work.go | 30 +---- .../add_block_to_virtual.go | 2 +- .../calculate_past_utxo.go | 4 +- .../pick_virtual_parents.go | 2 +- .../resolve_block_status.go | 6 +- .../resolve_block_status_test.go | 16 +-- .../update_pruning_utxo_set.go | 60 +++++---- 16 files changed, 243 insertions(+), 129 deletions(-) diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index d22a6df3e..d262ddb6f 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -62,8 +62,8 @@ func TestConsensus_GetBlockInfo(t *testing.T) { if !info.Exists { t.Fatal("The block is missing") } - if info.BlockStatus != externalapi.StatusValid { - t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus) + if info.BlockStatus != externalapi.StatusUTXOValid { + t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusUTXOValid, info.BlockStatus) } }) diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index d9ffc7f41..0c5aa3189 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -55,9 +55,9 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Block #%d failed to get info: %+v", i, err) } - if blockInfo.BlockStatus != externalapi.StatusValid { + if blockInfo.BlockStatus != externalapi.StatusUTXOValid { t.Fatalf("Block #%d in main chain expected to have status '%s', but got '%s'", - i, externalapi.StatusValid, blockInfo.BlockStatus) + i, externalapi.StatusUTXOValid, blockInfo.BlockStatus) } } @@ -99,9 +99,9 @@ func TestFinality(t *testing.T) { } else if !blockInfo.Exists { t.Fatalf("TestFinality: Failed getting block info, doesn't exists") } - if blockInfo.BlockStatus != externalapi.StatusValid { + if blockInfo.BlockStatus != externalapi.StatusUTXOValid { t.Fatalf("TestFinality: Overtaking block in side-chain expected to have status '%s', but got '%s'", - externalapi.StatusValid, blockInfo.BlockStatus) + externalapi.StatusUTXOValid, blockInfo.BlockStatus) } selectedTip, err := consensus.GetVirtualSelectedParent() if err != nil { @@ -387,14 +387,14 @@ func TestBoundedMergeDepth(t *testing.T) { } // Lets validate the status of all the interesting blocks - if getStatus(consensusReal, pointAtBlueKosherizing) != externalapi.StatusValid { - t.Fatalf("TestBoundedMergeDepth: pointAtBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, pointAtBlueKosherizing)) + if getStatus(consensusReal, pointAtBlueKosherizing) != externalapi.StatusUTXOValid { + t.Fatalf("TestBoundedMergeDepth: pointAtBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusUTXOValid, getStatus(consensusReal, pointAtBlueKosherizing)) } if getStatus(consensusReal, pointAtRedKosherizing) != externalapi.StatusInvalid { t.Fatalf("TestBoundedMergeDepth: pointAtRedKosherizing expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, pointAtRedKosherizing)) } - if getStatus(consensusReal, transitiveBlueKosherizing) != externalapi.StatusValid { - t.Fatalf("TestBoundedMergeDepth: transitiveBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, transitiveBlueKosherizing)) + if getStatus(consensusReal, transitiveBlueKosherizing) != externalapi.StatusUTXOValid { + t.Fatalf("TestBoundedMergeDepth: transitiveBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusUTXOValid, getStatus(consensusReal, transitiveBlueKosherizing)) } if getStatus(consensusReal, mergeDepthViolatingBlockBottom) != externalapi.StatusInvalid { t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingBlockBottom expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingBlockBottom)) @@ -412,8 +412,8 @@ func TestBoundedMergeDepth(t *testing.T) { } } for i, b := range selectedChain { - if getStatus(consensusReal, b) != externalapi.StatusValid { - t.Fatalf("selectedChain[%d] expected status '%s' but got '%s'", i, externalapi.StatusValid, getStatus(consensusReal, b)) + if getStatus(consensusReal, b) != externalapi.StatusUTXOValid { + t.Fatalf("selectedChain[%d] expected status '%s' but got '%s'", i, externalapi.StatusUTXOValid, getStatus(consensusReal, b)) } } }) diff --git a/domain/consensus/model/externalapi/blockstatus.go b/domain/consensus/model/externalapi/blockstatus.go index 8fc15cf3f..2c2fd408a 100644 --- a/domain/consensus/model/externalapi/blockstatus.go +++ b/domain/consensus/model/externalapi/blockstatus.go @@ -12,8 +12,8 @@ const ( // StatusInvalid indicates that the block is invalid. StatusInvalid BlockStatus = iota - // StatusValid indicates that the block has been fully validated. - StatusValid + // StatusUTXOValid indicates the block is valid from any UTXO related aspects and has passed all the other validations as well. + StatusUTXOValid // StatusUTXOPendingVerification indicates that the block is pending verification against its past UTXO-Set, either // because it was not yet verified since the block was never in the selected parent chain, or if the @@ -29,7 +29,7 @@ const ( var blockStatusStrings = map[BlockStatus]string{ StatusInvalid: "Invalid", - StatusValid: "Valid", + StatusUTXOValid: "Valid", StatusUTXOPendingVerification: "UTXOPendingVerification", StatusDisqualifiedFromChain: "DisqualifiedFromChain", StatusHeaderOnly: "HeaderOnly", diff --git a/domain/consensus/model/interface_processes_blockvalidator.go b/domain/consensus/model/interface_processes_blockvalidator.go index 12dde50d0..c7250cc0b 100644 --- a/domain/consensus/model/interface_processes_blockvalidator.go +++ b/domain/consensus/model/interface_processes_blockvalidator.go @@ -10,6 +10,6 @@ type BlockValidator interface { ValidateHeaderInIsolation(blockHash *externalapi.DomainHash) error ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error ValidateHeaderInContext(blockHash *externalapi.DomainHash) error - ValidateBodyInContext(blockHash *externalapi.DomainHash) error + ValidateBodyInContext(blockHash *externalapi.DomainHash, isPruningPoint bool) error ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error } diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index e1a6c8548..cb007a39a 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -126,7 +126,7 @@ func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertBlock") defer onEnd() - return bp.validateAndInsertBlock(block) + return bp.validateAndInsertBlock(block, false) } func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 56865f462..63db91e55 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -11,19 +11,59 @@ import ( "github.com/pkg/errors" ) -func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) { +func (bp *blockProcessor) setBlockStatusAfterBlockValidation(block *externalapi.DomainBlock, isPruningPoint bool) error { + blockHash := consensushashing.BlockHash(block) + + exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash) + if err != nil { + return err + } + if exists { + status, err := bp.blockStatusStore.Get(bp.databaseContext, blockHash) + if err != nil { + return err + } + + if status == externalapi.StatusUTXOValid { + // A block cannot have status StatusUTXOValid just after finishing bp.validateBlock, because + // if it's the case it should have been rejected as duplicate block. + // The only exception is the pruning point because its status is manually set before inserting + // the block. + if !isPruningPoint { + return errors.Errorf("block %s that is not the pruning point is not expected to be valid "+ + "before adding to to the consensus state manager", blockHash) + } + log.Tracef("Block %s is the pruning point and has status %s, so leaving its status untouched", + blockHash, status) + return nil + } + } + + isHeaderOnlyBlock := isHeaderOnlyBlock(block) + if isHeaderOnlyBlock { + log.Tracef("Block %s is a header-only block so setting its status as %s", + blockHash, externalapi.StatusHeaderOnly) + bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) + } else { + log.Tracef("Block %s has body so setting its status as %s", + blockHash, externalapi.StatusUTXOPendingVerification) + bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) + } + + return nil +} + +func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, isPruningPoint bool) (*externalapi.BlockInsertionResult, error) { blockHash := consensushashing.HeaderHash(block.Header) - err := bp.validateBlock(block) + err := bp.validateBlock(block, isPruningPoint) if err != nil { bp.discardAllChanges() return nil, err } - isHeaderOnlyBlock := isHeaderOnlyBlock(block) - if isHeaderOnlyBlock { - bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) - } else { - bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) + err = bp.setBlockStatusAfterBlockValidation(block, isPruningPoint) + if err != nil { + return nil, err } // Block validations passed, save whatever DAG data was @@ -34,8 +74,8 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } var oldHeadersSelectedTip *externalapi.DomainHash - isGenesis := *blockHash != *bp.genesisHash - if isGenesis { + isGenesis := *blockHash == *bp.genesisHash + if !isGenesis { var err error oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext) if err != nil { @@ -49,15 +89,21 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) } var selectedParentChainChanges *externalapi.SelectedParentChainChanges + isHeaderOnlyBlock := isHeaderOnlyBlock(block) if !isHeaderOnlyBlock { - // Attempt to add the block to the virtual - selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash) - if err != nil { - return nil, err + // There's no need to update the consensus state manager when + // processing the pruning point since it was already handled + // in consensusStateManager.UpdatePruningPoint + if !isPruningPoint { + // Attempt to add the block to the virtual + selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash) + if err != nil { + return nil, err + } } } - if isGenesis { + if !isGenesis { err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) if err != nil { return nil, err @@ -137,14 +183,22 @@ func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error return errors.Wrapf(ruleerrors.ErrKnownInvalid, "block %s is a known invalid block", hash) } - isBlockBodyAfterBlockHeader := !isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly - if !isBlockBodyAfterBlockHeader { - return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash) - } - - isDuplicateHeader := isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly - if isDuplicateHeader { - return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash) + if !isHeaderOnlyBlock { + hasBlock, err := bp.blockStore.HasBlock(bp.databaseContext, hash) + if err != nil { + return err + } + if hasBlock { + return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash) + } + } else { + hasHeader, err := bp.blockHeaderStore.HasBlockHeader(bp.databaseContext, hash) + if err != nil { + return err + } + if hasHeader { + return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s header already exists", hash) + } } return nil @@ -153,12 +207,12 @@ func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error { blockHash := consensushashing.BlockHash(block) - hasValidatedOnlyHeader, err := bp.hasValidatedOnlyHeader(blockHash) + hasValidatedHeader, err := bp.hasValidatedHeader(blockHash) if err != nil { return err } - if hasValidatedOnlyHeader { + if hasValidatedHeader { log.Debugf("Block %s header was already validated, so skip the rest of validatePreProofOfWork", blockHash) return nil } @@ -170,7 +224,7 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) return nil } -func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock) error { +func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, isPruningPoint bool) error { blockHash := consensushashing.BlockHash(block) isHeaderOnlyBlock := isHeaderOnlyBlock(block) @@ -182,7 +236,7 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock } } - hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash) + hasValidatedHeader, err := bp.hasValidatedHeader(blockHash) if err != nil { return err } @@ -195,7 +249,7 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock } if !isHeaderOnlyBlock { - err = bp.blockValidator.ValidateBodyInContext(blockHash) + err = bp.blockValidator.ValidateBodyInContext(blockHash, isPruningPoint) if err != nil { return err } @@ -206,7 +260,10 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock return nil } -func (bp *blockProcessor) hasValidatedOnlyHeader(blockHash *externalapi.DomainHash) (bool, error) { +// hasValidatedHeader returns whether the block header was validated. It returns +// true in any case the block header was validated, whether it was validated as a +// header-only block or as a block with body. +func (bp *blockProcessor) hasValidatedHeader(blockHash *externalapi.DomainHash) (bool, error) { exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash) if err != nil { return false, err @@ -221,7 +278,7 @@ func (bp *blockProcessor) hasValidatedOnlyHeader(blockHash *externalapi.DomainHa return false, err } - return status == externalapi.StatusHeaderOnly, nil + return status != externalapi.StatusInvalid, nil } func (bp *blockProcessor) discardAllChanges() { diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go index 902c8ec38..c2e60cc01 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go @@ -24,16 +24,27 @@ func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externa // 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) + err = bp.validateBlockAndDiscardChanges(newPruningPoint, true) if err != nil { return err } + log.Infof("Updating consensus state manager according to the new pruning point %s", newPruningPointHash) err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet) if err != nil { return err } - _, err = bp.ValidateAndInsertBlock(newPruningPoint) - return err + log.Infof("Inserting the new pruning point %s", newPruningPointHash) + _, err = bp.validateAndInsertBlock(newPruningPoint, true) + if err != nil { + if errors.As(err, &ruleerrors.RuleError{}) { + // This should never happen because we already validated the block with bp.validateBlockAndDiscardChanges. + // We use Errorf so it won't be identified later on to be a rule error and will eventually cause + // the program to panic. + return errors.Errorf("validateAndInsertBlock returned unexpected rule error while processing "+ + "the pruning point: %+v", err) + } + } + return nil } diff --git a/domain/consensus/processes/blockprocessor/validateblock.go b/domain/consensus/processes/blockprocessor/validateblock.go index f7bba7966..405c8e503 100644 --- a/domain/consensus/processes/blockprocessor/validateblock.go +++ b/domain/consensus/processes/blockprocessor/validateblock.go @@ -7,12 +7,12 @@ import ( "github.com/pkg/errors" ) -func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock) error { +func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock, isPruningPoint bool) error { defer bp.discardAllChanges() - return bp.validateBlock(block) + return bp.validateBlock(block, isPruningPoint) } -func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error { +func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, isPruningPoint bool) error { blockHash := consensushashing.HeaderHash(block.Header) log.Debugf("Validating block %s", blockHash) @@ -21,7 +21,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error { return err } - hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash) + hasValidatedHeader, err := bp.hasValidatedHeader(blockHash) if err != nil { return err } @@ -50,15 +50,19 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error { // If in-context validations fail, discard all changes and store the // block with StatusInvalid. - err = bp.validatePostProofOfWork(block) + err = bp.validatePostProofOfWork(block, isPruningPoint) 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 + // If we got ErrMissingParents the block shouldn't be considered as invalid + // because it could be added later on when its parents are present. + if !errors.As(err, &ruleerrors.ErrMissingParents{}) { + hash := consensushashing.BlockHash(block) + bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid) + commitErr := bp.commitAllChanges() + if commitErr != nil { + return commitErr + } } } return err diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index dd6fc4540..d16421e93 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -13,11 +13,69 @@ import ( // ValidateBodyInContext validates block bodies in the context of the current // consensus state -func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash) error { +func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash, isPruningPoint bool) error { onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext") defer onEnd() - return v.checkBlockTransactionsFinalized(blockHash) + err := v.checkBlockTransactionsFinalized(blockHash) + if err != nil { + return err + } + + if !isPruningPoint { + err := v.checkParentBlockBodiesExist(blockHash) + if err != nil { + return err + } + } + return nil +} + +func (v *blockValidator) checkParentBlockBodiesExist(blockHash *externalapi.DomainHash) error { + missingParentHashes := []*externalapi.DomainHash{} + header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash) + if err != nil { + return err + } + for _, parent := range header.ParentHashes { + hasBlock, err := v.blockStore.HasBlock(v.databaseContext, parent) + if err != nil { + return err + } + + if !hasBlock { + 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 a block parent is in the past of the pruning point + // it means its body will never be used, so it's ok if + // it's missing. + // This will usually happen during IBD when getting the blocks + // in the pruning point anticone. + if isInPastOfPruningPoint { + log.Debugf("Block %s parent %s is missing a body, but is in the past of the pruning point", + blockHash, parent) + continue + } + + log.Debugf("Block %s parent %s is missing a body", blockHash, parent) + + missingParentHashes = append(missingParentHashes, parent) + } + } + + if len(missingParentHashes) > 0 { + return ruleerrors.NewErrMissingParents(missingParentHashes) + } + + return nil } func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.DomainHash) error { diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index ffb38ba8a..08b4548f9 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -19,7 +19,7 @@ func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficult return err } - err = v.checkParentsExist(blockHash, header) + err = v.checkParentHeadersExist(header) if err != nil { return err } @@ -103,14 +103,8 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) return nil } -func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error { +func (v *blockValidator) checkParentHeadersExist(header *externalapi.DomainBlockHeader) error { missingParentHashes := []*externalapi.DomainHash{} - - hasBlockBody, err := v.blockStore.HasBlock(v.databaseContext, blockHash) - if err != nil { - return err - } - for _, parent := range header.ParentHashes { parentHeaderExists, err := v.blockHeaderStore.HasBlockHeader(v.databaseContext, parent) if err != nil { @@ -129,26 +123,6 @@ func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, he 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) - } - } } if len(missingParentHashes) > 0 { diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 58dcec929..aab8210ae 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -5,7 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// AddBlockToVirtual submits the given block to be added to the +// AddBlock 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) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 1e3dbb1c2..c092a9b51 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -256,10 +256,10 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external if err != nil { return nil, err } - if blockStatus != externalapi.StatusValid { + if blockStatus != externalapi.StatusUTXOValid { return nil, errors.Errorf( "block %s, has status '%s', and therefore can't restore it's UTXO set. Only blocks with status '%s' can be restored.", - blockHash, blockStatus, externalapi.StatusValid) + blockHash, blockStatus, externalapi.StatusUTXOValid) } log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index c85f03892..103da8975 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -88,7 +88,7 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( if err != nil { return nil, err } - if selectedParentCandidateStatus == externalapi.StatusValid { + if selectedParentCandidateStatus == externalapi.StatusUTXOValid { log.Tracef("Block %s is valid. Returning it as the selected parent", selectedParentCandidate) return selectedParentCandidate, nil } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 2aa6156b0..6f28d7312 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -72,8 +72,8 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1] if *lastUnverifiedBlock == *csm.genesisHash { log.Tracef("the most recent unverified block is the genesis block, "+ - "which by definition has status: %s", externalapi.StatusValid) - return externalapi.StatusValid, nil + "which by definition has status: %s", externalapi.StatusUTXOValid) + return externalapi.StatusUTXOValid, nil } lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, lastUnverifiedBlock) if err != nil { @@ -164,7 +164,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap return 0, err } - return externalapi.StatusValid, nil + return externalapi.StatusUTXOValid, nil } func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssignDiffChild( diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index f825e8025..52dc97612 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -70,8 +70,8 @@ func TestDoubleSpends(t *testing.T) { if err != nil { t.Fatalf("Error getting status of goodBlock1: %+v", err) } - if goodBlock1Status != externalapi.StatusValid { - t.Fatalf("GoodBlock1 status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock1Status) + if goodBlock1Status != externalapi.StatusUTXOValid { + t.Fatalf("GoodBlock1 status expected to be '%s', but is '%s'", externalapi.StatusUTXOValid, goodBlock1Status) } // To check that a block containing the same transaction already in it's past is disqualified: @@ -145,8 +145,8 @@ func TestDoubleSpends(t *testing.T) { if err != nil { t.Fatalf("Error getting status of goodBlock: %+v", err) } - if goodBlock2Status != externalapi.StatusValid { - t.Fatalf("GoodBlock2 status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock2Status) + if goodBlock2Status != externalapi.StatusUTXOValid { + t.Fatalf("GoodBlock2 status expected to be '%s', but is '%s'", externalapi.StatusUTXOValid, goodBlock2Status) } }) } @@ -167,7 +167,7 @@ func TestResolveBlockStatusSanity(t *testing.T) { if err != nil { t.Fatalf("error getting genesis status: %s", err) } - if genesisStatus != externalapi.StatusValid { + if genesisStatus != externalapi.StatusUTXOValid { t.Fatalf("genesis is unexpectedly non-valid. Its status is: %s", genesisStatus) } @@ -185,7 +185,7 @@ func TestResolveBlockStatusSanity(t *testing.T) { if err != nil { t.Fatalf("error getting block %d (%s) status: %s", i, addedBlockHash, err) } - if blockStatus != externalapi.StatusValid { + if blockStatus != externalapi.StatusUTXOValid { t.Fatalf("block %d (%s) is unexpectedly non-valid. Its status is: %s", i, addedBlockHash, blockStatus) } currentHash = addedBlockHash @@ -224,13 +224,13 @@ func TestResolveBlockStatusSanity(t *testing.T) { allHashes = append(allHashes, addedBlockHash) } - // Make sure that all the blocks in the DAG now have StatusValid + // Make sure that all the blocks in the DAG now have StatusUTXOValid for _, hash := range allHashes { blockStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), hash) if err != nil { t.Fatalf("error getting block %s status: %s", hash, err) } - if blockStatus != externalapi.StatusValid { + if blockStatus != externalapi.StatusUTXOValid { t.Fatalf("block %s is unexpectedly non-valid. Its status is: %s", hash, blockStatus) } } diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index cbca2911e..87847d699 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -54,59 +54,69 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap if err != nil { return err } - log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash()) + log.Debugf("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash()) newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash) if err != nil { return err } - log.Tracef("The UTXO commitment of the pruning point: %s", + log.Debugf("The UTXO commitment of the pruning point: %s", newPruningPointHeader.UTXOCommitment) 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", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash()) } - log.Tracef("The new pruning point UTXO commitment validation passed") + log.Debugf("The new pruning point UTXO commitment validation passed") - log.Tracef("Staging the parent hashes for pruning point as the DAG tips") - csm.consensusStateStore.StageTips(newPruningPointHeader.ParentHashes) + newTips := []*externalapi.DomainHash{newPruningPointHash} - log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents") - err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newPruningPointHeader.ParentHashes) - if err != nil { - return err - } - - log.Tracef("Staging the virtual UTXO set") - err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet)) - if err != nil { - 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()) + log.Debugf("Staging the the pruning point as the only DAG tip") + csm.consensusStateStore.StageTips(newTips) + + log.Debugf("Setting the pruning point as the only virtual parent") + err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newTips) if err != nil { return err } + log.Debugf("Calculating GHOSTDAG for the new virtual") err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash) if err != nil { return err } - log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff") - err = csm.updateVirtualDiffParents(utxo.NewUTXODiff()) + log.Debugf("Staging the virtual UTXO set") + err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet)) if err != nil { return err } - log.Tracef("Staging the new pruning point and its UTXO set") + log.Debugf("Deleting all the existing virtual diff parents") + csm.consensusStateStore.StageVirtualDiffParents(nil) + + log.Debugf("Updating the new pruning point to be the new virtual diff parent with an empty diff") + err = csm.stageDiff(newPruningPointHash, utxo.NewUTXODiff(), nil) + if err != nil { + return err + } + + log.Debugf("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) + // Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid + // against the provided UTXO set. + log.Debugf("Validating that the pruning point is UTXO valid") + err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint, utxo.NewUTXODiff()) + if err != nil { + return err + } + + log.Debugf("Staging the new pruning point as %s", externalapi.StatusUTXOValid) + csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusUTXOValid) + + log.Debugf("Staging the new pruning point multiset") + csm.multisetStore.Stage(newPruningPointHash, utxoSetMultiSet) return nil } From 843edc4ba5881e8c95f0340597df228d3f2eee6a Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 20 Dec 2020 11:20:51 +0200 Subject: [PATCH 140/351] Limit the orphan collection (#1238) * Limit the orphan collection. * Fix grammar in a comment. * Fix a bad log. --- app/protocol/flowcontext/orphans.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index b54dc07cf..8cdc0058d 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -7,6 +7,12 @@ import ( "github.com/pkg/errors" ) +// maxOrphans is the maximum amount of orphans allowed in the +// orphans collection. This number is an approximation of how +// many orphans there can possibly be on average. It is based +// on: 2^orphanResolutionRange * PHANTOM K. +const maxOrphans = 600 + // AddOrphan adds the block to the orphan set func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphansMutex.Lock() @@ -15,9 +21,24 @@ func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { orphanHash := consensushashing.BlockHash(orphanBlock) f.orphans[*orphanHash] = orphanBlock + if len(f.orphans) > maxOrphans { + log.Debugf("Orphan collection size exceeded. Evicting a random orphan") + f.evictRandomOrphan() + } + log.Infof("Received a block with missing parents, adding to orphan pool: %s", orphanHash) } +func (f *FlowContext) evictRandomOrphan() { + var toEvict externalapi.DomainHash + for hash := range f.orphans { + toEvict = hash + break + } + delete(f.orphans, toEvict) + log.Debugf("Evicted %s from the orphan collection", toEvict) +} + // IsOrphan returns whether the given blockHash belongs to an orphan block func (f *FlowContext) IsOrphan(blockHash *externalapi.DomainHash) bool { f.orphansMutex.RLock() From 053bb351b5a22c360900cbcab09cfbbfbf3b7c9c Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 20 Dec 2020 17:24:56 +0200 Subject: [PATCH 141/351] [NOD-1597] Implement a UTXO index (#1221) * [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-1597] Begin implementing UTXOIndex. * [NOD-1597] Connect UTXOIndex to RPC. * [NOD-1597] Connect Consensus to UTXOIndex. * [NOD-1597] Add AcceptanceData to BlockInfo. * [NOD-1597] Implement UTXOIndex.Update(). * [NOD-1597] Implement add(), remove(), and discard() in utxoIndexStore. * [NOD-1597] Add error cases to add() and remove(). * [NOD-1597] Add special cases to add() and remove(). * [NOD-1597] Implement commit. * [NOD-1597] Add a mutex around UTXOIndex.Update(). * [NOD-1597] Return changes to the UTXO from Update(). * [NOD-1597] Add NotifyUTXOsChangedRequestMessage and related structs. * [NOD-1597] Implement HandleNotifyUTXOsChanged. * [NOD-1597] Begin implementing TestUTXOIndex. * [NOD-1597] Implement RegisterForUTXOsChangedNotifications. * [NOD-1597] Fix bad transaction.ID usage. * [NOD-1597] Implement convertUTXOChangesToUTXOsChangedNotification. * [NOD-1597] Make UTXOsChangedNotificationMessage.Removed UTXOsByAddressesEntry instead of just RPCOutpoint so that the client can discern which address was the UTXO removed for. * [NOD-1597] Collect outpoints in TestUTXOIndex. * [NOD-1597] Rename RPC stuff. * [NOD-1597] Add messages for GetUTXOsByAddresses. * [NOD-1597] Implement HandleGetUTXOsByAddresses. * [NOD-1597] Implement GetUTXOsByAddresses. * [NOD-1597] Implement UTXOs(). * [NOD-1597] Implement getUTXOOutpointEntryPairs(). * [NOD-1597] Expand TestUTXOIndex. * [NOD-1597] Convert SubmitTransaction to use RPCTransaction instead of MsgTx. * [NOD-1597] Finish implementing TestUTXOIndex. * [NOD-1597] Add messages for GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement HandleGetVirtualSelectedParentBlueScore and GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement NotifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Expand TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement notifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Make go lint happy. * [NOD-1593] Fix merge errors. * [NOD-1593] Rename findSelectedParentChainChanges to calculateSelectedParentChainChanges. * [NOD-1593] Expand TestCalculateSelectedParentChainChanges. * [NOD-1597] Add logs to utxoindex.go. * [NOD-1597] Add logs to utxoindex/store.go. * [NOD-1597] Add logs to RPCManager.NotifyXXX functions. * [NOD-1597] Ignore transactions that aren't accepted. * [NOD-1597] Use GetBlockAcceptanceData instead of GetBlockInfo. * [NOD-1597] Convert scriptPublicKey to string directly, instead of using hex. * [NOD-1597] Add a comment. * [NOD-1597] Guard against calling utxoindex methods when utxoindex is turned off. * [NOD-1597] Add lock to UTXOs. * [NOD-1597] Guard against calls to getUTXOOutpointEntryPairs when staging isn't empty. --- app/appmessage/domainconverters.go | 114 + app/appmessage/message.go | 114 +- app/appmessage/rpc_get_utxos_by_addresses.go | 41 + ..._get_virtual_selected_parent_blue_score.go | 38 + app/appmessage/rpc_notify_utxos_changed.go | 62 + ...elected_parent_chain_blue_score_changed.go | 55 + app/appmessage/rpc_submit_transaction.go | 54 +- app/component_manager.go | 20 +- app/protocol/flowcontext/blocks.go | 10 +- app/protocol/flowcontext/flow_context.go | 2 +- .../flows/blockrelay/handle_relay_invs.go | 18 +- app/protocol/flows/blockrelay/ibd.go | 4 +- app/rpc/manager.go | 54 +- app/rpc/rpc.go | 48 +- app/rpc/rpccontext/context.go | 5 + app/rpc/rpccontext/notificationmanager.go | 112 +- app/rpc/rpccontext/utxos_by_addresses.go | 29 + app/rpc/rpchandlers/get_utxos_by_addresses.go | 45 + .../get_virtual_selected_parent_blue_score.go | 16 + app/rpc/rpchandlers/notify_utxos_changed.go | 51 + ...tual_selected_parent_blue_score_changed.go | 19 + app/rpc/rpchandlers/submit_transaction.go | 10 +- domain/consensus/consensus.go | 18 + .../database/serialization/acceptancedata.go | 16 +- .../acceptancedatastore.go | 16 +- .../model/{ => externalapi}/acceptancedata.go | 6 +- .../consensus/model/externalapi/consensus.go | 1 + domain/consensus/model/externalapi/virtual.go | 1 + ...face_datastructures_acceptancedatastore.go | 4 +- ...terface_processes_consensusstatemanager.go | 2 +- .../processes/blockbuilder/block_builder.go | 2 +- .../blockbuilder/test_block_builder.go | 2 +- .../coinbasemanager/coinbasemanager.go | 2 +- .../calculate_past_utxo.go | 14 +- .../consensusstatemanager/multisets.go | 2 +- .../verify_and_build_utxo.go | 6 +- domain/utxoindex/log.go | 11 + domain/utxoindex/model.go | 33 + domain/utxoindex/store.go | 255 ++ domain/utxoindex/utxoindex.go | 168 + infrastructure/config/config.go | 1 + .../grpcserver/protowire/messages.pb.go | 3126 ++++++++++++----- .../grpcserver/protowire/messages.proto | 100 +- .../protowire/rpc_get_utxos_by_addresses.go | 48 + ..._get_virtual_selected_parent_blue_score.go | 37 + .../protowire/rpc_notify_utxos_changed.go | 118 + ...tual_selected_parent_blue_score_changed.go | 46 + .../protowire/rpc_submit_transaction.go | 85 +- .../server/grpcserver/protowire/wire.go | 70 + .../rpcclient/rpc_get_utxos_by_addresses.go | 20 + ..._get_virtual_selected_parent_blue_score.go | 20 + .../network/rpcclient/rpc_on_utxos_changed.go | 40 + ...tual_selected_parent_blue_score_changed.go | 41 + .../rpcclient/rpc_send_raw_transaction.go | 4 +- testing/integration/config_test.go | 1 + testing/integration/setup_test.go | 3 + testing/integration/tx_relay_test.go | 8 +- testing/integration/utxo_index_test.go | 192 + ...virtual_selected_parent_blue_score_test.go | 62 + 59 files changed, 4517 insertions(+), 985 deletions(-) create mode 100644 app/appmessage/rpc_get_utxos_by_addresses.go create mode 100644 app/appmessage/rpc_get_virtual_selected_parent_blue_score.go create mode 100644 app/appmessage/rpc_notify_utxos_changed.go create mode 100644 app/appmessage/rpc_notify_virtual_selected_parent_chain_blue_score_changed.go create mode 100644 app/rpc/rpccontext/utxos_by_addresses.go create mode 100644 app/rpc/rpchandlers/get_utxos_by_addresses.go create mode 100644 app/rpc/rpchandlers/get_virtual_selected_parent_blue_score.go create mode 100644 app/rpc/rpchandlers/notify_utxos_changed.go create mode 100644 app/rpc/rpchandlers/notify_virtual_selected_parent_blue_score_changed.go rename domain/consensus/model/{ => externalapi}/acceptancedata.go (92%) create mode 100644 domain/utxoindex/log.go create mode 100644 domain/utxoindex/model.go create mode 100644 domain/utxoindex/store.go create mode 100644 domain/utxoindex/utxoindex.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_blue_score.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_blue_score_changed.go create mode 100644 infrastructure/network/rpcclient/rpc_get_utxos_by_addresses.go create mode 100644 infrastructure/network/rpcclient/rpc_get_virtual_selected_parent_blue_score.go create mode 100644 infrastructure/network/rpcclient/rpc_on_utxos_changed.go create mode 100644 infrastructure/network/rpcclient/rpc_on_virtual_selected_parent_blue_score_changed.go create mode 100644 testing/integration/utxo_index_test.go create mode 100644 testing/integration/virtual_selected_parent_blue_score_test.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 6a8116284..21733ff87 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -1,7 +1,11 @@ package appmessage import ( + "encoding/hex" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "github.com/kaspanet/kaspad/util/mstime" ) @@ -153,3 +157,113 @@ func outpointToDomainOutpoint(outpoint *Outpoint) *externalapi.DomainOutpoint { Index: outpoint.Index, } } + +// RPCTransactionToDomainTransaction converts RPCTransactions to DomainTransactions +func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externalapi.DomainTransaction, error) { + inputs := make([]*externalapi.DomainTransactionInput, len(rpcTransaction.Inputs)) + for i, input := range rpcTransaction.Inputs { + transactionIDBytes, err := hex.DecodeString(input.PreviousOutpoint.TransactionID) + if err != nil { + return nil, err + } + transactionID, err := transactionid.FromBytes(transactionIDBytes) + if err != nil { + return nil, err + } + previousOutpoint := &externalapi.DomainOutpoint{ + TransactionID: *transactionID, + Index: input.PreviousOutpoint.Index, + } + signatureScript, err := hex.DecodeString(input.SignatureScript) + if err != nil { + return nil, err + } + inputs[i] = &externalapi.DomainTransactionInput{ + PreviousOutpoint: *previousOutpoint, + SignatureScript: signatureScript, + Sequence: input.Sequence, + } + } + outputs := make([]*externalapi.DomainTransactionOutput, len(rpcTransaction.Outputs)) + for i, output := range rpcTransaction.Outputs { + scriptPublicKey, err := hex.DecodeString(output.ScriptPubKey) + if err != nil { + return nil, err + } + outputs[i] = &externalapi.DomainTransactionOutput{ + Value: output.Amount, + ScriptPublicKey: scriptPublicKey, + } + } + + subnetworkIDBytes, err := hex.DecodeString(rpcTransaction.SubnetworkID) + if err != nil { + return nil, err + } + subnetworkID, err := subnetworks.FromBytes(subnetworkIDBytes) + if err != nil { + return nil, err + } + payloadHashBytes, err := hex.DecodeString(rpcTransaction.PayloadHash) + if err != nil { + return nil, err + } + payloadHash, err := hashes.FromBytes(payloadHashBytes) + if err != nil { + return nil, err + } + payload, err := hex.DecodeString(rpcTransaction.Payload) + if err != nil { + return nil, err + } + + return &externalapi.DomainTransaction{ + Version: rpcTransaction.Version, + Inputs: inputs, + Outputs: outputs, + LockTime: rpcTransaction.LockTime, + SubnetworkID: *subnetworkID, + Gas: rpcTransaction.LockTime, + PayloadHash: *payloadHash, + Payload: payload, + }, nil +} + +// DomainTransactionToRPCTransaction converts DomainTransactions to RPCTransactions +func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransaction) *RPCTransaction { + inputs := make([]*RPCTransactionInput, len(transaction.Inputs)) + for i, input := range transaction.Inputs { + transactionID := hex.EncodeToString(input.PreviousOutpoint.TransactionID[:]) + previousOutpoint := &RPCOutpoint{ + TransactionID: transactionID, + Index: input.PreviousOutpoint.Index, + } + signatureScript := hex.EncodeToString(input.SignatureScript) + inputs[i] = &RPCTransactionInput{ + PreviousOutpoint: previousOutpoint, + SignatureScript: signatureScript, + Sequence: input.Sequence, + } + } + outputs := make([]*RPCTransactionOutput, len(transaction.Outputs)) + for i, output := range transaction.Outputs { + scriptPublicKey := hex.EncodeToString(output.ScriptPublicKey) + outputs[i] = &RPCTransactionOutput{ + Amount: output.Value, + ScriptPubKey: scriptPublicKey, + } + } + subnetworkID := hex.EncodeToString(transaction.SubnetworkID[:]) + payloadHash := hex.EncodeToString(transaction.PayloadHash[:]) + payload := hex.EncodeToString(transaction.Payload) + return &RPCTransaction{ + Version: transaction.Version, + Inputs: inputs, + Outputs: outputs, + LockTime: transaction.LockTime, + SubnetworkID: subnetworkID, + Gas: transaction.LockTime, + PayloadHash: payloadHash, + Payload: payload, + } +} diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 7b12147d6..381ca4436 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -106,6 +106,16 @@ const ( CmdShutDownResponseMessage CmdGetHeadersRequestMessage CmdGetHeadersResponseMessage + CmdNotifyUTXOsChangedRequestMessage + CmdNotifyUTXOsChangedResponseMessage + CmdUTXOsChangedNotificationMessage + CmdGetUTXOsByAddressesRequestMessage + CmdGetUTXOsByAddressesResponseMessage + CmdGetVirtualSelectedParentBlueScoreRequestMessage + CmdGetVirtualSelectedParentBlueScoreResponseMessage + CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage + CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage + CmdVirtualSelectedParentBlueScoreChangedNotificationMessage ) // ProtocolMessageCommandToString maps all MessageCommands to their string representation @@ -139,53 +149,63 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ // RPCMessageCommandToString maps all MessageCommands to their string representation var RPCMessageCommandToString = map[MessageCommand]string{ - CmdGetCurrentNetworkRequestMessage: "GetCurrentNetworkRequest", - CmdGetCurrentNetworkResponseMessage: "GetCurrentNetworkResponse", - CmdSubmitBlockRequestMessage: "SubmitBlockRequest", - CmdSubmitBlockResponseMessage: "SubmitBlockResponse", - CmdGetBlockTemplateRequestMessage: "GetBlockTemplateRequest", - CmdGetBlockTemplateResponseMessage: "GetBlockTemplateResponse", - CmdGetBlockTemplateTransactionMessage: "CmdGetBlockTemplateTransaction", - CmdNotifyBlockAddedRequestMessage: "NotifyBlockAddedRequest", - CmdNotifyBlockAddedResponseMessage: "NotifyBlockAddedResponse", - CmdBlockAddedNotificationMessage: "BlockAddedNotification", - CmdGetPeerAddressesRequestMessage: "GetPeerAddressesRequest", - CmdGetPeerAddressesResponseMessage: "GetPeerAddressesResponse", - CmdGetSelectedTipHashRequestMessage: "GetSelectedTipHashRequest", - CmdGetSelectedTipHashResponseMessage: "GetSelectedTipHashResponse", - CmdGetMempoolEntryRequestMessage: "GetMempoolEntryRequest", - CmdGetMempoolEntryResponseMessage: "GetMempoolEntryResponse", - CmdGetConnectedPeerInfoRequestMessage: "GetConnectedPeerInfoRequest", - CmdGetConnectedPeerInfoResponseMessage: "GetConnectedPeerInfoResponse", - CmdAddPeerRequestMessage: "AddPeerRequest", - CmdAddPeerResponseMessage: "AddPeerResponse", - CmdSubmitTransactionRequestMessage: "SubmitTransactionRequest", - CmdSubmitTransactionResponseMessage: "SubmitTransactionResponse", - CmdNotifyChainChangedRequestMessage: "NotifyChainChangedRequest", - CmdNotifyChainChangedResponseMessage: "NotifyChainChangedResponse", - CmdChainChangedNotificationMessage: "ChainChangedNotification", - CmdGetBlockRequestMessage: "GetBlockRequest", - CmdGetBlockResponseMessage: "GetBlockResponse", - CmdGetSubnetworkRequestMessage: "GetSubnetworkRequest", - CmdGetSubnetworkResponseMessage: "GetSubnetworkResponse", - CmdGetChainFromBlockRequestMessage: "GetChainFromBlockRequest", - CmdGetChainFromBlockResponseMessage: "GetChainFromBlockResponse", - CmdGetBlocksRequestMessage: "GetBlocksRequest", - CmdGetBlocksResponseMessage: "GetBlocksResponse", - CmdGetBlockCountRequestMessage: "GetBlockCountRequest", - CmdGetBlockCountResponseMessage: "GetBlockCountResponse", - CmdGetBlockDAGInfoRequestMessage: "GetBlockDAGInfoRequest", - CmdGetBlockDAGInfoResponseMessage: "GetBlockDAGInfoResponse", - CmdResolveFinalityConflictRequestMessage: "ResolveFinalityConflictRequest", - CmdResolveFinalityConflictResponseMessage: "ResolveFinalityConflictResponse", - CmdNotifyFinalityConflictsRequestMessage: "NotifyFinalityConflictsRequest", - CmdNotifyFinalityConflictsResponseMessage: "NotifyFinalityConflictsResponse", - CmdFinalityConflictNotificationMessage: "FinalityConflictNotification", - CmdFinalityConflictResolvedNotificationMessage: "FinalityConflictResolvedNotification", - CmdGetMempoolEntriesRequestMessage: "GetMempoolEntriesRequestMessage", - CmdGetMempoolEntriesResponseMessage: "GetMempoolEntriesResponseMessage", - CmdGetHeadersRequestMessage: "GetHeadersRequest", - CmdGetHeadersResponseMessage: "GetHeadersResponse", + CmdGetCurrentNetworkRequestMessage: "GetCurrentNetworkRequest", + CmdGetCurrentNetworkResponseMessage: "GetCurrentNetworkResponse", + CmdSubmitBlockRequestMessage: "SubmitBlockRequest", + CmdSubmitBlockResponseMessage: "SubmitBlockResponse", + CmdGetBlockTemplateRequestMessage: "GetBlockTemplateRequest", + CmdGetBlockTemplateResponseMessage: "GetBlockTemplateResponse", + CmdGetBlockTemplateTransactionMessage: "CmdGetBlockTemplateTransaction", + CmdNotifyBlockAddedRequestMessage: "NotifyBlockAddedRequest", + CmdNotifyBlockAddedResponseMessage: "NotifyBlockAddedResponse", + CmdBlockAddedNotificationMessage: "BlockAddedNotification", + CmdGetPeerAddressesRequestMessage: "GetPeerAddressesRequest", + CmdGetPeerAddressesResponseMessage: "GetPeerAddressesResponse", + CmdGetSelectedTipHashRequestMessage: "GetSelectedTipHashRequest", + CmdGetSelectedTipHashResponseMessage: "GetSelectedTipHashResponse", + CmdGetMempoolEntryRequestMessage: "GetMempoolEntryRequest", + CmdGetMempoolEntryResponseMessage: "GetMempoolEntryResponse", + CmdGetConnectedPeerInfoRequestMessage: "GetConnectedPeerInfoRequest", + CmdGetConnectedPeerInfoResponseMessage: "GetConnectedPeerInfoResponse", + CmdAddPeerRequestMessage: "AddPeerRequest", + CmdAddPeerResponseMessage: "AddPeerResponse", + CmdSubmitTransactionRequestMessage: "SubmitTransactionRequest", + CmdSubmitTransactionResponseMessage: "SubmitTransactionResponse", + CmdNotifyChainChangedRequestMessage: "NotifyChainChangedRequest", + CmdNotifyChainChangedResponseMessage: "NotifyChainChangedResponse", + CmdChainChangedNotificationMessage: "ChainChangedNotification", + CmdGetBlockRequestMessage: "GetBlockRequest", + CmdGetBlockResponseMessage: "GetBlockResponse", + CmdGetSubnetworkRequestMessage: "GetSubnetworkRequest", + CmdGetSubnetworkResponseMessage: "GetSubnetworkResponse", + CmdGetChainFromBlockRequestMessage: "GetChainFromBlockRequest", + CmdGetChainFromBlockResponseMessage: "GetChainFromBlockResponse", + CmdGetBlocksRequestMessage: "GetBlocksRequest", + CmdGetBlocksResponseMessage: "GetBlocksResponse", + CmdGetBlockCountRequestMessage: "GetBlockCountRequest", + CmdGetBlockCountResponseMessage: "GetBlockCountResponse", + CmdGetBlockDAGInfoRequestMessage: "GetBlockDAGInfoRequest", + CmdGetBlockDAGInfoResponseMessage: "GetBlockDAGInfoResponse", + CmdResolveFinalityConflictRequestMessage: "ResolveFinalityConflictRequest", + CmdResolveFinalityConflictResponseMessage: "ResolveFinalityConflictResponse", + CmdNotifyFinalityConflictsRequestMessage: "NotifyFinalityConflictsRequest", + CmdNotifyFinalityConflictsResponseMessage: "NotifyFinalityConflictsResponse", + CmdFinalityConflictNotificationMessage: "FinalityConflictNotification", + CmdFinalityConflictResolvedNotificationMessage: "FinalityConflictResolvedNotification", + CmdGetMempoolEntriesRequestMessage: "GetMempoolEntriesRequest", + CmdGetMempoolEntriesResponseMessage: "GetMempoolEntriesResponse", + CmdGetHeadersRequestMessage: "GetHeadersRequest", + CmdGetHeadersResponseMessage: "GetHeadersResponse", + CmdNotifyUTXOsChangedRequestMessage: "NotifyUTXOsChangedRequest", + CmdNotifyUTXOsChangedResponseMessage: "NotifyUTXOsChangedResponse", + CmdUTXOsChangedNotificationMessage: "UTXOsChangedNotification", + CmdGetUTXOsByAddressesRequestMessage: "GetUTXOsByAddressesRequest", + CmdGetUTXOsByAddressesResponseMessage: "GetUTXOsByAddressesResponse", + CmdGetVirtualSelectedParentBlueScoreRequestMessage: "GetVirtualSelectedParentBlueScoreRequest", + CmdGetVirtualSelectedParentBlueScoreResponseMessage: "GetVirtualSelectedParentBlueScoreResponse", + CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: "NotifyVirtualSelectedParentBlueScoreChangedRequest", + CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage: "NotifyVirtualSelectedParentBlueScoreChangedResponse", + CmdVirtualSelectedParentBlueScoreChangedNotificationMessage: "VirtualSelectedParentBlueScoreChangedNotification", } // Message is an interface that describes a kaspa message. A type that diff --git a/app/appmessage/rpc_get_utxos_by_addresses.go b/app/appmessage/rpc_get_utxos_by_addresses.go new file mode 100644 index 000000000..0fff8b80b --- /dev/null +++ b/app/appmessage/rpc_get_utxos_by_addresses.go @@ -0,0 +1,41 @@ +package appmessage + +// GetUTXOsByAddressesRequestMessage is an appmessage corresponding to +// its respective RPC message +type GetUTXOsByAddressesRequestMessage struct { + baseMessage + Addresses []string +} + +// Command returns the protocol command string for the message +func (msg *GetUTXOsByAddressesRequestMessage) Command() MessageCommand { + return CmdGetUTXOsByAddressesRequestMessage +} + +// NewGetUTXOsByAddressesRequestMessage returns a instance of the message +func NewGetUTXOsByAddressesRequestMessage(addresses []string) *GetUTXOsByAddressesRequestMessage { + return &GetUTXOsByAddressesRequestMessage{ + Addresses: addresses, + } +} + +// GetUTXOsByAddressesResponseMessage is an appmessage corresponding to +// its respective RPC message +type GetUTXOsByAddressesResponseMessage struct { + baseMessage + Entries []*UTXOsByAddressesEntry + + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *GetUTXOsByAddressesResponseMessage) Command() MessageCommand { + return CmdGetUTXOsByAddressesResponseMessage +} + +// NewGetUTXOsByAddressesResponseMessage returns a instance of the message +func NewGetUTXOsByAddressesResponseMessage(entries []*UTXOsByAddressesEntry) *GetUTXOsByAddressesResponseMessage { + return &GetUTXOsByAddressesResponseMessage{ + Entries: entries, + } +} diff --git a/app/appmessage/rpc_get_virtual_selected_parent_blue_score.go b/app/appmessage/rpc_get_virtual_selected_parent_blue_score.go new file mode 100644 index 000000000..67fb6b486 --- /dev/null +++ b/app/appmessage/rpc_get_virtual_selected_parent_blue_score.go @@ -0,0 +1,38 @@ +package appmessage + +// GetVirtualSelectedParentBlueScoreRequestMessage is an appmessage corresponding to +// its respective RPC message +type GetVirtualSelectedParentBlueScoreRequestMessage struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *GetVirtualSelectedParentBlueScoreRequestMessage) Command() MessageCommand { + return CmdGetVirtualSelectedParentBlueScoreRequestMessage +} + +// NewGetVirtualSelectedParentBlueScoreRequestMessage returns a instance of the message +func NewGetVirtualSelectedParentBlueScoreRequestMessage() *GetVirtualSelectedParentBlueScoreRequestMessage { + return &GetVirtualSelectedParentBlueScoreRequestMessage{} +} + +// GetVirtualSelectedParentBlueScoreResponseMessage is an appmessage corresponding to +// its respective RPC message +type GetVirtualSelectedParentBlueScoreResponseMessage struct { + baseMessage + BlueScore uint64 + + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *GetVirtualSelectedParentBlueScoreResponseMessage) Command() MessageCommand { + return CmdGetVirtualSelectedParentBlueScoreResponseMessage +} + +// NewGetVirtualSelectedParentBlueScoreResponseMessage returns a instance of the message +func NewGetVirtualSelectedParentBlueScoreResponseMessage(blueScore uint64) *GetVirtualSelectedParentBlueScoreResponseMessage { + return &GetVirtualSelectedParentBlueScoreResponseMessage{ + BlueScore: blueScore, + } +} diff --git a/app/appmessage/rpc_notify_utxos_changed.go b/app/appmessage/rpc_notify_utxos_changed.go new file mode 100644 index 000000000..e8f0e6d4c --- /dev/null +++ b/app/appmessage/rpc_notify_utxos_changed.go @@ -0,0 +1,62 @@ +package appmessage + +// NotifyUTXOsChangedRequestMessage is an appmessage corresponding to +// its respective RPC message +type NotifyUTXOsChangedRequestMessage struct { + baseMessage + Addresses []string +} + +// Command returns the protocol command string for the message +func (msg *NotifyUTXOsChangedRequestMessage) Command() MessageCommand { + return CmdNotifyUTXOsChangedRequestMessage +} + +// NewNotifyUTXOsChangedRequestMessage returns a instance of the message +func NewNotifyUTXOsChangedRequestMessage(addresses []string) *NotifyUTXOsChangedRequestMessage { + return &NotifyUTXOsChangedRequestMessage{ + Addresses: addresses, + } +} + +// NotifyUTXOsChangedResponseMessage is an appmessage corresponding to +// its respective RPC message +type NotifyUTXOsChangedResponseMessage struct { + baseMessage + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *NotifyUTXOsChangedResponseMessage) Command() MessageCommand { + return CmdNotifyUTXOsChangedResponseMessage +} + +// NewNotifyUTXOsChangedResponseMessage returns a instance of the message +func NewNotifyUTXOsChangedResponseMessage() *NotifyUTXOsChangedResponseMessage { + return &NotifyUTXOsChangedResponseMessage{} +} + +// UTXOsChangedNotificationMessage is an appmessage corresponding to +// its respective RPC message +type UTXOsChangedNotificationMessage struct { + baseMessage + Added []*UTXOsByAddressesEntry + Removed []*UTXOsByAddressesEntry +} + +// UTXOsByAddressesEntry represents a UTXO of some address +type UTXOsByAddressesEntry struct { + Address string + Outpoint *RPCOutpoint + UTXOEntry *RPCUTXOEntry +} + +// Command returns the protocol command string for the message +func (msg *UTXOsChangedNotificationMessage) Command() MessageCommand { + return CmdUTXOsChangedNotificationMessage +} + +// NewUTXOsChangedNotificationMessage returns a instance of the message +func NewUTXOsChangedNotificationMessage() *UTXOsChangedNotificationMessage { + return &UTXOsChangedNotificationMessage{} +} diff --git a/app/appmessage/rpc_notify_virtual_selected_parent_chain_blue_score_changed.go b/app/appmessage/rpc_notify_virtual_selected_parent_chain_blue_score_changed.go new file mode 100644 index 000000000..c4c2b3533 --- /dev/null +++ b/app/appmessage/rpc_notify_virtual_selected_parent_chain_blue_score_changed.go @@ -0,0 +1,55 @@ +package appmessage + +// NotifyVirtualSelectedParentBlueScoreChangedRequestMessage is an appmessage corresponding to +// its respective RPC message +type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Command() MessageCommand { + return CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage +} + +// NewNotifyVirtualSelectedParentBlueScoreChangedRequestMessage returns a instance of the message +func NewNotifyVirtualSelectedParentBlueScoreChangedRequestMessage() *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage { + return &NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} +} + +// NotifyVirtualSelectedParentBlueScoreChangedResponseMessage is an appmessage corresponding to +// its respective RPC message +type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { + baseMessage + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Command() MessageCommand { + return CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage +} + +// NewNotifyVirtualSelectedParentBlueScoreChangedResponseMessage returns a instance of the message +func NewNotifyVirtualSelectedParentBlueScoreChangedResponseMessage() *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { + return &NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} +} + +// VirtualSelectedParentBlueScoreChangedNotificationMessage is an appmessage corresponding to +// its respective RPC message +type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { + baseMessage + VirtualSelectedParentBlueScore uint64 +} + +// Command returns the protocol command string for the message +func (msg *VirtualSelectedParentBlueScoreChangedNotificationMessage) Command() MessageCommand { + return CmdVirtualSelectedParentBlueScoreChangedNotificationMessage +} + +// NewVirtualSelectedParentBlueScoreChangedNotificationMessage returns a instance of the message +func NewVirtualSelectedParentBlueScoreChangedNotificationMessage( + virtualSelectedParentBlueScore uint64) *VirtualSelectedParentBlueScoreChangedNotificationMessage { + + return &VirtualSelectedParentBlueScoreChangedNotificationMessage{ + VirtualSelectedParentBlueScore: virtualSelectedParentBlueScore, + } +} diff --git a/app/appmessage/rpc_submit_transaction.go b/app/appmessage/rpc_submit_transaction.go index 199406f66..ba63da336 100644 --- a/app/appmessage/rpc_submit_transaction.go +++ b/app/appmessage/rpc_submit_transaction.go @@ -4,7 +4,7 @@ package appmessage // its respective RPC message type SubmitTransactionRequestMessage struct { baseMessage - Transaction *MsgTx + Transaction *RPCTransaction } // Command returns the protocol command string for the message @@ -13,7 +13,7 @@ func (msg *SubmitTransactionRequestMessage) Command() MessageCommand { } // NewSubmitTransactionRequestMessage returns a instance of the message -func NewSubmitTransactionRequestMessage(transaction *MsgTx) *SubmitTransactionRequestMessage { +func NewSubmitTransactionRequestMessage(transaction *RPCTransaction) *SubmitTransactionRequestMessage { return &SubmitTransactionRequestMessage{ Transaction: transaction, } @@ -23,7 +23,7 @@ func NewSubmitTransactionRequestMessage(transaction *MsgTx) *SubmitTransactionRe // its respective RPC message type SubmitTransactionResponseMessage struct { baseMessage - TxID string + TransactionID string Error *RPCError } @@ -34,8 +34,52 @@ func (msg *SubmitTransactionResponseMessage) Command() MessageCommand { } // NewSubmitTransactionResponseMessage returns a instance of the message -func NewSubmitTransactionResponseMessage(txID string) *SubmitTransactionResponseMessage { +func NewSubmitTransactionResponseMessage(transactionID string) *SubmitTransactionResponseMessage { return &SubmitTransactionResponseMessage{ - TxID: txID, + TransactionID: transactionID, } } + +// RPCTransaction is a kaspad transaction representation meant to be +// used over RPC +type RPCTransaction struct { + Version int32 + Inputs []*RPCTransactionInput + Outputs []*RPCTransactionOutput + LockTime uint64 + SubnetworkID string + Gas uint64 + PayloadHash string + Payload string +} + +// RPCTransactionInput is a kaspad transaction input representation +// meant to be used over RPC +type RPCTransactionInput struct { + PreviousOutpoint *RPCOutpoint + SignatureScript string + Sequence uint64 +} + +// RPCTransactionOutput is a kaspad transaction output representation +// meant to be used over RPC +type RPCTransactionOutput struct { + Amount uint64 + ScriptPubKey string +} + +// RPCOutpoint is a kaspad outpoint representation meant to be used +// over RPC +type RPCOutpoint struct { + TransactionID string + Index uint32 +} + +// RPCUTXOEntry is a kaspad utxo entry representation meant to be used +// over RPC +type RPCUTXOEntry struct { + Amount uint64 + ScriptPubKey string + BlockBlueScore uint64 + IsCoinbase bool +} diff --git a/app/component_manager.go b/app/component_manager.go index 441ec1d92..f3efe34e9 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -2,6 +2,7 @@ package app import ( "fmt" + "github.com/kaspanet/kaspad/domain/utxoindex" "sync/atomic" infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database" @@ -93,6 +94,12 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, return nil, err } + var utxoIndex *utxoindex.UTXOIndex + if cfg.UTXOIndex { + utxoIndex = utxoindex.New(domain.Consensus(), db) + log.Infof("UTXO index started") + } + connectionManager, err := connmanager.New(cfg, netAdapter, addressManager) if err != nil { return nil, err @@ -101,7 +108,7 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, if err != nil { return nil, err } - rpcManager := setupRPC(cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, interrupt) + rpcManager := setupRPC(cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, utxoIndex, interrupt) return &ComponentManager{ cfg: cfg, @@ -121,11 +128,20 @@ func setupRPC( protocolManager *protocol.Manager, connectionManager *connmanager.ConnectionManager, addressManager *addressmanager.AddressManager, + utxoIndex *utxoindex.UTXOIndex, shutDownChan chan<- struct{}, ) *rpc.Manager { rpcManager := rpc.NewManager( - cfg, domain, netAdapter, protocolManager, connectionManager, addressManager, shutDownChan) + cfg, + domain, + netAdapter, + protocolManager, + connectionManager, + addressManager, + utxoIndex, + shutDownChan, + ) protocolManager.SetOnBlockAddedToDAGHandler(rpcManager.NotifyBlockAddedToDAG) return rpcManager diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 66de8bdd0..d83c18906 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -17,7 +17,9 @@ import ( // OnNewBlock updates the mempool after a new block arrival, and // relays newly unorphaned transactions and possibly rebroadcast // manually added transactions when not in IBD. -func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { +func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, + blockInsertionResult *externalapi.BlockInsertionResult) error { + hash := consensushashing.BlockHash(block) log.Debugf("OnNewBlock start for block %s", hash) defer log.Debugf("OnNewBlock end for block %s", hash) @@ -37,7 +39,7 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock) error { if f.onBlockAddedToDAGHandler != nil { log.Tracef("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash) - err := f.onBlockAddedToDAGHandler(newBlock) + err := f.onBlockAddedToDAGHandler(newBlock, blockInsertionResult) if err != nil { return err } @@ -89,7 +91,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) + blockInsertionResult, 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) @@ -97,7 +99,7 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { } return err } - err = f.OnNewBlock(block) + err = f.OnNewBlock(block, blockInsertionResult) if err != nil { return err } diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index 0394e9a87..08406621e 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -20,7 +20,7 @@ import ( // OnBlockAddedToDAGHandler is a handler function that's triggered // when a block is added to the DAG -type OnBlockAddedToDAGHandler func(block *externalapi.DomainBlock) error +type OnBlockAddedToDAGHandler func(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error // OnTransactionAddedToMempoolHandler is a handler function that's triggered // when a transaction is added to the mempool diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 266e732ea..26e335580 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -25,7 +25,7 @@ type RelayInvsContext interface { Domain() domain.Domain Config() *config.Config NetAdapter() *netadapter.NetAdapter - OnNewBlock(block *externalapi.DomainBlock) error + OnNewBlock(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error SharedRequestedBlocks() *SharedRequestedBlocks Broadcast(message appmessage.Message) error AddOrphan(orphanBlock *externalapi.DomainBlock) @@ -102,7 +102,7 @@ func (flow *handleRelayInvsFlow) start() error { } log.Debugf("Processing block %s", inv.Hash) - missingParents, err := flow.processBlock(block) + missingParents, blockInsertionResult, err := flow.processBlock(block) if err != nil { return err } @@ -121,7 +121,7 @@ func (flow *handleRelayInvsFlow) start() error { return err } log.Infof("Accepted block %s via relay", inv.Hash) - err = flow.OnNewBlock(block) + err = flow.OnNewBlock(block, blockInsertionResult) if err != nil { return err } @@ -199,22 +199,22 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock, } } -func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) { +func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) { blockHash := consensushashing.BlockHash(block) - _, err := flow.Domain().Consensus().ValidateAndInsertBlock(block) + blockInsertionResult, 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) + return nil, nil, errors.Wrapf(err, "failed to process block %s", blockHash) } missingParentsError := &ruleerrors.ErrMissingParents{} if errors.As(err, missingParentsError) { - return missingParentsError.MissingParentHashes, nil + return missingParentsError.MissingParentHashes, nil, 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, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash) } - return nil, nil + return nil, blockInsertionResult, nil } func (flow *handleRelayInvsFlow) relayBlock(block *externalapi.DomainBlock) error { diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 6bd2ad722..41745bbab 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -283,11 +283,11 @@ 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) + blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash) } - err = flow.OnNewBlock(block) + err = flow.OnNewBlock(block, blockInsertionResult) if err != nil { return err } diff --git a/app/rpc/manager.go b/app/rpc/manager.go index c3c5ea607..c1d44d146 100644 --- a/app/rpc/manager.go +++ b/app/rpc/manager.go @@ -6,7 +6,9 @@ import ( "github.com/kaspanet/kaspad/app/rpc/rpccontext" "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/utxoindex" "github.com/kaspanet/kaspad/infrastructure/config" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" "github.com/kaspanet/kaspad/infrastructure/network/connmanager" "github.com/kaspanet/kaspad/infrastructure/network/netadapter" @@ -25,6 +27,7 @@ func NewManager( protocolManager *protocol.Manager, connectionManager *connmanager.ConnectionManager, addressManager *addressmanager.AddressManager, + utxoIndex *utxoindex.UTXOIndex, shutDownChan chan<- struct{}) *Manager { manager := Manager{ @@ -35,6 +38,7 @@ func NewManager( protocolManager, connectionManager, addressManager, + utxoIndex, shutDownChan, ), } @@ -44,19 +48,63 @@ func NewManager( } // NotifyBlockAddedToDAG notifies the manager that a block has been added to the DAG -func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock) error { - notification := appmessage.NewBlockAddedNotificationMessage(appmessage.DomainBlockToMsgBlock(block)) - return m.context.NotificationManager.NotifyBlockAdded(notification) +func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyBlockAddedToDAG") + defer onEnd() + + if m.context.Config.UTXOIndex { + err := m.notifyUTXOsChanged(blockInsertionResult) + if err != nil { + return err + } + } + + err := m.notifyVirtualSelectedParentBlueScoreChanged() + if err != nil { + return err + } + + blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(appmessage.DomainBlockToMsgBlock(block)) + return m.context.NotificationManager.NotifyBlockAdded(blockAddedNotification) } // NotifyFinalityConflict notifies the manager that there's a finality conflict in the DAG func (m *Manager) NotifyFinalityConflict(violatingBlockHash string) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyFinalityConflict") + defer onEnd() + notification := appmessage.NewFinalityConflictNotificationMessage(violatingBlockHash) return m.context.NotificationManager.NotifyFinalityConflict(notification) } // NotifyFinalityConflictResolved notifies the manager that a finality conflict in the DAG has been resolved func (m *Manager) NotifyFinalityConflictResolved(finalityBlockHash string) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyFinalityConflictResolved") + defer onEnd() + notification := appmessage.NewFinalityConflictResolvedNotificationMessage(finalityBlockHash) return m.context.NotificationManager.NotifyFinalityConflictResolved(notification) } + +func (m *Manager) notifyUTXOsChanged(blockInsertionResult *externalapi.BlockInsertionResult) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyUTXOsChanged") + defer onEnd() + + utxoIndexChanges, err := m.context.UTXOIndex.Update(blockInsertionResult.SelectedParentChainChanges) + if err != nil { + return err + } + return m.context.NotificationManager.NotifyUTXOsChanged(utxoIndexChanges) +} + +func (m *Manager) notifyVirtualSelectedParentBlueScoreChanged() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualSelectedParentBlueScoreChanged") + defer onEnd() + + virtualInfo, err := m.context.Domain.Consensus().GetVirtualInfo() + if err != nil { + return err + } + notification := appmessage.NewVirtualSelectedParentBlueScoreChangedNotificationMessage(virtualInfo.BlueScore) + return m.context.NotificationManager.NotifyVirtualSelectedParentBlueScoreChanged(notification) +} diff --git a/app/rpc/rpc.go b/app/rpc/rpc.go index 44ac3a8d3..0f73929cb 100644 --- a/app/rpc/rpc.go +++ b/app/rpc/rpc.go @@ -12,28 +12,32 @@ import ( type handler func(context *rpccontext.Context, router *router.Router, request appmessage.Message) (appmessage.Message, error) var handlers = map[appmessage.MessageCommand]handler{ - appmessage.CmdGetCurrentNetworkRequestMessage: rpchandlers.HandleGetCurrentNetwork, - appmessage.CmdSubmitBlockRequestMessage: rpchandlers.HandleSubmitBlock, - appmessage.CmdGetBlockTemplateRequestMessage: rpchandlers.HandleGetBlockTemplate, - appmessage.CmdNotifyBlockAddedRequestMessage: rpchandlers.HandleNotifyBlockAdded, - appmessage.CmdGetPeerAddressesRequestMessage: rpchandlers.HandleGetPeerAddresses, - appmessage.CmdGetSelectedTipHashRequestMessage: rpchandlers.HandleGetSelectedTipHash, - appmessage.CmdGetMempoolEntryRequestMessage: rpchandlers.HandleGetMempoolEntry, - appmessage.CmdGetConnectedPeerInfoRequestMessage: rpchandlers.HandleGetConnectedPeerInfo, - appmessage.CmdAddPeerRequestMessage: rpchandlers.HandleAddPeer, - appmessage.CmdSubmitTransactionRequestMessage: rpchandlers.HandleSubmitTransaction, - appmessage.CmdNotifyChainChangedRequestMessage: rpchandlers.HandleNotifyChainChanged, - appmessage.CmdGetBlockRequestMessage: rpchandlers.HandleGetBlock, - appmessage.CmdGetSubnetworkRequestMessage: rpchandlers.HandleGetSubnetwork, - appmessage.CmdGetChainFromBlockRequestMessage: rpchandlers.HandleGetChainFromBlock, - appmessage.CmdGetBlocksRequestMessage: rpchandlers.HandleGetBlocks, - appmessage.CmdGetBlockCountRequestMessage: rpchandlers.HandleGetBlockCount, - appmessage.CmdGetBlockDAGInfoRequestMessage: rpchandlers.HandleGetBlockDAGInfo, - appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict, - appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts, - appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries, - appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown, - appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders, + appmessage.CmdGetCurrentNetworkRequestMessage: rpchandlers.HandleGetCurrentNetwork, + appmessage.CmdSubmitBlockRequestMessage: rpchandlers.HandleSubmitBlock, + appmessage.CmdGetBlockTemplateRequestMessage: rpchandlers.HandleGetBlockTemplate, + appmessage.CmdNotifyBlockAddedRequestMessage: rpchandlers.HandleNotifyBlockAdded, + appmessage.CmdGetPeerAddressesRequestMessage: rpchandlers.HandleGetPeerAddresses, + appmessage.CmdGetSelectedTipHashRequestMessage: rpchandlers.HandleGetSelectedTipHash, + appmessage.CmdGetMempoolEntryRequestMessage: rpchandlers.HandleGetMempoolEntry, + appmessage.CmdGetConnectedPeerInfoRequestMessage: rpchandlers.HandleGetConnectedPeerInfo, + appmessage.CmdAddPeerRequestMessage: rpchandlers.HandleAddPeer, + appmessage.CmdSubmitTransactionRequestMessage: rpchandlers.HandleSubmitTransaction, + appmessage.CmdNotifyChainChangedRequestMessage: rpchandlers.HandleNotifyChainChanged, + appmessage.CmdGetBlockRequestMessage: rpchandlers.HandleGetBlock, + appmessage.CmdGetSubnetworkRequestMessage: rpchandlers.HandleGetSubnetwork, + appmessage.CmdGetChainFromBlockRequestMessage: rpchandlers.HandleGetChainFromBlock, + appmessage.CmdGetBlocksRequestMessage: rpchandlers.HandleGetBlocks, + appmessage.CmdGetBlockCountRequestMessage: rpchandlers.HandleGetBlockCount, + appmessage.CmdGetBlockDAGInfoRequestMessage: rpchandlers.HandleGetBlockDAGInfo, + appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict, + appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts, + appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries, + appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown, + appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders, + appmessage.CmdNotifyUTXOsChangedRequestMessage: rpchandlers.HandleNotifyUTXOsChanged, + appmessage.CmdGetUTXOsByAddressesRequestMessage: rpchandlers.HandleGetUTXOsByAddresses, + appmessage.CmdGetVirtualSelectedParentBlueScoreRequestMessage: rpchandlers.HandleGetVirtualSelectedParentBlueScore, + appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualSelectedParentBlueScoreChanged, } func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) { diff --git a/app/rpc/rpccontext/context.go b/app/rpc/rpccontext/context.go index 7850938ab..7a6035042 100644 --- a/app/rpc/rpccontext/context.go +++ b/app/rpc/rpccontext/context.go @@ -3,6 +3,7 @@ package rpccontext import ( "github.com/kaspanet/kaspad/app/protocol" "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/utxoindex" "github.com/kaspanet/kaspad/infrastructure/config" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" "github.com/kaspanet/kaspad/infrastructure/network/connmanager" @@ -17,6 +18,7 @@ type Context struct { ProtocolManager *protocol.Manager ConnectionManager *connmanager.ConnectionManager AddressManager *addressmanager.AddressManager + UTXOIndex *utxoindex.UTXOIndex ShutDownChan chan<- struct{} NotificationManager *NotificationManager @@ -29,6 +31,7 @@ func NewContext(cfg *config.Config, protocolManager *protocol.Manager, connectionManager *connmanager.ConnectionManager, addressManager *addressmanager.AddressManager, + utxoIndex *utxoindex.UTXOIndex, shutDownChan chan<- struct{}) *Context { context := &Context{ @@ -38,8 +41,10 @@ func NewContext(cfg *config.Config, ProtocolManager: protocolManager, ConnectionManager: connectionManager, AddressManager: addressManager, + UTXOIndex: utxoIndex, ShutDownChan: shutDownChan, } context.NotificationManager = NewNotificationManager() + return context } diff --git a/app/rpc/rpccontext/notificationmanager.go b/app/rpc/rpccontext/notificationmanager.go index f3f3adb4c..f69ac59a1 100644 --- a/app/rpc/rpccontext/notificationmanager.go +++ b/app/rpc/rpccontext/notificationmanager.go @@ -1,7 +1,9 @@ package rpccontext import ( + "encoding/hex" "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/utxoindex" routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" "sync" @@ -13,12 +15,23 @@ type NotificationManager struct { listeners map[*routerpkg.Router]*NotificationListener } +// UTXOsChangedNotificationAddress represents a kaspad address. +// This type is meant to be used in UTXOsChanged notifications +type UTXOsChangedNotificationAddress struct { + Address string + ScriptPublicKeyString utxoindex.ScriptPublicKeyString +} + // NotificationListener represents a registered RPC notification listener type NotificationListener struct { - propagateBlockAddedNotifications bool - propagateChainChangedNotifications bool - propagateFinalityConflictNotifications bool - propagateFinalityConflictResolvedNotifications bool + propagateBlockAddedNotifications bool + propagateChainChangedNotifications bool + propagateFinalityConflictNotifications bool + propagateFinalityConflictResolvedNotifications bool + propagateUTXOsChangedNotifications bool + propagateVirtualSelectedParentBlueScoreChangedNotifications bool + + propagateUTXOsChangedNotificationAddresses []*UTXOsChangedNotificationAddress } // NewNotificationManager creates a new NotificationManager @@ -123,12 +136,58 @@ func (nm *NotificationManager) NotifyFinalityConflictResolved(notification *appm return nil } +// NotifyUTXOsChanged notifies the notification manager that UTXOs have been changed +func (nm *NotificationManager) NotifyUTXOsChanged(utxoChanges *utxoindex.UTXOChanges) error { + nm.RLock() + defer nm.RUnlock() + + for router, listener := range nm.listeners { + if listener.propagateUTXOsChangedNotifications { + // Filter utxoChanges and create a notification + notification := listener.convertUTXOChangesToUTXOsChangedNotification(utxoChanges) + + // Don't send the notification if it's empty + if len(notification.Added) == 0 && len(notification.Removed) == 0 { + continue + } + + // Enqueue the notification + err := router.OutgoingRoute().Enqueue(notification) + if err != nil { + return err + } + } + } + return nil +} + +// NotifyVirtualSelectedParentBlueScoreChanged notifies the notification manager that the DAG's +// virtual selected parent blue score has changed +func (nm *NotificationManager) NotifyVirtualSelectedParentBlueScoreChanged( + notification *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) error { + + nm.RLock() + defer nm.RUnlock() + + for router, listener := range nm.listeners { + if listener.propagateVirtualSelectedParentBlueScoreChangedNotifications { + err := router.OutgoingRoute().Enqueue(notification) + if err != nil { + return err + } + } + } + return nil +} + func newNotificationListener() *NotificationListener { return &NotificationListener{ - propagateBlockAddedNotifications: false, - propagateChainChangedNotifications: false, - propagateFinalityConflictNotifications: false, - propagateFinalityConflictResolvedNotifications: false, + propagateBlockAddedNotifications: false, + propagateChainChangedNotifications: false, + propagateFinalityConflictNotifications: false, + propagateFinalityConflictResolvedNotifications: false, + propagateUTXOsChangedNotifications: false, + propagateVirtualSelectedParentBlueScoreChangedNotifications: false, } } @@ -155,3 +214,40 @@ func (nl *NotificationListener) PropagateFinalityConflictNotifications() { func (nl *NotificationListener) PropagateFinalityConflictResolvedNotifications() { nl.propagateFinalityConflictResolvedNotifications = true } + +// PropagateUTXOsChangedNotifications instructs the listener to send UTXOs changed notifications +// to the remote listener +func (nl *NotificationListener) PropagateUTXOsChangedNotifications(addresses []*UTXOsChangedNotificationAddress) { + nl.propagateUTXOsChangedNotifications = true + nl.propagateUTXOsChangedNotificationAddresses = addresses +} + +func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification( + utxoChanges *utxoindex.UTXOChanges) *appmessage.UTXOsChangedNotificationMessage { + + notification := &appmessage.UTXOsChangedNotificationMessage{} + for _, listenerAddress := range nl.propagateUTXOsChangedNotificationAddresses { + listenerScriptPublicKeyString := listenerAddress.ScriptPublicKeyString + if addedPairs, ok := utxoChanges.Added[listenerScriptPublicKeyString]; ok { + notification.Added = ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs) + } + if removedOutpoints, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok { + for outpoint := range removedOutpoints { + notification.Removed = append(notification.Removed, &appmessage.UTXOsByAddressesEntry{ + Address: listenerAddress.Address, + Outpoint: &appmessage.RPCOutpoint{ + TransactionID: hex.EncodeToString(outpoint.TransactionID[:]), + Index: outpoint.Index, + }, + }) + } + } + } + return notification +} + +// PropagateVirtualSelectedParentBlueScoreChangedNotifications instructs the listener to send +// virtual selected parent blue score notifications to the remote listener +func (nl *NotificationListener) PropagateVirtualSelectedParentBlueScoreChangedNotifications() { + nl.propagateVirtualSelectedParentBlueScoreChangedNotifications = true +} diff --git a/app/rpc/rpccontext/utxos_by_addresses.go b/app/rpc/rpccontext/utxos_by_addresses.go new file mode 100644 index 000000000..b4ead0d75 --- /dev/null +++ b/app/rpc/rpccontext/utxos_by_addresses.go @@ -0,0 +1,29 @@ +package rpccontext + +import ( + "encoding/hex" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/utxoindex" +) + +// ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries converts +// UTXOOutpointEntryPairs to a slice of UTXOsByAddressesEntry +func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pairs utxoindex.UTXOOutpointEntryPairs) []*appmessage.UTXOsByAddressesEntry { + utxosByAddressesEntries := make([]*appmessage.UTXOsByAddressesEntry, 0, len(pairs)) + for outpoint, utxoEntry := range pairs { + utxosByAddressesEntries = append(utxosByAddressesEntries, &appmessage.UTXOsByAddressesEntry{ + Address: address, + Outpoint: &appmessage.RPCOutpoint{ + TransactionID: hex.EncodeToString(outpoint.TransactionID[:]), + Index: outpoint.Index, + }, + UTXOEntry: &appmessage.RPCUTXOEntry{ + Amount: utxoEntry.Amount(), + ScriptPubKey: hex.EncodeToString(utxoEntry.ScriptPublicKey()), + BlockBlueScore: utxoEntry.BlockBlueScore(), + IsCoinbase: utxoEntry.IsCoinbase(), + }, + }) + } + return utxosByAddressesEntries +} diff --git a/app/rpc/rpchandlers/get_utxos_by_addresses.go b/app/rpc/rpchandlers/get_utxos_by_addresses.go new file mode 100644 index 000000000..3fde76143 --- /dev/null +++ b/app/rpc/rpchandlers/get_utxos_by_addresses.go @@ -0,0 +1,45 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/kaspanet/kaspad/util" +) + +// HandleGetUTXOsByAddresses handles the respectively named RPC command +func HandleGetUTXOsByAddresses(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { + if !context.Config.UTXOIndex { + errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex") + return errorMessage, nil + } + + getUTXOsByAddressesRequest := request.(*appmessage.GetUTXOsByAddressesRequestMessage) + + allEntries := make([]*appmessage.UTXOsByAddressesEntry, 0) + for _, addressString := range getUTXOsByAddressesRequest.Addresses { + address, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix) + if err != nil { + errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err) + return errorMessage, nil + } + scriptPublicKey, err := txscript.PayToAddrScript(address) + if err != nil { + errorMessage := &appmessage.GetUTXOsByAddressesResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err) + return errorMessage, nil + } + utxoOutpointEntryPairs, err := context.UTXOIndex.UTXOs(scriptPublicKey) + if err != nil { + return nil, err + } + entries := rpccontext.ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(addressString, utxoOutpointEntryPairs) + allEntries = append(allEntries, entries...) + } + + response := appmessage.NewGetUTXOsByAddressesResponseMessage(allEntries) + return response, nil +} diff --git a/app/rpc/rpchandlers/get_virtual_selected_parent_blue_score.go b/app/rpc/rpchandlers/get_virtual_selected_parent_blue_score.go new file mode 100644 index 000000000..4500bf09e --- /dev/null +++ b/app/rpc/rpchandlers/get_virtual_selected_parent_blue_score.go @@ -0,0 +1,16 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleGetVirtualSelectedParentBlueScore handles the respectively named RPC command +func HandleGetVirtualSelectedParentBlueScore(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { + virtualInfo, err := context.Domain.Consensus().GetVirtualInfo() + if err != nil { + return nil, err + } + return appmessage.NewGetVirtualSelectedParentBlueScoreResponseMessage(virtualInfo.BlueScore), nil +} diff --git a/app/rpc/rpchandlers/notify_utxos_changed.go b/app/rpc/rpchandlers/notify_utxos_changed.go new file mode 100644 index 000000000..e3acb31dd --- /dev/null +++ b/app/rpc/rpchandlers/notify_utxos_changed.go @@ -0,0 +1,51 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/domain/utxoindex" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/kaspanet/kaspad/util" +) + +// HandleNotifyUTXOsChanged handles the respectively named RPC command +func HandleNotifyUTXOsChanged(context *rpccontext.Context, router *router.Router, request appmessage.Message) (appmessage.Message, error) { + if !context.Config.UTXOIndex { + errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() + errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex") + return errorMessage, nil + } + + notifyUTXOsChangedRequest := request.(*appmessage.NotifyUTXOsChangedRequestMessage) + + addresses := make([]*rpccontext.UTXOsChangedNotificationAddress, len(notifyUTXOsChangedRequest.Addresses)) + for i, addressString := range notifyUTXOsChangedRequest.Addresses { + address, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix) + if err != nil { + errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() + errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err) + return errorMessage, nil + } + scriptPublicKey, err := txscript.PayToAddrScript(address) + if err != nil { + errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() + errorMessage.Error = appmessage.RPCErrorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err) + return errorMessage, nil + } + scriptPublicKeyString := utxoindex.ConvertScriptPublicKeyToString(scriptPublicKey) + addresses[i] = &rpccontext.UTXOsChangedNotificationAddress{ + Address: addressString, + ScriptPublicKeyString: scriptPublicKeyString, + } + } + + listener, err := context.NotificationManager.Listener(router) + if err != nil { + return nil, err + } + listener.PropagateUTXOsChangedNotifications(addresses) + + response := appmessage.NewNotifyUTXOsChangedResponseMessage() + return response, nil +} diff --git a/app/rpc/rpchandlers/notify_virtual_selected_parent_blue_score_changed.go b/app/rpc/rpchandlers/notify_virtual_selected_parent_blue_score_changed.go new file mode 100644 index 000000000..73ea4363e --- /dev/null +++ b/app/rpc/rpchandlers/notify_virtual_selected_parent_blue_score_changed.go @@ -0,0 +1,19 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleNotifyVirtualSelectedParentBlueScoreChanged handles the respectively named RPC command +func HandleNotifyVirtualSelectedParentBlueScoreChanged(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) { + listener, err := context.NotificationManager.Listener(router) + if err != nil { + return nil, err + } + listener.PropagateVirtualSelectedParentBlueScoreChangedNotifications() + + response := appmessage.NewNotifyVirtualSelectedParentBlueScoreChangedResponseMessage() + return response, nil +} diff --git a/app/rpc/rpchandlers/submit_transaction.go b/app/rpc/rpchandlers/submit_transaction.go index 46e4437eb..e7174c60e 100644 --- a/app/rpc/rpchandlers/submit_transaction.go +++ b/app/rpc/rpchandlers/submit_transaction.go @@ -13,9 +13,15 @@ import ( func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { submitTransactionRequest := request.(*appmessage.SubmitTransactionRequestMessage) - domainTransaction := appmessage.MsgTxToDomainTransaction(submitTransactionRequest.Transaction) + domainTransaction, err := appmessage.RPCTransactionToDomainTransaction(submitTransactionRequest.Transaction) + if err != nil { + errorMessage := &appmessage.SubmitTransactionResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not parse transaction: %s", err) + return errorMessage, nil + } + transactionID := consensushashing.TransactionID(domainTransaction) - err := context.ProtocolManager.AddTransaction(domainTransaction) + err = context.ProtocolManager.AddTransaction(domainTransaction) if err != nil { if !errors.As(err, &mempool.RuleError{}) { return nil, err diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index a9dca69f2..9643ed182 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -141,6 +141,13 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap return blockInfo, nil } +func (s *consensus) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) { + s.lock.Lock() + defer s.lock.Unlock() + + return s.acceptanceDataStore.Get(s.databaseContext, blockHash) +} + func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { s.lock.Lock() defer s.lock.Unlock() @@ -196,10 +203,16 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) } func (s *consensus) Tips() ([]*externalapi.DomainHash, error) { + s.lock.Lock() + defer s.lock.Unlock() + return s.consensusStateStore.Tips(s.databaseContext) } func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) { + s.lock.Lock() + defer s.lock.Unlock() + blockRelations, err := s.blockRelationStore.BlockRelation(s.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err @@ -212,11 +225,16 @@ func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) { if err != nil { return nil, err } + virtualGHOSTDAGData, err := s.ghostdagDataStore.Get(s.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } return &externalapi.VirtualInfo{ ParentHashes: blockRelations.Parents, Bits: bits, PastMedianTime: pastMedianTime, + BlueScore: virtualGHOSTDAGData.BlueScore(), }, nil } diff --git a/domain/consensus/database/serialization/acceptancedata.go b/domain/consensus/database/serialization/acceptancedata.go index ee41752e7..56730436a 100644 --- a/domain/consensus/database/serialization/acceptancedata.go +++ b/domain/consensus/database/serialization/acceptancedata.go @@ -1,9 +1,11 @@ package serialization -import "github.com/kaspanet/kaspad/domain/consensus/model" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // DomainAcceptanceDataToDbAcceptanceData converts model.AcceptanceData to DbAcceptanceData -func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData model.AcceptanceData) *DbAcceptanceData { +func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData externalapi.AcceptanceData) *DbAcceptanceData { dbBlockAcceptanceData := make([]*DbBlockAcceptanceData, len(domainAcceptanceData)) for i, blockAcceptanceData := range domainAcceptanceData { dbTransactionAcceptanceData := make([]*DbTransactionAcceptanceData, @@ -29,10 +31,10 @@ func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData model.Acceptanc } // DbAcceptanceDataToDomainAcceptanceData converts DbAcceptanceData to model.AcceptanceData -func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) (model.AcceptanceData, error) { - domainAcceptanceData := make(model.AcceptanceData, len(dbAcceptanceData.BlockAcceptanceData)) +func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) (externalapi.AcceptanceData, error) { + domainAcceptanceData := make(externalapi.AcceptanceData, len(dbAcceptanceData.BlockAcceptanceData)) for i, dbBlockAcceptanceData := range dbAcceptanceData.BlockAcceptanceData { - domainTransactionAcceptanceData := make([]*model.TransactionAcceptanceData, + domainTransactionAcceptanceData := make([]*externalapi.TransactionAcceptanceData, len(dbBlockAcceptanceData.TransactionAcceptanceData)) for j, dbTransactionAcceptanceData := range dbBlockAcceptanceData.TransactionAcceptanceData { @@ -40,14 +42,14 @@ func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) if err != nil { return nil, err } - domainTransactionAcceptanceData[j] = &model.TransactionAcceptanceData{ + domainTransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{ Transaction: domainTransaction, Fee: dbTransactionAcceptanceData.Fee, IsAccepted: dbTransactionAcceptanceData.IsAccepted, } } - domainAcceptanceData[i] = &model.BlockAcceptanceData{ + domainAcceptanceData[i] = &externalapi.BlockAcceptanceData{ TransactionAcceptanceData: domainTransactionAcceptanceData, } } diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index f19a4402a..ce824e215 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -13,7 +13,7 @@ var bucket = dbkeys.MakeBucket([]byte("acceptance-data")) // acceptanceDataStore represents a store of AcceptanceData type acceptanceDataStore struct { - staging map[externalapi.DomainHash]model.AcceptanceData + staging map[externalapi.DomainHash]externalapi.AcceptanceData toDelete map[externalapi.DomainHash]struct{} cache *lrucache.LRUCache } @@ -21,14 +21,14 @@ type acceptanceDataStore struct { // New instantiates a new AcceptanceDataStore func New(cacheSize int) model.AcceptanceDataStore { return &acceptanceDataStore{ - staging: make(map[externalapi.DomainHash]model.AcceptanceData), + staging: make(map[externalapi.DomainHash]externalapi.AcceptanceData), toDelete: make(map[externalapi.DomainHash]struct{}), cache: lrucache.New(cacheSize), } } // Stage stages the given acceptanceData for the given blockHash -func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) { +func (ads *acceptanceDataStore) Stage(blockHash *externalapi.DomainHash, acceptanceData externalapi.AcceptanceData) { ads.staging[*blockHash] = acceptanceData.Clone() } @@ -37,7 +37,7 @@ func (ads *acceptanceDataStore) IsStaged() bool { } func (ads *acceptanceDataStore) Discard() { - ads.staging = make(map[externalapi.DomainHash]model.AcceptanceData) + ads.staging = make(map[externalapi.DomainHash]externalapi.AcceptanceData) ads.toDelete = make(map[externalapi.DomainHash]struct{}) } @@ -67,13 +67,13 @@ func (ads *acceptanceDataStore) Commit(dbTx model.DBTransaction) error { } // Get gets the acceptanceData associated with the given blockHash -func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.AcceptanceData, error) { +func (ads *acceptanceDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) { if acceptanceData, ok := ads.staging[*blockHash]; ok { return acceptanceData.Clone(), nil } if acceptanceData, ok := ads.cache.Get(blockHash); ok { - return acceptanceData.(model.AcceptanceData).Clone(), nil + return acceptanceData.(externalapi.AcceptanceData).Clone(), nil } acceptanceDataBytes, err := dbContext.Get(ads.hashAsKey(blockHash)) @@ -98,12 +98,12 @@ func (ads *acceptanceDataStore) Delete(blockHash *externalapi.DomainHash) { ads.toDelete[*blockHash] = struct{}{} } -func (ads *acceptanceDataStore) serializeAcceptanceData(acceptanceData model.AcceptanceData) ([]byte, error) { +func (ads *acceptanceDataStore) serializeAcceptanceData(acceptanceData externalapi.AcceptanceData) ([]byte, error) { dbAcceptanceData := serialization.DomainAcceptanceDataToDbAcceptanceData(acceptanceData) return proto.Marshal(dbAcceptanceData) } -func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes []byte) (model.AcceptanceData, error) { +func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes []byte) (externalapi.AcceptanceData, error) { dbAcceptanceData := &serialization.DbAcceptanceData{} err := proto.Unmarshal(acceptanceDataBytes, dbAcceptanceData) if err != nil { diff --git a/domain/consensus/model/acceptancedata.go b/domain/consensus/model/externalapi/acceptancedata.go similarity index 92% rename from domain/consensus/model/acceptancedata.go rename to domain/consensus/model/externalapi/acceptancedata.go index 27f79c329..8ec60d112 100644 --- a/domain/consensus/model/acceptancedata.go +++ b/domain/consensus/model/externalapi/acceptancedata.go @@ -1,6 +1,4 @@ -package model - -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +package externalapi // AcceptanceData stores data about which transactions were accepted by a block. // It's ordered in the same way as the block merge set blues. @@ -42,7 +40,7 @@ func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData { // TransactionAcceptanceData stores a transaction together with an indication // if it was accepted or not by some block type TransactionAcceptanceData struct { - Transaction *externalapi.DomainTransaction + Transaction *DomainTransaction Fee uint64 IsAccepted bool } diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 3a24edc7e..1628b0737 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -9,6 +9,7 @@ type Consensus interface { GetBlock(blockHash *DomainHash) (*DomainBlock, error) GetBlockHeader(blockHash *DomainHash) (*DomainBlockHeader, error) GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error) + GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error) GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error) GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) diff --git a/domain/consensus/model/externalapi/virtual.go b/domain/consensus/model/externalapi/virtual.go index b35ec4342..4391ce5b5 100644 --- a/domain/consensus/model/externalapi/virtual.go +++ b/domain/consensus/model/externalapi/virtual.go @@ -5,4 +5,5 @@ type VirtualInfo struct { ParentHashes []*DomainHash Bits uint32 PastMedianTime int64 + BlueScore uint64 } diff --git a/domain/consensus/model/interface_datastructures_acceptancedatastore.go b/domain/consensus/model/interface_datastructures_acceptancedatastore.go index 4d75e1225..53a3c5925 100644 --- a/domain/consensus/model/interface_datastructures_acceptancedatastore.go +++ b/domain/consensus/model/interface_datastructures_acceptancedatastore.go @@ -5,8 +5,8 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // AcceptanceDataStore represents a store of AcceptanceData type AcceptanceDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, acceptanceData AcceptanceData) + Stage(blockHash *externalapi.DomainHash, acceptanceData externalapi.AcceptanceData) IsStaged() bool - Get(dbContext DBReader, blockHash *externalapi.DomainHash) (AcceptanceData, error) + Get(dbContext DBReader, blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) Delete(blockHash *externalapi.DomainHash) } diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index c7d51c122..08367b299 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -8,5 +8,5 @@ type ConsensusStateManager interface { PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) - CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error) + CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, externalapi.AcceptanceData, Multiset, error) } diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 515465dce..78b4bb119 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -182,7 +182,7 @@ func (bb *blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, return bb.calculateAcceptedIDMerkleRoot(newBlockAcceptanceData) } -func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.AcceptanceData) (*externalapi.DomainHash, error) { +func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData externalapi.AcceptanceData) (*externalapi.DomainHash, error) { var acceptedTransactions []*externalapi.DomainTransaction for _, blockAcceptanceData := range acceptanceData { for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData { diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 78e5a56ca..3248fcfa9 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -40,7 +40,7 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do } func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, - transactions []*externalapi.DomainTransaction, acceptanceData model.AcceptanceData, multiset model.Multiset) ( + transactions []*externalapi.DomainTransaction, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) ( *externalapi.DomainBlockHeader, error) { timeInMilliseconds, err := bb.minBlockTime(tempBlockHash) diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index 268a23421..21c66980b 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -65,7 +65,7 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom // 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, - blockAcceptanceData *model.BlockAcceptanceData) (*externalapi.DomainTransactionOutput, bool, error) { + blockAcceptanceData *externalapi.BlockAcceptanceData) (*externalapi.DomainTransactionOutput, bool, error) { totalFees := uint64(0) for _, txAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index c092a9b51..addb85ff2 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -13,7 +13,7 @@ import ( ) func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( - model.UTXODiff, model.AcceptanceData, model.Multiset, error) { + model.UTXODiff, externalapi.AcceptanceData, model.Multiset, error) { log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) @@ -21,7 +21,7 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * if *blockHash == *csm.genesisHash { log.Tracef("Block %s is the genesis. By definition, "+ "it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash) - return utxo.NewUTXODiff(), model.AcceptanceData{}, multiset.New(), nil + return utxo.NewUTXODiff(), externalapi.AcceptanceData{}, multiset.New(), nil } blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash) @@ -109,7 +109,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash, selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) ( - model.AcceptanceData, model.MutableUTXODiff, error) { + externalapi.AcceptanceData, model.MutableUTXODiff, error) { log.Tracef("applyBlueBlocks start for block %s", blockHash) defer log.Tracef("applyBlueBlocks end for block %s", blockHash) @@ -125,15 +125,15 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH } log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime) - multiblockAcceptanceData := make(model.AcceptanceData, len(blueBlocks)) + multiblockAcceptanceData := make(externalapi.AcceptanceData, len(blueBlocks)) accumulatedUTXODiff := selectedParentPastUTXODiff accumulatedMass := uint64(0) for i, blueBlock := range blueBlocks { blueBlockHash := consensushashing.BlockHash(blueBlock) log.Tracef("Applying blue block %s", blueBlockHash) - blockAcceptanceData := &model.BlockAcceptanceData{ - TransactionAcceptanceData: make([]*model.TransactionAcceptanceData, len(blueBlock.Transactions)), + blockAcceptanceData := &externalapi.BlockAcceptanceData{ + TransactionAcceptanceData: make([]*externalapi.TransactionAcceptanceData, len(blueBlock.Transactions)), } isSelectedParent := i == 0 log.Tracef("Is blue block %s the selected parent: %t", blueBlockHash, isSelectedParent) @@ -153,7 +153,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH log.Tracef("Transaction %s in block %s isAccepted: %t, fee: %d", transactionID, blueBlockHash, isAccepted, transaction.Fee) - blockAcceptanceData.TransactionAcceptanceData[j] = &model.TransactionAcceptanceData{ + blockAcceptanceData.TransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{ Transaction: transaction, Fee: transaction.Fee, IsAccepted: isAccepted, diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index bb3f1a91b..a0c74d3b7 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -10,7 +10,7 @@ import ( ) func (csm *consensusStateManager) calculateMultiset( - acceptanceData model.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) { + acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) { log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index f28ab7ba2..c5a0eef2c 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -18,7 +18,7 @@ import ( ) func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, - pastUTXODiff model.UTXODiff, acceptanceData model.AcceptanceData, multiset model.Multiset) error { + pastUTXODiff model.UTXODiff, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) error { log.Tracef("verifyUTXO start for block %s", blockHash) defer log.Tracef("verifyUTXO end for block %s", blockHash) @@ -97,7 +97,7 @@ func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block } func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalapi.DomainBlock, - blockHash *externalapi.DomainHash, acceptanceData model.AcceptanceData) error { + blockHash *externalapi.DomainHash, acceptanceData externalapi.AcceptanceData) error { log.Tracef("validateAcceptedIDMerkleRoot start for block %s", blockHash) defer log.Tracef("validateAcceptedIDMerkleRoot end for block %s", blockHash) @@ -127,7 +127,7 @@ func (csm *consensusStateManager) validateUTXOCommitment( return nil } -func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData model.AcceptanceData) *externalapi.DomainHash { +func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData externalapi.AcceptanceData) *externalapi.DomainHash { log.Tracef("calculateAcceptedIDMerkleRoot start") defer log.Tracef("calculateAcceptedIDMerkleRoot end") diff --git a/domain/utxoindex/log.go b/domain/utxoindex/log.go new file mode 100644 index 000000000..8692e6ba5 --- /dev/null +++ b/domain/utxoindex/log.go @@ -0,0 +1,11 @@ +// Copyright (c) 2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package utxoindex + +import ( + "github.com/kaspanet/kaspad/infrastructure/logger" +) + +var log, _ = logger.Get(logger.SubsystemTags.INDX) diff --git a/domain/utxoindex/model.go b/domain/utxoindex/model.go new file mode 100644 index 000000000..c8ded415f --- /dev/null +++ b/domain/utxoindex/model.go @@ -0,0 +1,33 @@ +package utxoindex + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// ScriptPublicKeyString is a script public key represented as a string +// We use this type rather than just a byte slice because Go maps don't +// support slices as keys. See: UTXOChanges +type ScriptPublicKeyString string + +// UTXOOutpointEntryPairs is a map between UTXO outpoints to UTXO entries +type UTXOOutpointEntryPairs map[externalapi.DomainOutpoint]externalapi.UTXOEntry + +// UTXOOutpoints is a set of UTXO outpoints +type UTXOOutpoints map[externalapi.DomainOutpoint]interface{} + +// UTXOChanges is the set of changes made to the UTXO index after +// a successful update +type UTXOChanges struct { + Added map[ScriptPublicKeyString]UTXOOutpointEntryPairs + Removed map[ScriptPublicKeyString]UTXOOutpoints +} + +// ConvertScriptPublicKeyToString converts the given scriptPublicKey to a string +func ConvertScriptPublicKeyToString(scriptPublicKey []byte) ScriptPublicKeyString { + return ScriptPublicKeyString(scriptPublicKey) +} + +// ConvertStringToScriptPublicKey converts the given string to a scriptPublicKey byte slice +func ConvertStringToScriptPublicKey(string ScriptPublicKeyString) []byte { + return []byte(string) +} diff --git a/domain/utxoindex/store.go b/domain/utxoindex/store.go new file mode 100644 index 000000000..e09a4b1be --- /dev/null +++ b/domain/utxoindex/store.go @@ -0,0 +1,255 @@ +package utxoindex + +import ( + "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database/serialization" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" +) + +var utxoIndexBucket = database.MakeBucket([]byte("utxo-index")) + +type utxoIndexStore struct { + database database.Database + toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs + toRemove map[ScriptPublicKeyString]UTXOOutpoints +} + +func newUTXOIndexStore(database database.Database) *utxoIndexStore { + return &utxoIndexStore{ + database: database, + toAdd: make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs), + toRemove: make(map[ScriptPublicKeyString]UTXOOutpoints), + } +} + +func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry) error { + key := ConvertScriptPublicKeyToString(scriptPublicKey) + log.Tracef("Adding outpoint %s:%d to scriptPublicKey %s", + outpoint.TransactionID, outpoint.Index, key) + + // If the outpoint exists in `toRemove` simply remove it from there and return + if toRemoveOutpointsOfKey, ok := uis.toRemove[key]; ok { + if _, ok := toRemoveOutpointsOfKey[*outpoint]; ok { + log.Tracef("Outpoint %s:%d exists in `toRemove`. Deleting it from there", + outpoint.TransactionID, outpoint.Index) + delete(toRemoveOutpointsOfKey, *outpoint) + return nil + } + } + + // Create a UTXOOutpointEntryPairs entry in `toAdd` if it doesn't exist + if _, ok := uis.toAdd[key]; !ok { + log.Tracef("Creating key %s in `toAdd`", key) + uis.toAdd[key] = make(UTXOOutpointEntryPairs) + } + + // Return an error if the outpoint already exists in `toAdd` + toAddPairsOfKey := uis.toAdd[key] + if _, ok := toAddPairsOfKey[*outpoint]; ok { + return errors.Errorf("cannot add outpoint %s because it's being added already", outpoint) + } + + toAddPairsOfKey[*outpoint] = *utxoEntry + + log.Tracef("Added outpoint %s:%d to scriptPublicKey %s", + outpoint.TransactionID, outpoint.Index, key) + return nil +} + +func (uis *utxoIndexStore) remove(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint) error { + key := ConvertScriptPublicKeyToString(scriptPublicKey) + log.Tracef("Removing outpoint %s:%d from scriptPublicKey %s", + outpoint.TransactionID, outpoint.Index, key) + + // If the outpoint exists in `toAdd` simply remove it from there and return + if toAddPairsOfKey, ok := uis.toAdd[key]; ok { + if _, ok := toAddPairsOfKey[*outpoint]; ok { + log.Tracef("Outpoint %s:%d exists in `toAdd`. Deleting it from there", + outpoint.TransactionID, outpoint.Index) + delete(toAddPairsOfKey, *outpoint) + return nil + } + } + + // Create a UTXOOutpoints entry in `toRemove` if it doesn't exist + if _, ok := uis.toRemove[key]; !ok { + log.Tracef("Creating key %s in `toRemove`", key) + uis.toRemove[key] = make(UTXOOutpoints) + } + + // Return an error if the outpoint already exists in `toRemove` + toRemoveOutpointsOfKey := uis.toRemove[key] + if _, ok := toRemoveOutpointsOfKey[*outpoint]; ok { + return errors.Errorf("cannot remove outpoint %s because it's being removed already", outpoint) + } + + toRemoveOutpointsOfKey[*outpoint] = struct{}{} + + log.Tracef("Removed outpoint %s:%d from scriptPublicKey %s", + outpoint.TransactionID, outpoint.Index, key) + return nil +} + +func (uis *utxoIndexStore) discard() { + uis.toAdd = make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs) + uis.toRemove = make(map[ScriptPublicKeyString]UTXOOutpoints) +} + +func (uis *utxoIndexStore) commit() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "utxoIndexStore.commit") + defer onEnd() + + dbTransaction, err := uis.database.Begin() + if err != nil { + return err + } + defer dbTransaction.RollbackUnlessClosed() + + for scriptPublicKeyString, toRemoveOutpointsOfKey := range uis.toRemove { + scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString) + bucket := uis.bucketForScriptPublicKey(scriptPublicKey) + for outpointToRemove := range toRemoveOutpointsOfKey { + key, err := uis.convertOutpointToKey(bucket, &outpointToRemove) + if err != nil { + return err + } + err = dbTransaction.Delete(key) + if err != nil { + return err + } + } + } + + for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd { + scriptPublicKey := ConvertStringToScriptPublicKey(scriptPublicKeyString) + bucket := uis.bucketForScriptPublicKey(scriptPublicKey) + for outpointToAdd, utxoEntryToAdd := range toAddUTXOOutpointEntryPairs { + key, err := uis.convertOutpointToKey(bucket, &outpointToAdd) + if err != nil { + return err + } + serializedUTXOEntry, err := uis.serializeUTXOEntry(utxoEntryToAdd) + if err != nil { + return err + } + err = dbTransaction.Put(key, serializedUTXOEntry) + if err != nil { + return err + } + } + } + + err = dbTransaction.Commit() + if err != nil { + return err + } + + uis.discard() + return nil +} + +func (uis *utxoIndexStore) bucketForScriptPublicKey(scriptPublicKey []byte) *database.Bucket { + return utxoIndexBucket.Bucket(scriptPublicKey) +} + +func (uis *utxoIndexStore) convertOutpointToKey(bucket *database.Bucket, outpoint *externalapi.DomainOutpoint) (*database.Key, error) { + serializedOutpoint, err := uis.serializeOutpoint(outpoint) + if err != nil { + return nil, err + } + return bucket.Key(serializedOutpoint), nil +} + +func (uis *utxoIndexStore) convertKeyToOutpoint(key *database.Key) (*externalapi.DomainOutpoint, error) { + serializedOutpoint := key.Suffix() + return uis.deserializeOutpoint(serializedOutpoint) +} + +func (uis *utxoIndexStore) serializeOutpoint(outpoint *externalapi.DomainOutpoint) ([]byte, error) { + dbOutpoint := serialization.DomainOutpointToDbOutpoint(outpoint) + return proto.Marshal(dbOutpoint) +} + +func (uis *utxoIndexStore) deserializeOutpoint(serializedOutpoint []byte) (*externalapi.DomainOutpoint, error) { + var dbOutpoint serialization.DbOutpoint + err := proto.Unmarshal(serializedOutpoint, &dbOutpoint) + if err != nil { + return nil, err + } + return serialization.DbOutpointToDomainOutpoint(&dbOutpoint) +} + +func (uis *utxoIndexStore) serializeUTXOEntry(utxoEntry externalapi.UTXOEntry) ([]byte, error) { + dbUTXOEntry := serialization.UTXOEntryToDBUTXOEntry(utxoEntry) + return proto.Marshal(dbUTXOEntry) +} + +func (uis *utxoIndexStore) deserializeUTXOEntry(serializedUTXOEntry []byte) (externalapi.UTXOEntry, error) { + var dbUTXOEntry serialization.DbUtxoEntry + err := proto.Unmarshal(serializedUTXOEntry, &dbUTXOEntry) + if err != nil { + return nil, err + } + return serialization.DBUTXOEntryToUTXOEntry(&dbUTXOEntry), nil +} + +func (uis *utxoIndexStore) stagedData() ( + toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs, + toRemove map[ScriptPublicKeyString]UTXOOutpoints) { + + toAddClone := make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs, len(uis.toAdd)) + for scriptPublicKeyString, toAddUTXOOutpointEntryPairs := range uis.toAdd { + toAddUTXOOutpointEntryPairsClone := make(UTXOOutpointEntryPairs, len(toAddUTXOOutpointEntryPairs)) + for outpoint, utxoEntry := range toAddUTXOOutpointEntryPairs { + toAddUTXOOutpointEntryPairsClone[outpoint] = utxoEntry + } + toAddClone[scriptPublicKeyString] = toAddUTXOOutpointEntryPairsClone + } + + toRemoveClone := make(map[ScriptPublicKeyString]UTXOOutpoints, len(uis.toRemove)) + for scriptPublicKeyString, toRemoveOutpoints := range uis.toRemove { + toRemoveOutpointsClone := make(UTXOOutpoints, len(toRemoveOutpoints)) + for outpoint := range toRemoveOutpoints { + toRemoveOutpointsClone[outpoint] = struct{}{} + } + toRemoveClone[scriptPublicKeyString] = toRemoveOutpointsClone + } + + return toAddClone, toRemoveClone +} + +func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) { + if len(uis.toAdd) > 0 || len(uis.toRemove) > 0 { + return nil, errors.Errorf("cannot get utxo outpoint entry pairs while staging isn't empty") + } + + bucket := uis.bucketForScriptPublicKey(scriptPublicKey) + cursor, err := uis.database.Cursor(bucket) + if err != nil { + return nil, err + } + utxoOutpointEntryPairs := make(UTXOOutpointEntryPairs) + for cursor.Next() { + key, err := cursor.Key() + if err != nil { + return nil, err + } + outpoint, err := uis.convertKeyToOutpoint(key) + if err != nil { + return nil, err + } + serializedUTXOEntry, err := cursor.Value() + if err != nil { + return nil, err + } + utxoEntry, err := uis.deserializeUTXOEntry(serializedUTXOEntry) + if err != nil { + return nil, err + } + utxoOutpointEntryPairs[*outpoint] = utxoEntry + } + return utxoOutpointEntryPairs, nil +} diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go new file mode 100644 index 000000000..8e2666fe5 --- /dev/null +++ b/domain/utxoindex/utxoindex.go @@ -0,0 +1,168 @@ +package utxoindex + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/kaspanet/kaspad/infrastructure/logger" + "sync" +) + +// UTXOIndex maintains an index between transaction scriptPublicKeys +// and UTXOs +type UTXOIndex struct { + consensus externalapi.Consensus + store *utxoIndexStore + + mutex sync.Mutex +} + +// New creates a new UTXO index +func New(consensus externalapi.Consensus, database database.Database) *UTXOIndex { + store := newUTXOIndexStore(database) + return &UTXOIndex{ + consensus: consensus, + store: store, + } +} + +// Update updates the UTXO index with the given DAG selected parent chain changes +func (ui *UTXOIndex) Update(chainChanges *externalapi.SelectedParentChainChanges) (*UTXOChanges, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.Update") + defer onEnd() + + ui.mutex.Lock() + defer ui.mutex.Unlock() + + log.Tracef("Updating UTXO index with chainChanges: %+v", chainChanges) + for _, removedBlockHash := range chainChanges.Removed { + err := ui.removeBlock(removedBlockHash) + if err != nil { + return nil, err + } + } + for _, addedBlockHash := range chainChanges.Added { + err := ui.addBlock(addedBlockHash) + if err != nil { + return nil, err + } + } + + added, removed := ui.store.stagedData() + utxoIndexChanges := &UTXOChanges{ + Added: added, + Removed: removed, + } + + err := ui.store.commit() + if err != nil { + return nil, err + } + + log.Tracef("UTXO index updated with the UTXOChanged: %+v", utxoIndexChanges) + return utxoIndexChanges, nil +} + +func (ui *UTXOIndex) addBlock(blockHash *externalapi.DomainHash) error { + log.Tracef("Adding block %s to UTXO index", blockHash) + acceptanceData, err := ui.consensus.GetBlockAcceptanceData(blockHash) + if err != nil { + return err + } + blockInfo, err := ui.consensus.GetBlockInfo(blockHash) + if err != nil { + return err + } + for _, blockAcceptanceData := range acceptanceData { + for _, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { + if !transactionAcceptanceData.IsAccepted { + continue + } + err := ui.addTransaction(transactionAcceptanceData.Transaction, blockInfo.BlueScore) + if err != nil { + return err + } + } + } + return nil +} + +func (ui *UTXOIndex) removeBlock(blockHash *externalapi.DomainHash) error { + log.Tracef("Removing block %s from UTXO index", blockHash) + acceptanceData, err := ui.consensus.GetBlockAcceptanceData(blockHash) + if err != nil { + return err + } + for _, blockAcceptanceData := range acceptanceData { + for _, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { + if !transactionAcceptanceData.IsAccepted { + continue + } + err := ui.removeTransaction(transactionAcceptanceData.Transaction) + if err != nil { + return err + } + } + } + return nil +} + +func (ui *UTXOIndex) addTransaction(transaction *externalapi.DomainTransaction, blockBlueScore uint64) error { + transactionID := consensushashing.TransactionID(transaction) + log.Tracef("Adding transaction %s to UTXO index", transactionID) + + isCoinbase := transactionhelper.IsCoinBase(transaction) + for _, transactionInput := range transaction.Inputs { + log.Tracef("Removing outpoint %s:%d from UTXO index", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) + err := ui.store.remove(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint) + if err != nil { + return err + } + } + for index, transactionOutput := range transaction.Outputs { + log.Tracef("Adding outpoint %s:%d to UTXO index", transactionID, index) + outpoint := externalapi.NewDomainOutpoint(transactionID, uint32(index)) + utxoEntry := utxo.NewUTXOEntry(transactionOutput.Value, transactionOutput.ScriptPublicKey, isCoinbase, blockBlueScore) + err := ui.store.add(transactionOutput.ScriptPublicKey, outpoint, &utxoEntry) + if err != nil { + return err + } + } + return nil +} + +func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransaction) error { + transactionID := consensushashing.TransactionID(transaction) + log.Tracef("Removing transaction %s from UTXO index", transactionID) + for index, transactionOutput := range transaction.Outputs { + log.Tracef("Removing outpoint %s:%d from UTXO index", transactionID, index) + outpoint := externalapi.NewDomainOutpoint(transactionID, uint32(index)) + err := ui.store.remove(transactionOutput.ScriptPublicKey, outpoint) + if err != nil { + return err + } + } + for _, transactionInput := range transaction.Inputs { + log.Tracef("Adding outpoint %s:%d to UTXO index", + transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) + err := ui.store.add(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint, &transactionInput.UTXOEntry) + if err != nil { + return err + } + } + return nil +} + +// UTXOs returns all the UTXOs for the given scriptPublicKey +func (ui *UTXOIndex) UTXOs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.UTXOs") + defer onEnd() + + ui.mutex.Lock() + defer ui.mutex.Unlock() + + return ui.store.getUTXOOutpointEntryPairs(scriptPublicKey) +} diff --git a/infrastructure/config/config.go b/infrastructure/config/config.go index 3f36572b5..05b2727ee 100644 --- a/infrastructure/config/config.go +++ b/infrastructure/config/config.go @@ -123,6 +123,7 @@ type Flags struct { RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."` ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."` MaxUTXOCacheSize uint64 `long:"maxutxocachesize" description:"Max size of loaded UTXO into ram from the disk in bytes"` + UTXOIndex bool `long:"utxoindex" description:"Enable the UTXO index"` NetworkFlags ServiceOptions *ServiceOptions } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 739a502a9..ce748049a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -104,6 +104,16 @@ type KaspadMessage struct { // *KaspadMessage_ShutDownResponse // *KaspadMessage_GetHeadersRequest // *KaspadMessage_GetHeadersResponse + // *KaspadMessage_NotifyUtxosChangedRequest + // *KaspadMessage_NotifyUtxosChangedResponse + // *KaspadMessage_UtxosChangedNotification + // *KaspadMessage_GetUtxosByAddressesRequest + // *KaspadMessage_GetUtxosByAddressesResponse + // *KaspadMessage_GetVirtualSelectedParentBlueScoreRequest + // *KaspadMessage_GetVirtualSelectedParentBlueScoreResponse + // *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest + // *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse + // *KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification Payload isKaspadMessage_Payload `protobuf_oneof:"payload"` } @@ -657,6 +667,76 @@ func (x *KaspadMessage) GetGetHeadersResponse() *GetHeadersResponseMessage { return nil } +func (x *KaspadMessage) GetNotifyUtxosChangedRequest() *NotifyUtxosChangedRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_NotifyUtxosChangedRequest); ok { + return x.NotifyUtxosChangedRequest + } + return nil +} + +func (x *KaspadMessage) GetNotifyUtxosChangedResponse() *NotifyUtxosChangedResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_NotifyUtxosChangedResponse); ok { + return x.NotifyUtxosChangedResponse + } + return nil +} + +func (x *KaspadMessage) GetUtxosChangedNotification() *UtxosChangedNotificationMessage { + if x, ok := x.GetPayload().(*KaspadMessage_UtxosChangedNotification); ok { + return x.UtxosChangedNotification + } + return nil +} + +func (x *KaspadMessage) GetGetUtxosByAddressesRequest() *GetUtxosByAddressesRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetUtxosByAddressesRequest); ok { + return x.GetUtxosByAddressesRequest + } + return nil +} + +func (x *KaspadMessage) GetGetUtxosByAddressesResponse() *GetUtxosByAddressesResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetUtxosByAddressesResponse); ok { + return x.GetUtxosByAddressesResponse + } + return nil +} + +func (x *KaspadMessage) GetGetVirtualSelectedParentBlueScoreRequest() *GetVirtualSelectedParentBlueScoreRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetVirtualSelectedParentBlueScoreRequest); ok { + return x.GetVirtualSelectedParentBlueScoreRequest + } + return nil +} + +func (x *KaspadMessage) GetGetVirtualSelectedParentBlueScoreResponse() *GetVirtualSelectedParentBlueScoreResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetVirtualSelectedParentBlueScoreResponse); ok { + return x.GetVirtualSelectedParentBlueScoreResponse + } + return nil +} + +func (x *KaspadMessage) GetNotifyVirtualSelectedParentBlueScoreChangedRequest() *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest); ok { + return x.NotifyVirtualSelectedParentBlueScoreChangedRequest + } + return nil +} + +func (x *KaspadMessage) GetNotifyVirtualSelectedParentBlueScoreChangedResponse() *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse); ok { + return x.NotifyVirtualSelectedParentBlueScoreChangedResponse + } + return nil +} + +func (x *KaspadMessage) GetVirtualSelectedParentBlueScoreChangedNotification() *VirtualSelectedParentBlueScoreChangedNotificationMessage { + if x, ok := x.GetPayload().(*KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification); ok { + return x.VirtualSelectedParentBlueScoreChangedNotification + } + return nil +} + type isKaspadMessage_Payload interface { isKaspadMessage_Payload() } @@ -946,13 +1026,53 @@ type KaspadMessage_ShutDownResponse struct { } type KaspadMessage_GetHeadersRequest struct { - GetHeadersRequest *GetHeadersRequestMessage `protobuf:"bytes,10347,opt,name=getHeadersRequest,proto3,oneof"` + GetHeadersRequest *GetHeadersRequestMessage `protobuf:"bytes,1047,opt,name=getHeadersRequest,proto3,oneof"` } type KaspadMessage_GetHeadersResponse struct { GetHeadersResponse *GetHeadersResponseMessage `protobuf:"bytes,1048,opt,name=getHeadersResponse,proto3,oneof"` } +type KaspadMessage_NotifyUtxosChangedRequest struct { + NotifyUtxosChangedRequest *NotifyUtxosChangedRequestMessage `protobuf:"bytes,1049,opt,name=notifyUtxosChangedRequest,proto3,oneof"` +} + +type KaspadMessage_NotifyUtxosChangedResponse struct { + NotifyUtxosChangedResponse *NotifyUtxosChangedResponseMessage `protobuf:"bytes,1050,opt,name=notifyUtxosChangedResponse,proto3,oneof"` +} + +type KaspadMessage_UtxosChangedNotification struct { + UtxosChangedNotification *UtxosChangedNotificationMessage `protobuf:"bytes,1051,opt,name=utxosChangedNotification,proto3,oneof"` +} + +type KaspadMessage_GetUtxosByAddressesRequest struct { + GetUtxosByAddressesRequest *GetUtxosByAddressesRequestMessage `protobuf:"bytes,1052,opt,name=getUtxosByAddressesRequest,proto3,oneof"` +} + +type KaspadMessage_GetUtxosByAddressesResponse struct { + GetUtxosByAddressesResponse *GetUtxosByAddressesResponseMessage `protobuf:"bytes,1053,opt,name=getUtxosByAddressesResponse,proto3,oneof"` +} + +type KaspadMessage_GetVirtualSelectedParentBlueScoreRequest struct { + GetVirtualSelectedParentBlueScoreRequest *GetVirtualSelectedParentBlueScoreRequestMessage `protobuf:"bytes,1054,opt,name=getVirtualSelectedParentBlueScoreRequest,proto3,oneof"` +} + +type KaspadMessage_GetVirtualSelectedParentBlueScoreResponse struct { + GetVirtualSelectedParentBlueScoreResponse *GetVirtualSelectedParentBlueScoreResponseMessage `protobuf:"bytes,1055,opt,name=getVirtualSelectedParentBlueScoreResponse,proto3,oneof"` +} + +type KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest struct { + NotifyVirtualSelectedParentBlueScoreChangedRequest *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage `protobuf:"bytes,1056,opt,name=notifyVirtualSelectedParentBlueScoreChangedRequest,proto3,oneof"` +} + +type KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse struct { + NotifyVirtualSelectedParentBlueScoreChangedResponse *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage `protobuf:"bytes,1057,opt,name=notifyVirtualSelectedParentBlueScoreChangedResponse,proto3,oneof"` +} + +type KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification struct { + VirtualSelectedParentBlueScoreChangedNotification *VirtualSelectedParentBlueScoreChangedNotificationMessage `protobuf:"bytes,1058,opt,name=virtualSelectedParentBlueScoreChangedNotification,proto3,oneof"` +} + func (*KaspadMessage_Addresses) isKaspadMessage_Payload() {} func (*KaspadMessage_Block) isKaspadMessage_Payload() {} @@ -1099,6 +1219,26 @@ func (*KaspadMessage_GetHeadersRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetHeadersResponse) isKaspadMessage_Payload() {} +func (*KaspadMessage_NotifyUtxosChangedRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_NotifyUtxosChangedResponse) isKaspadMessage_Payload() {} + +func (*KaspadMessage_UtxosChangedNotification) isKaspadMessage_Payload() {} + +func (*KaspadMessage_GetUtxosByAddressesRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_GetUtxosByAddressesResponse) isKaspadMessage_Payload() {} + +func (*KaspadMessage_GetVirtualSelectedParentBlueScoreRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_GetVirtualSelectedParentBlueScoreResponse) isKaspadMessage_Payload() {} + +func (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) isKaspadMessage_Payload() {} + +func (*KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) isKaspadMessage_Payload() {} + // RequestAddressesMessage start type RequestAddressesMessage struct { state protoimpl.MessageState @@ -4086,7 +4226,7 @@ type SubmitTransactionRequestMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Transaction *TransactionMessage `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` + Transaction *RpcTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` } func (x *SubmitTransactionRequestMessage) Reset() { @@ -4121,7 +4261,7 @@ func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{57} } -func (x *SubmitTransactionRequestMessage) GetTransaction() *TransactionMessage { +func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { if x != nil { return x.Transaction } @@ -4133,8 +4273,8 @@ type SubmitTransactionResponseMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` + TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } func (x *SubmitTransactionResponseMessage) Reset() { @@ -4169,9 +4309,9 @@ func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{58} } -func (x *SubmitTransactionResponseMessage) GetTxId() string { +func (x *SubmitTransactionResponseMessage) GetTransactionId() string { if x != nil { - return x.TxId + return x.TransactionId } return "" } @@ -6209,11 +6349,897 @@ func (x *GetHeadersResponseMessage) GetError() *RPCError { return nil } +type NotifyUtxosChangedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (x *NotifyUtxosChangedRequestMessage) Reset() { + *x = NotifyUtxosChangedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[92] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyUtxosChangedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} + +func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[92] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{92} +} + +func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +type NotifyUtxosChangedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyUtxosChangedResponseMessage) Reset() { + *x = NotifyUtxosChangedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[93] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyUtxosChangedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} + +func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[93] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{93} +} + +func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type UtxosChangedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Added []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=added,proto3" json:"added,omitempty"` + Removed []*UtxosByAddressesEntry `protobuf:"bytes,2,rep,name=removed,proto3" json:"removed,omitempty"` +} + +func (x *UtxosChangedNotificationMessage) Reset() { + *x = UtxosChangedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[94] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UtxosChangedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UtxosChangedNotificationMessage) ProtoMessage() {} + +func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[94] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. +func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{94} +} + +func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { + if x != nil { + return x.Added + } + return nil +} + +func (x *UtxosChangedNotificationMessage) GetRemoved() []*UtxosByAddressesEntry { + if x != nil { + return x.Removed + } + return nil +} + +type UtxosByAddressesEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Outpoint *RpcOutpoint `protobuf:"bytes,2,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + UtxoEntry *RpcUtxoEntry `protobuf:"bytes,3,opt,name=utxoEntry,proto3" json:"utxoEntry,omitempty"` +} + +func (x *UtxosByAddressesEntry) Reset() { + *x = UtxosByAddressesEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[95] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UtxosByAddressesEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UtxosByAddressesEntry) ProtoMessage() {} + +func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[95] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. +func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{95} +} + +func (x *UtxosByAddressesEntry) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *UtxosByAddressesEntry) GetOutpoint() *RpcOutpoint { + if x != nil { + return x.Outpoint + } + return nil +} + +func (x *UtxosByAddressesEntry) GetUtxoEntry() *RpcUtxoEntry { + if x != nil { + return x.UtxoEntry + } + return nil +} + +type RpcTransaction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Inputs []*RpcTransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*RpcTransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` + LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` + SubnetworkId string `protobuf:"bytes,5,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"` + PayloadHash string `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` + Payload string `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *RpcTransaction) Reset() { + *x = RpcTransaction{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[96] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcTransaction) ProtoMessage() {} + +func (x *RpcTransaction) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[96] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. +func (*RpcTransaction) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{96} +} + +func (x *RpcTransaction) GetVersion() int32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *RpcTransaction) GetInputs() []*RpcTransactionInput { + if x != nil { + return x.Inputs + } + return nil +} + +func (x *RpcTransaction) GetOutputs() []*RpcTransactionOutput { + if x != nil { + return x.Outputs + } + return nil +} + +func (x *RpcTransaction) GetLockTime() uint64 { + if x != nil { + return x.LockTime + } + return 0 +} + +func (x *RpcTransaction) GetSubnetworkId() string { + if x != nil { + return x.SubnetworkId + } + return "" +} + +func (x *RpcTransaction) GetGas() uint64 { + if x != nil { + return x.Gas + } + return 0 +} + +func (x *RpcTransaction) GetPayloadHash() string { + if x != nil { + return x.PayloadHash + } + return "" +} + +func (x *RpcTransaction) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +type RpcTransactionInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PreviousOutpoint *RpcOutpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` + SignatureScript string `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` + Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (x *RpcTransactionInput) Reset() { + *x = RpcTransactionInput{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[97] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcTransactionInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcTransactionInput) ProtoMessage() {} + +func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[97] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. +func (*RpcTransactionInput) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{97} +} + +func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { + if x != nil { + return x.PreviousOutpoint + } + return nil +} + +func (x *RpcTransactionInput) GetSignatureScript() string { + if x != nil { + return x.SignatureScript + } + return "" +} + +func (x *RpcTransactionInput) GetSequence() uint64 { + if x != nil { + return x.Sequence + } + return 0 +} + +type RpcTransactionOutput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPubKey string `protobuf:"bytes,2,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` +} + +func (x *RpcTransactionOutput) Reset() { + *x = RpcTransactionOutput{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[98] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcTransactionOutput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcTransactionOutput) ProtoMessage() {} + +func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[98] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. +func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{98} +} + +func (x *RpcTransactionOutput) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *RpcTransactionOutput) GetScriptPubKey() string { + if x != nil { + return x.ScriptPubKey + } + return "" +} + +type RpcOutpoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` +} + +func (x *RpcOutpoint) Reset() { + *x = RpcOutpoint{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[99] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcOutpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcOutpoint) ProtoMessage() {} + +func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[99] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. +func (*RpcOutpoint) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{99} +} + +func (x *RpcOutpoint) GetTransactionId() string { + if x != nil { + return x.TransactionId + } + return "" +} + +func (x *RpcOutpoint) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +type RpcUtxoEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPubKey string `protobuf:"bytes,2,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` + BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` + IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` +} + +func (x *RpcUtxoEntry) Reset() { + *x = RpcUtxoEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[100] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcUtxoEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcUtxoEntry) ProtoMessage() {} + +func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[100] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. +func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{100} +} + +func (x *RpcUtxoEntry) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *RpcUtxoEntry) GetScriptPubKey() string { + if x != nil { + return x.ScriptPubKey + } + return "" +} + +func (x *RpcUtxoEntry) GetBlockBlueScore() uint64 { + if x != nil { + return x.BlockBlueScore + } + return 0 +} + +func (x *RpcUtxoEntry) GetIsCoinbase() bool { + if x != nil { + return x.IsCoinbase + } + return false +} + +type GetUtxosByAddressesRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (x *GetUtxosByAddressesRequestMessage) Reset() { + *x = GetUtxosByAddressesRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[101] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUtxosByAddressesRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} + +func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[101] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. +func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{101} +} + +func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +type GetUtxosByAddressesResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entries []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetUtxosByAddressesResponseMessage) Reset() { + *x = GetUtxosByAddressesResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[102] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUtxosByAddressesResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} + +func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[102] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. +func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{102} +} + +func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { + if x != nil { + return x.Entries + } + return nil +} + +func (x *GetUtxosByAddressesResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type GetVirtualSelectedParentBlueScoreRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { + *x = GetVirtualSelectedParentBlueScoreRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[103] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} + +func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[103] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{103} +} + +type GetVirtualSelectedParentBlueScoreResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlueScore uint64 `protobuf:"varint,1,opt,name=blueScore,proto3" json:"blueScore,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { + *x = GetVirtualSelectedParentBlueScoreResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[104] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{104} +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { + if x != nil { + return x.BlueScore + } + return 0 +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { + *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[105] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{105} +} + +type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { + *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[106] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{106} +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + VirtualSelectedParentBlueScore uint64 `protobuf:"varint,1,opt,name=virtualSelectedParentBlueScore,proto3" json:"virtualSelectedParentBlueScore,omitempty"` +} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { + *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[107] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. +func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{107} +} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { + if x != nil { + return x.VirtualSelectedParentBlueScore + } + return 0 +} + var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xa1, 0x35, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xb9, 0x40, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -6629,7 +7655,7 @@ var file_messages_proto_rawDesc = []byte{ 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x50, 0x20, 0x01, 0x28, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, @@ -6639,526 +7665,460 @@ var file_messages_proto_rawDesc = []byte{ 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, - 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, - 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, - 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, - 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, - 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, - 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, - 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, - 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, - 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, - 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, - 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, - 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, - 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, - 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, - 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, - 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, + 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, + 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, + 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, + 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, - 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, - 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, - 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, - 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, - 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, - 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, - 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, - 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, - 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, - 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, + 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, - 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, - 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, - 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, - 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, - 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 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, 0x40, 0x0a, 0x1e, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, - 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, - 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, - 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, - 0x64, 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, 0x4e, 0x0a, 0x1d, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, - 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, - 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, - 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, - 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, - 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, - 0x65, 0x65, 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, 0x02, 0x20, 0x01, - 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, 0x22, 0x33, 0x0a, - 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, - 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, - 0x74, 0x72, 0x79, 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, - 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, - 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, - 0x6f, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, + 0x48, 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, + 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, + 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, + 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, + 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, + 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, + 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, + 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, + 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, + 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, + 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, + 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, + 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, + 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, + 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, + 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, + 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, + 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, + 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, + 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, + 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, + 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, + 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, + 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, + 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, + 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, + 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, + 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 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, 0xb5, - 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, - 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, - 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, - 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, - 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, - 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, - 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x62, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x12, 0x2a, 0x0a, + 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x4a, + 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, + 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, + 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 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, 0x39, + 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, + 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 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, 0x24, + 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, + 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, + 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, + 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, + 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, + 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, - 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 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, 0x9e, - 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, - 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, - 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, 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, 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, - 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, 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, + 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, + 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 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, + 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 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, @@ -7166,138 +8126,414 @@ var file_messages_proto_rawDesc = []byte{ 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, 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, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 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, 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, + 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, 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, + 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, 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, 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, + 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 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, 0x95, 0x01, 0x0a, 0x1f, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, + 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, + 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, + 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, 0x05, + 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, + 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, + 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, + 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, + 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, + 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, + 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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 ( @@ -7312,100 +8548,116 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 92) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 108) var file_messages_proto_goTypes = []interface{}{ - (*KaspadMessage)(nil), // 0: protowire.KaspadMessage - (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage - (*AddressesMessage)(nil), // 2: protowire.AddressesMessage - (*NetAddress)(nil), // 3: protowire.NetAddress - (*SubnetworkId)(nil), // 4: protowire.SubnetworkId - (*TransactionMessage)(nil), // 5: protowire.TransactionMessage - (*TransactionInput)(nil), // 6: protowire.TransactionInput - (*Outpoint)(nil), // 7: protowire.Outpoint - (*TransactionId)(nil), // 8: protowire.TransactionId - (*TransactionOutput)(nil), // 9: protowire.TransactionOutput - (*BlockMessage)(nil), // 10: protowire.BlockMessage - (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage - (*Hash)(nil), // 12: protowire.Hash - (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage - (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage - (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage - (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage - (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage - (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage - (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage - (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage - (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage - (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage - (*PingMessage)(nil), // 23: protowire.PingMessage - (*PongMessage)(nil), // 24: protowire.PongMessage - (*VerackMessage)(nil), // 25: protowire.VerackMessage - (*VersionMessage)(nil), // 26: protowire.VersionMessage - (*RejectMessage)(nil), // 27: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage - (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage - (*RPCError)(nil), // 32: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 33: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 34: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 35: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 36: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 37: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 38: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 39: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 40: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 41: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 42: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 43: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 44: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 45: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 46: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 47: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 48: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 49: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 50: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 51: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 52: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 53: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 54: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 55: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 56: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 57: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 58: protowire.SubmitTransactionResponseMessage - (*NotifyChainChangedRequestMessage)(nil), // 59: protowire.NotifyChainChangedRequestMessage - (*NotifyChainChangedResponseMessage)(nil), // 60: protowire.NotifyChainChangedResponseMessage - (*ChainChangedNotificationMessage)(nil), // 61: protowire.ChainChangedNotificationMessage - (*ChainBlock)(nil), // 62: protowire.ChainBlock - (*AcceptedBlock)(nil), // 63: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 64: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 65: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 66: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 67: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 68: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 69: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 70: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 71: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 72: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 73: protowire.GetSubnetworkResponseMessage - (*GetChainFromBlockRequestMessage)(nil), // 74: protowire.GetChainFromBlockRequestMessage - (*GetChainFromBlockResponseMessage)(nil), // 75: protowire.GetChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 76: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 77: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 78: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 79: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 80: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 81: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 82: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 83: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 84: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 85: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 86: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 87: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 88: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 89: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 90: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 91: protowire.GetHeadersResponseMessage + (*KaspadMessage)(nil), // 0: protowire.KaspadMessage + (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage + (*AddressesMessage)(nil), // 2: protowire.AddressesMessage + (*NetAddress)(nil), // 3: protowire.NetAddress + (*SubnetworkId)(nil), // 4: protowire.SubnetworkId + (*TransactionMessage)(nil), // 5: protowire.TransactionMessage + (*TransactionInput)(nil), // 6: protowire.TransactionInput + (*Outpoint)(nil), // 7: protowire.Outpoint + (*TransactionId)(nil), // 8: protowire.TransactionId + (*TransactionOutput)(nil), // 9: protowire.TransactionOutput + (*BlockMessage)(nil), // 10: protowire.BlockMessage + (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage + (*Hash)(nil), // 12: protowire.Hash + (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage + (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage + (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage + (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage + (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage + (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage + (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 23: protowire.PingMessage + (*PongMessage)(nil), // 24: protowire.PongMessage + (*VerackMessage)(nil), // 25: protowire.VerackMessage + (*VersionMessage)(nil), // 26: protowire.VersionMessage + (*RejectMessage)(nil), // 27: protowire.RejectMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage + (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage + (*RPCError)(nil), // 32: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 33: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 34: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 35: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 36: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 37: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 38: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 39: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 40: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 41: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 42: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 43: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 44: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 45: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 46: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 47: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 48: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 49: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 50: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 51: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 52: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 53: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 54: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 55: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 56: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 57: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 58: protowire.SubmitTransactionResponseMessage + (*NotifyChainChangedRequestMessage)(nil), // 59: protowire.NotifyChainChangedRequestMessage + (*NotifyChainChangedResponseMessage)(nil), // 60: protowire.NotifyChainChangedResponseMessage + (*ChainChangedNotificationMessage)(nil), // 61: protowire.ChainChangedNotificationMessage + (*ChainBlock)(nil), // 62: protowire.ChainBlock + (*AcceptedBlock)(nil), // 63: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 64: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 65: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 66: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 67: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 68: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 69: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 70: protowire.TransactionVerboseOutput + (*ScriptPubKeyResult)(nil), // 71: protowire.ScriptPubKeyResult + (*GetSubnetworkRequestMessage)(nil), // 72: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 73: protowire.GetSubnetworkResponseMessage + (*GetChainFromBlockRequestMessage)(nil), // 74: protowire.GetChainFromBlockRequestMessage + (*GetChainFromBlockResponseMessage)(nil), // 75: protowire.GetChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 76: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 77: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 78: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 79: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 80: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 81: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 82: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 83: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 84: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 85: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 86: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 87: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 88: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 89: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 90: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 91: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 92: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 93: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 94: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 95: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 96: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 97: protowire.RpcTransactionInput + (*RpcTransactionOutput)(nil), // 98: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 99: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 100: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 101: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 102: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 103: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 104: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 105: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 106: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 107: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -7481,87 +8733,109 @@ var file_messages_proto_depIdxs = []int32{ 89, // 70: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage 90, // 71: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage 91, // 72: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 4, // 73: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId - 3, // 74: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 6, // 75: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 76: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 4, // 77: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 78: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 79: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint - 8, // 80: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId - 11, // 81: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 82: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 83: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 12, // 84: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 85: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash - 12, // 86: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 12, // 87: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 88: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 89: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 90: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 12, // 91: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 12, // 92: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 93: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId - 8, // 94: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId - 12, // 95: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 96: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId - 3, // 97: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 4, // 98: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 99: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 100: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 101: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 32, // 102: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 103: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 32, // 104: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 105: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 32, // 106: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 32, // 107: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 108: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 44, // 109: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 44, // 110: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 32, // 111: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 32, // 112: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 67, // 113: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 47, // 114: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 32, // 115: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 47, // 116: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 32, // 117: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 54, // 118: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 32, // 119: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 32, // 120: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 5, // 121: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.TransactionMessage - 32, // 122: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 32, // 123: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError - 62, // 124: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 63, // 125: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 66, // 126: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 127: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 67, // 128: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 68, // 129: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 70, // 130: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 69, // 131: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 71, // 132: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 32, // 133: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 62, // 134: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 66, // 135: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 136: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 66, // 137: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 138: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 32, // 139: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 32, // 140: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 32, // 141: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 32, // 142: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 32, // 143: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 32, // 144: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 0, // 145: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 146: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 147: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 148: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 147, // [147:149] is the sub-list for method output_type - 145, // [145:147] is the sub-list for method input_type - 145, // [145:145] is the sub-list for extension type_name - 145, // [145:145] is the sub-list for extension extendee - 0, // [0:145] is the sub-list for field type_name + 92, // 73: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 93, // 74: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 94, // 75: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 101, // 76: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 102, // 77: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 103, // 78: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 104, // 79: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 105, // 80: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 106, // 81: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 107, // 82: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 4, // 83: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId + 3, // 84: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 6, // 85: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 86: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 4, // 87: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 88: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 7, // 89: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint + 8, // 90: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId + 11, // 91: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 92: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 93: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 94: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 95: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash + 12, // 96: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 97: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 98: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 99: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 100: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 101: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 102: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 103: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 8, // 104: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId + 12, // 105: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 106: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId + 3, // 107: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 4, // 108: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 109: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 110: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 111: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 32, // 112: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 113: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 32, // 114: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 115: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 32, // 116: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 32, // 117: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 118: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 44, // 119: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 44, // 120: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 32, // 121: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 32, // 122: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 67, // 123: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 47, // 124: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 32, // 125: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 47, // 126: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 32, // 127: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 54, // 128: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 32, // 129: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 32, // 130: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 96, // 131: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 32, // 132: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 32, // 133: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError + 62, // 134: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 63, // 135: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 66, // 136: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 137: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 67, // 138: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 68, // 139: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 70, // 140: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 69, // 141: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 71, // 142: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 32, // 143: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 62, // 144: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 66, // 145: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 146: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 66, // 147: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 148: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 32, // 149: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 32, // 150: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 32, // 151: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 32, // 152: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 32, // 153: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 32, // 154: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 32, // 155: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 95, // 156: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 95, // 157: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 99, // 158: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 100, // 159: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 97, // 160: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 98, // 161: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 99, // 162: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 95, // 163: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 32, // 164: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 32, // 165: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 32, // 166: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 0, // 167: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 168: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 169: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 170: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 169, // [169:171] is the sub-list for method output_type + 167, // [167:169] is the sub-list for method input_type + 167, // [167:167] is the sub-list for extension type_name + 167, // [167:167] is the sub-list for extension extendee + 0, // [0:167] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -8674,6 +9948,198 @@ func file_messages_proto_init() { return nil } } + file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyUtxosChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyUtxosChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UtxosChangedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UtxosByAddressesEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcTransaction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcTransactionInput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcTransactionOutput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcOutpoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcUtxoEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_messages_proto_msgTypes[0].OneofWrappers = []interface{}{ (*KaspadMessage_Addresses)(nil), @@ -8749,6 +10215,16 @@ func file_messages_proto_init() { (*KaspadMessage_ShutDownResponse)(nil), (*KaspadMessage_GetHeadersRequest)(nil), (*KaspadMessage_GetHeadersResponse)(nil), + (*KaspadMessage_NotifyUtxosChangedRequest)(nil), + (*KaspadMessage_NotifyUtxosChangedResponse)(nil), + (*KaspadMessage_UtxosChangedNotification)(nil), + (*KaspadMessage_GetUtxosByAddressesRequest)(nil), + (*KaspadMessage_GetUtxosByAddressesResponse)(nil), + (*KaspadMessage_GetVirtualSelectedParentBlueScoreRequest)(nil), + (*KaspadMessage_GetVirtualSelectedParentBlueScoreResponse)(nil), + (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest)(nil), + (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse)(nil), + (*KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -8756,7 +10232,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 92, + NumMessages: 108, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index e88ae9c9b..434982c54 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -77,8 +77,18 @@ message KaspadMessage { GetMempoolEntriesResponseMessage getMempoolEntriesResponse = 1044; ShutDownRequestMessage shutDownRequest = 1045; ShutDownResponseMessage shutDownResponse = 1046; - GetHeadersRequestMessage getHeadersRequest = 10347; + GetHeadersRequestMessage getHeadersRequest = 1047; GetHeadersResponseMessage getHeadersResponse = 1048; + NotifyUtxosChangedRequestMessage notifyUtxosChangedRequest = 1049; + NotifyUtxosChangedResponseMessage notifyUtxosChangedResponse = 1050; + UtxosChangedNotificationMessage utxosChangedNotification = 1051; + GetUtxosByAddressesRequestMessage getUtxosByAddressesRequest = 1052; + GetUtxosByAddressesResponseMessage getUtxosByAddressesResponse = 1053; + GetVirtualSelectedParentBlueScoreRequestMessage getVirtualSelectedParentBlueScoreRequest = 1054; + GetVirtualSelectedParentBlueScoreResponseMessage getVirtualSelectedParentBlueScoreResponse = 1055; + NotifyVirtualSelectedParentBlueScoreChangedRequestMessage notifyVirtualSelectedParentBlueScoreChangedRequest = 1056; + NotifyVirtualSelectedParentBlueScoreChangedResponseMessage notifyVirtualSelectedParentBlueScoreChangedResponse = 1057; + VirtualSelectedParentBlueScoreChangedNotificationMessage virtualSelectedParentBlueScoreChangedNotification = 1058; } } @@ -412,11 +422,12 @@ message AddPeerResponseMessage{ } message SubmitTransactionRequestMessage{ - TransactionMessage transaction = 1; + RpcTransaction transaction = 1; } message SubmitTransactionResponseMessage{ - string txId = 1; + string transactionId = 1; + RPCError error = 1000; } @@ -612,6 +623,89 @@ message GetHeadersResponseMessage{ RPCError error = 1000; } +message NotifyUtxosChangedRequestMessage { + repeated string addresses = 1; +} + +message NotifyUtxosChangedResponseMessage { + RPCError error = 1000; +} + +message UtxosChangedNotificationMessage { + repeated UtxosByAddressesEntry added = 1; + repeated UtxosByAddressesEntry removed = 2; +} + +message UtxosByAddressesEntry { + string address = 1; + RpcOutpoint outpoint = 2; + RpcUtxoEntry utxoEntry = 3; +} + +message RpcTransaction { + int32 version = 1; + repeated RpcTransactionInput inputs = 2; + repeated RpcTransactionOutput outputs = 3; + uint64 lockTime = 4; + string subnetworkId = 5; + uint64 gas = 6; + string payloadHash = 7; + string payload = 8; +} + +message RpcTransactionInput { + RpcOutpoint previousOutpoint = 1; + string signatureScript = 2; + uint64 sequence = 3; +} + +message RpcTransactionOutput { + uint64 amount = 1; + string scriptPubKey = 2; +} + +message RpcOutpoint { + string transactionId = 1; + uint32 index = 2; +} + +message RpcUtxoEntry { + uint64 amount = 1; + string scriptPubKey = 2; + uint64 blockBlueScore = 3; + bool isCoinbase = 4; +} + +message GetUtxosByAddressesRequestMessage { + repeated string addresses = 1; +} + +message GetUtxosByAddressesResponseMessage { + repeated UtxosByAddressesEntry entries = 1; + + RPCError error = 1000; +} + +message GetVirtualSelectedParentBlueScoreRequestMessage { +} + +message GetVirtualSelectedParentBlueScoreResponseMessage { + uint64 blueScore = 1; + + RPCError error = 1000; +} + +message NotifyVirtualSelectedParentBlueScoreChangedRequestMessage { +} + +message NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { + RPCError error = 1000; +} + +message VirtualSelectedParentBlueScoreChangedNotificationMessage { + uint64 virtualSelectedParentBlueScore = 1; +} + service RPC { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go new file mode 100644 index 000000000..ce712cdcc --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go @@ -0,0 +1,48 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_GetUtxosByAddressesRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.GetUTXOsByAddressesRequestMessage{ + Addresses: x.GetUtxosByAddressesRequest.Addresses, + }, nil +} + +func (x *KaspadMessage_GetUtxosByAddressesRequest) fromAppMessage(message *appmessage.GetUTXOsByAddressesRequestMessage) error { + x.GetUtxosByAddressesRequest = &GetUtxosByAddressesRequestMessage{ + Addresses: message.Addresses, + } + return nil +} + +func (x *KaspadMessage_GetUtxosByAddressesResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.GetUtxosByAddressesResponse.Error != nil { + err = &appmessage.RPCError{Message: x.GetUtxosByAddressesResponse.Error.Message} + } + entries := make([]*appmessage.UTXOsByAddressesEntry, len(x.GetUtxosByAddressesResponse.Entries)) + for i, entry := range x.GetUtxosByAddressesResponse.Entries { + entries[i] = entry.toAppMessage() + } + return &appmessage.GetUTXOsByAddressesResponseMessage{ + Entries: entries, + Error: err, + }, nil +} + +func (x *KaspadMessage_GetUtxosByAddressesResponse) fromAppMessage(message *appmessage.GetUTXOsByAddressesResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + entries := make([]*UtxosByAddressesEntry, len(message.Entries)) + for i, entry := range message.Entries { + entries[i] = &UtxosByAddressesEntry{} + entries[i].fromAppMessage(entry) + } + x.GetUtxosByAddressesResponse = &GetUtxosByAddressesResponseMessage{ + Entries: entries, + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_blue_score.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_blue_score.go new file mode 100644 index 000000000..ba2a8607a --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_blue_score.go @@ -0,0 +1,37 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.GetVirtualSelectedParentBlueScoreRequestMessage{}, nil +} + +func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreRequest) fromAppMessage(message *appmessage.GetVirtualSelectedParentBlueScoreRequestMessage) error { + x.GetVirtualSelectedParentBlueScoreRequest = &GetVirtualSelectedParentBlueScoreRequestMessage{} + return nil +} + +func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.GetVirtualSelectedParentBlueScoreResponse.Error != nil { + err = &appmessage.RPCError{Message: x.GetVirtualSelectedParentBlueScoreResponse.Error.Message} + } + return &appmessage.GetVirtualSelectedParentBlueScoreResponseMessage{ + BlueScore: x.GetVirtualSelectedParentBlueScoreResponse.BlueScore, + Error: err, + }, nil +} + +func (x *KaspadMessage_GetVirtualSelectedParentBlueScoreResponse) fromAppMessage(message *appmessage.GetVirtualSelectedParentBlueScoreResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.GetVirtualSelectedParentBlueScoreResponse = &GetVirtualSelectedParentBlueScoreResponseMessage{ + BlueScore: message.BlueScore, + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go new file mode 100644 index 000000000..23b3210b3 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go @@ -0,0 +1,118 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_NotifyUtxosChangedRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.NotifyUTXOsChangedRequestMessage{ + Addresses: x.NotifyUtxosChangedRequest.Addresses, + }, nil +} + +func (x *KaspadMessage_NotifyUtxosChangedRequest) fromAppMessage(message *appmessage.NotifyUTXOsChangedRequestMessage) error { + x.NotifyUtxosChangedRequest = &NotifyUtxosChangedRequestMessage{ + Addresses: message.Addresses, + } + return nil +} + +func (x *KaspadMessage_NotifyUtxosChangedResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.NotifyUtxosChangedResponse.Error != nil { + err = &appmessage.RPCError{Message: x.NotifyUtxosChangedResponse.Error.Message} + } + return &appmessage.NotifyUTXOsChangedResponseMessage{ + Error: err, + }, nil +} + +func (x *KaspadMessage_NotifyUtxosChangedResponse) fromAppMessage(message *appmessage.NotifyUTXOsChangedResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.NotifyUtxosChangedResponse = &NotifyUtxosChangedResponseMessage{ + Error: err, + } + return nil +} + +func (x *KaspadMessage_UtxosChangedNotification) toAppMessage() (appmessage.Message, error) { + added := make([]*appmessage.UTXOsByAddressesEntry, len(x.UtxosChangedNotification.Added)) + for i, entry := range x.UtxosChangedNotification.Added { + added[i] = entry.toAppMessage() + } + + removed := make([]*appmessage.UTXOsByAddressesEntry, len(x.UtxosChangedNotification.Removed)) + for i, entry := range x.UtxosChangedNotification.Removed { + removed[i] = entry.toAppMessage() + } + + return &appmessage.UTXOsChangedNotificationMessage{ + Added: added, + Removed: removed, + }, nil +} + +func (x *KaspadMessage_UtxosChangedNotification) fromAppMessage(message *appmessage.UTXOsChangedNotificationMessage) error { + added := make([]*UtxosByAddressesEntry, len(message.Added)) + for i, entry := range message.Added { + added[i] = &UtxosByAddressesEntry{} + added[i].fromAppMessage(entry) + } + + removed := make([]*UtxosByAddressesEntry, len(message.Removed)) + for i, entry := range message.Removed { + removed[i] = &UtxosByAddressesEntry{} + removed[i].fromAppMessage(entry) + } + + x.UtxosChangedNotification = &UtxosChangedNotificationMessage{ + Added: added, + Removed: removed, + } + return nil +} + +func (x *UtxosByAddressesEntry) toAppMessage() *appmessage.UTXOsByAddressesEntry { + outpoint := &appmessage.RPCOutpoint{ + TransactionID: x.Outpoint.TransactionId, + Index: x.Outpoint.Index, + } + var utxoEntry *appmessage.RPCUTXOEntry + if x.UtxoEntry != nil { + utxoEntry = &appmessage.RPCUTXOEntry{ + Amount: x.UtxoEntry.Amount, + ScriptPubKey: x.UtxoEntry.ScriptPubKey, + BlockBlueScore: x.UtxoEntry.BlockBlueScore, + IsCoinbase: x.UtxoEntry.IsCoinbase, + } + } + return &appmessage.UTXOsByAddressesEntry{ + Address: x.Address, + Outpoint: outpoint, + UTXOEntry: utxoEntry, + } +} + +func (x *UtxosByAddressesEntry) fromAppMessage(entry *appmessage.UTXOsByAddressesEntry) { + outpoint := &RpcOutpoint{ + TransactionId: entry.Outpoint.TransactionID, + Index: entry.Outpoint.Index, + } + var utxoEntry *RpcUtxoEntry + if entry.UTXOEntry != nil { + utxoEntry = &RpcUtxoEntry{ + Amount: entry.UTXOEntry.Amount, + ScriptPubKey: entry.UTXOEntry.ScriptPubKey, + BlockBlueScore: entry.UTXOEntry.BlockBlueScore, + IsCoinbase: entry.UTXOEntry.IsCoinbase, + } + } + *x = UtxosByAddressesEntry{ + Address: entry.Address, + Outpoint: outpoint, + UtxoEntry: utxoEntry, + } +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_blue_score_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_blue_score_changed.go new file mode 100644 index 000000000..b1d4145a3 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_blue_score_changed.go @@ -0,0 +1,46 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{}, nil +} + +func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest) fromAppMessage(_ *appmessage.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) error { + x.NotifyVirtualSelectedParentBlueScoreChangedRequest = &NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} + return nil +} + +func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.NotifyVirtualSelectedParentBlueScoreChangedResponse.Error != nil { + err = &appmessage.RPCError{Message: x.NotifyVirtualSelectedParentBlueScoreChangedResponse.Error.Message} + } + return &appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{ + Error: err, + }, nil +} + +func (x *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) fromAppMessage(message *appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.NotifyVirtualSelectedParentBlueScoreChangedResponse = &NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{ + Error: err, + } + return nil +} + +func (x *KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) toAppMessage() (appmessage.Message, error) { + return &appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage{ + VirtualSelectedParentBlueScore: x.VirtualSelectedParentBlueScoreChangedNotification.VirtualSelectedParentBlueScore, + }, nil +} + +func (x *KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) fromAppMessage(message *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) error { + x.VirtualSelectedParentBlueScoreChangedNotification = &VirtualSelectedParentBlueScoreChangedNotificationMessage{ + VirtualSelectedParentBlueScore: message.VirtualSelectedParentBlueScore, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go index 89a9bc440..f60525930 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go @@ -1,20 +1,19 @@ package protowire -import "github.com/kaspanet/kaspad/app/appmessage" +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) { - msgTx, err := x.SubmitTransactionRequest.Transaction.toAppMessage() - if err != nil { - return nil, err - } + rpcTransaction := x.SubmitTransactionRequest.Transaction.toAppMessage() return &appmessage.SubmitTransactionRequestMessage{ - Transaction: msgTx.(*appmessage.MsgTx), + Transaction: rpcTransaction, }, nil } func (x *KaspadMessage_SubmitTransactionRequest) fromAppMessage(message *appmessage.SubmitTransactionRequestMessage) error { x.SubmitTransactionRequest = &SubmitTransactionRequestMessage{ - Transaction: &TransactionMessage{}, + Transaction: &RpcTransaction{}, } x.SubmitTransactionRequest.Transaction.fromAppMessage(message.Transaction) return nil @@ -26,8 +25,8 @@ func (x *KaspadMessage_SubmitTransactionResponse) toAppMessage() (appmessage.Mes err = &appmessage.RPCError{Message: x.SubmitTransactionResponse.Error.Message} } return &appmessage.SubmitTransactionResponseMessage{ - TxID: x.SubmitTransactionResponse.TxId, - Error: err, + TransactionID: x.SubmitTransactionResponse.TransactionId, + Error: err, }, nil } @@ -37,8 +36,72 @@ func (x *KaspadMessage_SubmitTransactionResponse) fromAppMessage(message *appmes err = &RPCError{Message: message.Error.Message} } x.SubmitTransactionResponse = &SubmitTransactionResponseMessage{ - TxId: message.TxID, - Error: err, + TransactionId: message.TransactionID, + Error: err, } return nil } + +func (x *RpcTransaction) toAppMessage() *appmessage.RPCTransaction { + inputs := make([]*appmessage.RPCTransactionInput, len(x.Inputs)) + for i, input := range x.Inputs { + previousOutpoint := &appmessage.RPCOutpoint{ + TransactionID: input.PreviousOutpoint.TransactionId, + Index: input.PreviousOutpoint.Index, + } + inputs[i] = &appmessage.RPCTransactionInput{ + PreviousOutpoint: previousOutpoint, + SignatureScript: input.SignatureScript, + Sequence: input.Sequence, + } + } + outputs := make([]*appmessage.RPCTransactionOutput, len(x.Outputs)) + for i, output := range x.Outputs { + outputs[i] = &appmessage.RPCTransactionOutput{ + Amount: output.Amount, + ScriptPubKey: output.ScriptPubKey, + } + } + return &appmessage.RPCTransaction{ + Version: x.Version, + Inputs: inputs, + Outputs: outputs, + LockTime: x.LockTime, + SubnetworkID: x.SubnetworkId, + Gas: x.Gas, + PayloadHash: x.PayloadHash, + Payload: x.Payload, + } +} + +func (x *RpcTransaction) fromAppMessage(transaction *appmessage.RPCTransaction) { + inputs := make([]*RpcTransactionInput, len(transaction.Inputs)) + for i, input := range transaction.Inputs { + previousOutpoint := &RpcOutpoint{ + TransactionId: input.PreviousOutpoint.TransactionID, + Index: input.PreviousOutpoint.Index, + } + inputs[i] = &RpcTransactionInput{ + PreviousOutpoint: previousOutpoint, + SignatureScript: input.SignatureScript, + Sequence: input.Sequence, + } + } + outputs := make([]*RpcTransactionOutput, len(transaction.Outputs)) + for i, output := range transaction.Outputs { + outputs[i] = &RpcTransactionOutput{ + Amount: output.Amount, + ScriptPubKey: output.ScriptPubKey, + } + } + *x = RpcTransaction{ + Version: transaction.Version, + Inputs: inputs, + Outputs: outputs, + LockTime: transaction.LockTime, + SubnetworkId: transaction.SubnetworkID, + Gas: transaction.Gas, + PayloadHash: transaction.PayloadHash, + Payload: transaction.Payload, + } +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index 83e6623f7..89e647b9e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -575,6 +575,76 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.NotifyUTXOsChangedRequestMessage: + payload := new(KaspadMessage_NotifyUtxosChangedRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.NotifyUTXOsChangedResponseMessage: + payload := new(KaspadMessage_NotifyUtxosChangedResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.UTXOsChangedNotificationMessage: + payload := new(KaspadMessage_UtxosChangedNotification) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.GetUTXOsByAddressesRequestMessage: + payload := new(KaspadMessage_GetUtxosByAddressesRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.GetUTXOsByAddressesResponseMessage: + payload := new(KaspadMessage_GetUtxosByAddressesResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.GetVirtualSelectedParentBlueScoreRequestMessage: + payload := new(KaspadMessage_GetVirtualSelectedParentBlueScoreRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.GetVirtualSelectedParentBlueScoreResponseMessage: + payload := new(KaspadMessage_GetVirtualSelectedParentBlueScoreResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage: + payload := new(KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage: + payload := new(KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage: + payload := new(KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil default: return nil, nil } diff --git a/infrastructure/network/rpcclient/rpc_get_utxos_by_addresses.go b/infrastructure/network/rpcclient/rpc_get_utxos_by_addresses.go new file mode 100644 index 000000000..3f4476fb1 --- /dev/null +++ b/infrastructure/network/rpcclient/rpc_get_utxos_by_addresses.go @@ -0,0 +1,20 @@ +package rpcclient + +import "github.com/kaspanet/kaspad/app/appmessage" + +// GetUTXOsByAddresses sends an RPC request respective to the function's name and returns the RPC server's response +func (c *RPCClient) GetUTXOsByAddresses(addresses []string) (*appmessage.GetUTXOsByAddressesResponseMessage, error) { + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetUTXOsByAddressesRequestMessage(addresses)) + if err != nil { + return nil, err + } + response, err := c.route(appmessage.CmdGetUTXOsByAddressesResponseMessage).DequeueWithTimeout(c.timeout) + if err != nil { + return nil, err + } + getUTXOsByAddressesResponse := response.(*appmessage.GetUTXOsByAddressesResponseMessage) + if getUTXOsByAddressesResponse.Error != nil { + return nil, c.convertRPCError(getUTXOsByAddressesResponse.Error) + } + return getUTXOsByAddressesResponse, nil +} diff --git a/infrastructure/network/rpcclient/rpc_get_virtual_selected_parent_blue_score.go b/infrastructure/network/rpcclient/rpc_get_virtual_selected_parent_blue_score.go new file mode 100644 index 000000000..037cd1c74 --- /dev/null +++ b/infrastructure/network/rpcclient/rpc_get_virtual_selected_parent_blue_score.go @@ -0,0 +1,20 @@ +package rpcclient + +import "github.com/kaspanet/kaspad/app/appmessage" + +// GetVirtualSelectedParentBlueScore sends an RPC request respective to the function's name and returns the RPC server's response +func (c *RPCClient) GetVirtualSelectedParentBlueScore() (*appmessage.GetVirtualSelectedParentBlueScoreResponseMessage, error) { + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetVirtualSelectedParentBlueScoreRequestMessage()) + if err != nil { + return nil, err + } + response, err := c.route(appmessage.CmdGetVirtualSelectedParentBlueScoreResponseMessage).DequeueWithTimeout(c.timeout) + if err != nil { + return nil, err + } + getVirtualSelectedParentBlueScoreResponse := response.(*appmessage.GetVirtualSelectedParentBlueScoreResponseMessage) + if getVirtualSelectedParentBlueScoreResponse.Error != nil { + return nil, c.convertRPCError(getVirtualSelectedParentBlueScoreResponse.Error) + } + return getVirtualSelectedParentBlueScoreResponse, nil +} diff --git a/infrastructure/network/rpcclient/rpc_on_utxos_changed.go b/infrastructure/network/rpcclient/rpc_on_utxos_changed.go new file mode 100644 index 000000000..49916c66b --- /dev/null +++ b/infrastructure/network/rpcclient/rpc_on_utxos_changed.go @@ -0,0 +1,40 @@ +package rpcclient + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/pkg/errors" +) + +// RegisterForUTXOsChangedNotifications sends an RPC request respective to the function's name and returns the RPC server's response. +// Additionally, it starts listening for the appropriate notification using the given handler function +func (c *RPCClient) RegisterForUTXOsChangedNotifications(addresses []string, + onUTXOsChanged func(notification *appmessage.UTXOsChangedNotificationMessage)) error { + + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewNotifyUTXOsChangedRequestMessage(addresses)) + if err != nil { + return err + } + response, err := c.route(appmessage.CmdNotifyUTXOsChangedResponseMessage).DequeueWithTimeout(c.timeout) + if err != nil { + return err + } + notifyUTXOsChangedResponse := response.(*appmessage.NotifyUTXOsChangedResponseMessage) + if notifyUTXOsChangedResponse.Error != nil { + return c.convertRPCError(notifyUTXOsChangedResponse.Error) + } + spawn("RegisterForUTXOsChangedNotifications", func() { + for { + notification, err := c.route(appmessage.CmdUTXOsChangedNotificationMessage).Dequeue() + if err != nil { + if errors.Is(err, routerpkg.ErrRouteClosed) { + break + } + panic(err) + } + UTXOsChangedNotification := notification.(*appmessage.UTXOsChangedNotificationMessage) + onUTXOsChanged(UTXOsChangedNotification) + } + }) + return nil +} diff --git a/infrastructure/network/rpcclient/rpc_on_virtual_selected_parent_blue_score_changed.go b/infrastructure/network/rpcclient/rpc_on_virtual_selected_parent_blue_score_changed.go new file mode 100644 index 000000000..92d1c78fe --- /dev/null +++ b/infrastructure/network/rpcclient/rpc_on_virtual_selected_parent_blue_score_changed.go @@ -0,0 +1,41 @@ +package rpcclient + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/pkg/errors" +) + +// RegisterForVirtualSelectedParentBlueScoreChangedNotifications sends an RPC request respective to the function's +// name and returns the RPC server's response. Additionally, it starts listening for the appropriate notification +// using the given handler function +func (c *RPCClient) RegisterForVirtualSelectedParentBlueScoreChangedNotifications( + onVirtualSelectedParentBlueScoreChanged func(notification *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage)) error { + + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewNotifyVirtualSelectedParentBlueScoreChangedRequestMessage()) + if err != nil { + return err + } + response, err := c.route(appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage).DequeueWithTimeout(c.timeout) + if err != nil { + return err + } + notifyVirtualSelectedParentBlueScoreChangedResponse := response.(*appmessage.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) + if notifyVirtualSelectedParentBlueScoreChangedResponse.Error != nil { + return c.convertRPCError(notifyVirtualSelectedParentBlueScoreChangedResponse.Error) + } + spawn("RegisterForVirtualSelectedParentBlueScoreChangedNotifications", func() { + for { + notification, err := c.route(appmessage.CmdVirtualSelectedParentBlueScoreChangedNotificationMessage).Dequeue() + if err != nil { + if errors.Is(err, routerpkg.ErrRouteClosed) { + break + } + panic(err) + } + VirtualSelectedParentBlueScoreChangedNotification := notification.(*appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) + onVirtualSelectedParentBlueScoreChanged(VirtualSelectedParentBlueScoreChangedNotification) + } + }) + return nil +} diff --git a/infrastructure/network/rpcclient/rpc_send_raw_transaction.go b/infrastructure/network/rpcclient/rpc_send_raw_transaction.go index 0a059383d..88bec860d 100644 --- a/infrastructure/network/rpcclient/rpc_send_raw_transaction.go +++ b/infrastructure/network/rpcclient/rpc_send_raw_transaction.go @@ -5,8 +5,8 @@ import ( ) // SubmitTransaction sends an RPC request respective to the function's name and returns the RPC server's response -func (c *RPCClient) SubmitTransaction(msgTx *appmessage.MsgTx) (*appmessage.SubmitTransactionResponseMessage, error) { - err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewSubmitTransactionRequestMessage(msgTx)) +func (c *RPCClient) SubmitTransaction(transaction *appmessage.RPCTransaction) (*appmessage.SubmitTransactionResponseMessage, error) { + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewSubmitTransactionRequestMessage(transaction)) if err != nil { return nil, err } diff --git a/testing/integration/config_test.go b/testing/integration/config_test.go index dd5253073..5309f6a23 100644 --- a/testing/integration/config_test.go +++ b/testing/integration/config_test.go @@ -35,6 +35,7 @@ func setConfig(t *testing.T, harness *appHarness) { harness.config.DataDir = randomDirectory(t) harness.config.Listeners = []string{harness.p2pAddress} harness.config.RPCListeners = []string{harness.rpcAddress} + harness.config.UTXOIndex = harness.utxoIndex } func commonConfig() *config.Config { diff --git a/testing/integration/setup_test.go b/testing/integration/setup_test.go index 174d49603..e0e2a17d9 100644 --- a/testing/integration/setup_test.go +++ b/testing/integration/setup_test.go @@ -21,6 +21,7 @@ type appHarness struct { miningAddressPrivateKey string config *config.Config database database.Database + utxoIndex bool } type harnessParams struct { @@ -28,6 +29,7 @@ type harnessParams struct { rpcAddress string miningAddress string miningAddressPrivateKey string + utxoIndex bool } // setupHarness creates a single appHarness with given parameters @@ -37,6 +39,7 @@ func setupHarness(t *testing.T, params *harnessParams) (harness *appHarness, tea rpcAddress: params.rpcAddress, miningAddress: params.miningAddress, miningAddressPrivateKey: params.miningAddressPrivateKey, + utxoIndex: params.utxoIndex, } setConfig(t, harness) diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 2e326e14a..86f7e20d2 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -42,12 +42,14 @@ func TestTxRelay(t *testing.T) { waitForPayeeToReceiveBlock(t, payeeBlockAddedChan) } - tx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee) - response, err := payer.rpcClient.SubmitTransaction(tx) + msgTx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee) + domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx) + rpcTransaction := appmessage.DomainTransactionToRPCTransaction(domainTransaction) + response, err := payer.rpcClient.SubmitTransaction(rpcTransaction) if err != nil { t.Fatalf("Error submitting transaction: %+v", err) } - txID := response.TxID + txID := response.TransactionID txAddedToMempoolChan := make(chan struct{}) diff --git a/testing/integration/utxo_index_test.go b/testing/integration/utxo_index_test.go new file mode 100644 index 000000000..c1388a335 --- /dev/null +++ b/testing/integration/utxo_index_test.go @@ -0,0 +1,192 @@ +package integration + +import ( + "encoding/hex" + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/util" + "testing" +) + +func TestUTXOIndex(t *testing.T) { + // Setup a single kaspad instance + harnessParams := &harnessParams{ + p2pAddress: p2pAddress1, + rpcAddress: rpcAddress1, + miningAddress: miningAddress1, + miningAddressPrivateKey: miningAddress1PrivateKey, + utxoIndex: true, + } + kaspad, teardown := setupHarness(t, harnessParams) + defer teardown() + + // skip the first block because it's paying to genesis script, + // which contains no outputs + mineNextBlock(t, kaspad) + + // Register for UTXO changes + const blockAmountToMine = 100 + onUTXOsChangedChan := make(chan *appmessage.UTXOsChangedNotificationMessage, blockAmountToMine) + err := kaspad.rpcClient.RegisterForUTXOsChangedNotifications([]string{miningAddress1}, func( + notification *appmessage.UTXOsChangedNotificationMessage) { + + onUTXOsChangedChan <- notification + }) + if err != nil { + t.Fatalf("Failed to register for UTXO change notifications: %s", err) + } + + // Mine some blocks + for i := 0; i < blockAmountToMine; i++ { + mineNextBlock(t, kaspad) + } + + // Collect the UTXO and make sure there's nothing in Removed + // Note that we expect blockAmountToMine-1 messages because + // the last block won't be accepted until the next block is + // mined + var notificationEntries []*appmessage.UTXOsByAddressesEntry + for i := 0; i < blockAmountToMine-1; i++ { + notification := <-onUTXOsChangedChan + if len(notification.Removed) > 0 { + t.Fatalf("Unexpectedly received that a UTXO has been removed") + } + for _, added := range notification.Added { + notificationEntries = append(notificationEntries, added) + } + } + + // Submit a few transactions that spends some UTXOs + const transactionAmountToSpend = 5 + for i := 0; i < transactionAmountToSpend; i++ { + rpcTransaction := buildTransactionForUTXOIndexTest(t, notificationEntries[i]) + _, err = kaspad.rpcClient.SubmitTransaction(rpcTransaction) + if err != nil { + t.Fatalf("Error submitting transaction: %s", err) + } + } + + // Mine a block to include the above transaction + mineNextBlock(t, kaspad) + notification := <-onUTXOsChangedChan + if len(notification.Removed) > 0 { + t.Fatalf("Unexpectedly received that a UTXO has been removed") + } + for _, added := range notification.Added { + notificationEntries = append(notificationEntries, added) + } + + // Mine another block to accept the above block + mineNextBlock(t, kaspad) + + // Make sure this block removed the UTXOs we spent + notification = <-onUTXOsChangedChan + if len(notification.Removed) != transactionAmountToSpend { + t.Fatalf("Unexpected amount of removed UTXOs. Want: %d, got: %d", + transactionAmountToSpend, len(notification.Removed)) + } + for i := 0; i < transactionAmountToSpend; i++ { + entry := notificationEntries[i] + + found := false + for _, removed := range notification.Removed { + if *removed.Outpoint == *entry.Outpoint { + found = true + break + } + } + if !found { + t.Fatalf("Missing entry amongst removed UTXOs: %s:%d", + entry.Outpoint.TransactionID, entry.Outpoint.Index) + } + } + for _, added := range notification.Added { + notificationEntries = append(notificationEntries, added) + } + + // Remove the UTXOs we spent from `notificationEntries` + notificationEntries = notificationEntries[transactionAmountToSpend:] + + // Get all the UTXOs and make sure the response is equivalent + // to the data collected via notifications + utxosByAddressesResponse, err := kaspad.rpcClient.GetUTXOsByAddresses([]string{miningAddress1}) + if err != nil { + t.Fatalf("Failed to get UTXOs: %s", err) + } + if len(notificationEntries) != len(utxosByAddressesResponse.Entries) { + t.Fatalf("Unexpected amount of UTXOs. Want: %d, got: %d", + len(notificationEntries), len(utxosByAddressesResponse.Entries)) + } + for _, notificationEntry := range notificationEntries { + var foundResponseEntry *appmessage.UTXOsByAddressesEntry + for _, responseEntry := range utxosByAddressesResponse.Entries { + if *notificationEntry.Outpoint == *responseEntry.Outpoint { + foundResponseEntry = responseEntry + break + } + } + if foundResponseEntry == nil { + t.Fatalf("Missing entry in UTXOs response: %s:%d", + notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index) + } + if *notificationEntry.UTXOEntry != *foundResponseEntry.UTXOEntry { + t.Fatalf("Unexpected UTXOEntry for outpoint %s:%d. Want: %+v, got: %+v", + notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index, + notificationEntry.UTXOEntry, foundResponseEntry.UTXOEntry) + } + } +} + +func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAddressesEntry) *appmessage.RPCTransaction { + transactionIDBytes, err := hex.DecodeString(entry.Outpoint.TransactionID) + if err != nil { + t.Fatalf("Error decoding transaction ID: %s", err) + } + transactionID, err := transactionid.FromBytes(transactionIDBytes) + if err != nil { + t.Fatalf("Error decoding transaction ID: %s", err) + } + + txIns := make([]*appmessage.TxIn, 1) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(transactionID, entry.Outpoint.Index), []byte{}) + + payeeAddress, err := util.DecodeAddress(miningAddress1, util.Bech32PrefixKaspaSim) + if err != nil { + t.Fatalf("Error decoding payeeAddress: %+v", err) + } + toScript, err := txscript.PayToAddrScript(payeeAddress) + if err != nil { + t.Fatalf("Error generating script: %+v", err) + } + + txOuts := []*appmessage.TxOut{appmessage.NewTxOut(entry.UTXOEntry.Amount-1000, toScript)} + + fromScript, err := hex.DecodeString(entry.UTXOEntry.ScriptPubKey) + if err != nil { + t.Fatalf("Error decoding script public key: %s", err) + } + + msgTx := appmessage.NewNativeMsgTx(constants.TransactionVersion, txIns, txOuts) + + privateKeyBytes, err := hex.DecodeString(miningAddress1PrivateKey) + if err != nil { + t.Fatalf("Error decoding private key: %+v", err) + } + privateKey, err := secp256k1.DeserializePrivateKeyFromSlice(privateKeyBytes) + if err != nil { + t.Fatalf("Error deserializing private key: %+v", err) + } + + signatureScript, err := txscript.SignatureScript(appmessage.MsgTxToDomainTransaction(msgTx), 0, + fromScript, txscript.SigHashAll, privateKey) + if err != nil { + t.Fatalf("Error signing transaction: %+v", err) + } + msgTx.TxIn[0].SignatureScript = signatureScript + + domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx) + return appmessage.DomainTransactionToRPCTransaction(domainTransaction) +} diff --git a/testing/integration/virtual_selected_parent_blue_score_test.go b/testing/integration/virtual_selected_parent_blue_score_test.go new file mode 100644 index 000000000..b005da809 --- /dev/null +++ b/testing/integration/virtual_selected_parent_blue_score_test.go @@ -0,0 +1,62 @@ +package integration + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "testing" +) + +func TestVirtualSelectedParentBlueScore(t *testing.T) { + // Setup a single kaspad instance + harnessParams := &harnessParams{ + p2pAddress: p2pAddress1, + rpcAddress: rpcAddress1, + miningAddress: miningAddress1, + miningAddressPrivateKey: miningAddress1PrivateKey, + utxoIndex: true, + } + kaspad, teardown := setupHarness(t, harnessParams) + defer teardown() + + // Make sure that the initial blue score is 1 + response, err := kaspad.rpcClient.GetVirtualSelectedParentBlueScore() + if err != nil { + t.Fatalf("Error getting virtual selected parent blue score: %s", err) + } + if response.BlueScore != 1 { + t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d", + 1, response.BlueScore) + } + + // Register to virtual selected parent blue score changes + onVirtualSelectedParentBlueScoreChangedChan := make(chan *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) + err = kaspad.rpcClient.RegisterForVirtualSelectedParentBlueScoreChangedNotifications( + func(notification *appmessage.VirtualSelectedParentBlueScoreChangedNotificationMessage) { + onVirtualSelectedParentBlueScoreChangedChan <- notification + }) + if err != nil { + t.Fatalf("Failed to register for virtual selected parent "+ + "blue score change notifications: %s", err) + } + + // Mine some blocks and make sure that the notifications + // report correct blue score values + const blockAmountToMine = 100 + for i := 0; i < blockAmountToMine; i++ { + mineNextBlock(t, kaspad) + notification := <-onVirtualSelectedParentBlueScoreChangedChan + if notification.VirtualSelectedParentBlueScore != 2+uint64(i) { + t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d", + 2+uint64(i), notification.VirtualSelectedParentBlueScore) + } + } + + // Make sure that the blue score after all that mining is as expected + response, err = kaspad.rpcClient.GetVirtualSelectedParentBlueScore() + if err != nil { + t.Fatalf("Error getting virtual selected parent blue score: %s", err) + } + if response.BlueScore != 1+blockAmountToMine { + t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d", + 1+blockAmountToMine, response.BlueScore) + } +} From 9f8f0fd7476e39f96999e399f7b23d4143c9183a Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 21 Dec 2020 11:30:43 +0200 Subject: [PATCH 142/351] Added safeguard against running TestDifficulty with a fresh genesis block (#1251) --- .../blockvalidator/block_header_in_isolation.go | 1 - .../difficultymanager/difficultymanager_test.go | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 01622825d..4578aef10 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -47,7 +47,6 @@ func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader } func (v *blockValidator) checkBlockTimestampInIsolation(header *externalapi.DomainBlockHeader) error { - blockTimestamp := header.TimeInMilliseconds now := mstime.Now().UnixMilliseconds() maxCurrentTime := now + int64(v.timestampDeviationTolerance)*v.targetTimePerBlock.Milliseconds() diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index cc66953a8..eef999e2a 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -2,6 +2,9 @@ package difficultymanager_test import ( "testing" + "time" + + "github.com/kaspanet/kaspad/util/mstime" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" @@ -18,6 +21,14 @@ func TestDifficulty(t *testing.T) { if params.DisableDifficultyAdjustment { return } + // This test generates 3066 blocks above genesis with at least 1 second between each block, amounting to + // a bit less then an hour of timestamps. + // To prevent rejected blocks due to timestamps in the future, the following safeguard makes sure + // the genesis block is at least 1 hour in the past. + if params.GenesisBlock.Header.TimeInMilliseconds > mstime.ToMSTime(time.Now().Add(-time.Hour)).UnixMilliseconds() { + t.Fatalf("TestDifficulty requires the GenesisBlock to be at least 1 hour old to pass") + } + params.K = 1 params.DifficultyAdjustmentWindowSize = 264 From 45edacfbfa006d9142acc483dafbc3a37d227c3e Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 21 Dec 2020 12:51:45 +0200 Subject: [PATCH 143/351] Replace Double-SHA256 with blake2b and implement domain seperation (#1245) * Replace default hasher (Double-SHA256) with domain seperated blake2b * Replace all hashes with domain seperated blake2b * Update the genesis blocks * Replace OP_HASH256 with OP_BLAKE2B * Fix the merkle tree by appending zeros instead of duplicating the hash when there is 1 branch left * Update tests * Add a payloadHash function * Update gitignore to ignore binaries * Fix a bug in the blake2b opcode --- .gitignore | 18 ++++- app/appmessage/p2p_msgtx.go | 5 +- app/appmessage/p2p_msgtx_test.go | 20 +++-- domain/consensus/consensus_test.go | 1 - domain/consensus/model/pow/pow.go | 18 ++--- .../block_body_in_isolation_test.go | 40 +++++----- .../coinbasemanager/coinbasemanager.go | 2 +- .../dagtraversalmanager/window_test.go | 54 ++++++------- .../processes/pruningmanager/pruning_test.go | 4 +- .../transaction_in_isolation.go | 2 +- .../transaction_in_isolation_test.go | 4 +- .../consensus/ruleerrors/rule_error_test.go | 2 +- .../consensus/utils/consensushashing/block.go | 6 +- .../utils/consensushashing/transaction.go | 14 ++-- domain/consensus/utils/hashes/domains.go | 79 +++++++++++++++++++ domain/consensus/utils/hashes/helpers.go | 10 +++ domain/consensus/utils/hashes/writers.go | 45 ++++------- domain/consensus/utils/merkle/merkle.go | 20 ++--- .../consensus/utils/transactionhelper/new.go | 2 +- .../utils/txscript/data/script_tests.json | 18 ++--- domain/consensus/utils/txscript/opcode.go | 19 +++-- .../consensus/utils/txscript/opcode_test.go | 2 +- domain/consensus/utils/txscript/script.go | 2 +- .../consensus/utils/txscript/script_test.go | 8 +- domain/dagconfig/genesis.go | 74 ++++++++--------- 25 files changed, 270 insertions(+), 199 deletions(-) create mode 100644 domain/consensus/utils/hashes/domains.go create mode 100644 domain/consensus/utils/hashes/helpers.go diff --git a/.gitignore b/.gitignore index 7253f83dc..0fa51a09d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,21 @@ kaspad.db *.o *.a *.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Real binaries, build with `go build .` +kaspad +cmd/gencerts/gencerts +cmd/kaspactl/kaspactl +cmd/kasminer/kaspaminer +*.exe +*.exe~ + +# Output of the go coverage tool +*.out # Folders _obj @@ -31,8 +46,7 @@ _cgo_export.* _testmain.go -*.exe - + # IDE .idea .vscode diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index 1cfad151c..54c367418 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -6,14 +6,13 @@ package appmessage import ( "encoding/binary" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "strconv" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -285,7 +284,7 @@ func newMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, subnetworkID *externa var payloadHash externalapi.DomainHash if *subnetworkID != subnetworks.SubnetworkIDNative { - payloadHash = *hashes.HashData(payload) + payloadHash = *hashes.PayloadHash(payload) } return &MsgTx{ diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index 417b305f5..7e25eceea 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -131,11 +131,15 @@ func TestTx(t *testing.T) { // TestTxHash tests the ability to generate the hash of a transaction accurately. func TestTxHashAndID(t *testing.T) { - txID1Str := "a3d29c39bfb578235e4813cc8138a9ba10def63acad193a7a880159624840d7f" + txHash1Str := "c2ac1e792c5c49260103ad9f86caf749d431958b7c7e5e5129346ceab8b709cf" + txID1Str := "47ce12a5ee5727cf97c0481eebedad0d80646b743305b0921a2403f1836f8b37" wantTxID1, err := transactionid.FromString(txID1Str) if err != nil { - t.Errorf("NewTxIDFromStr: %v", err) - return + t.Fatalf("NewTxIDFromStr: %v", err) + } + wantTxHash1, err := transactionid.FromString(txHash1Str) + if err != nil { + t.Fatalf("NewTxIDFromStr: %v", err) } // A coinbase transaction @@ -167,7 +171,7 @@ func TestTxHashAndID(t *testing.T) { // Ensure the hash produced is expected. tx1Hash := tx1.TxHash() - if *tx1Hash != (externalapi.DomainHash)(*wantTxID1) { + if *tx1Hash != (externalapi.DomainHash)(*wantTxHash1) { t.Errorf("TxHash: wrong hash - got %v, want %v", spew.Sprint(tx1Hash), spew.Sprint(wantTxID1)) } @@ -179,14 +183,14 @@ func TestTxHashAndID(t *testing.T) { spew.Sprint(tx1ID), spew.Sprint(wantTxID1)) } - hash2Str := "c84f3009b337aaa3adeb2ffd41010d5f62dd773ca25b39c908a77da91f87b729" + hash2Str := "6b769655a1420022e4690a4f7bb9b1c381185ebbefe3070351f06fb573a0600c" wantHash2, err := hashes.FromString(hash2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) return } - id2Str := "7c919f676109743a1271a88beeb43849a6f9cc653f6082e59a7266f3df4802b9" + id2Str := "af916032e271adaaa21f02bee4b44db2cca4dad9149dcaebc188009c7313ec68" wantID2, err := transactionid.FromString(id2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) @@ -249,7 +253,7 @@ func TestTxHashAndID(t *testing.T) { tx2.TxIn[0].SignatureScript = []byte{} newTx2Hash := tx2.TxHash() - if *tx2ID != (externalapi.DomainTransactionID)(*newTx2Hash) { - t.Errorf("tx2ID and newTx2Hash should be the same for transaction with an empty signature") + if *tx2ID == (externalapi.DomainTransactionID)(*newTx2Hash) { + t.Errorf("tx2ID and newTx2Hash should not be the same even for transaction with an empty signature") } } diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index d262ddb6f..021811a18 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -13,7 +13,6 @@ import ( func TestConsensus_GetBlockInfo(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - factory := NewFactory() consensus, teardown, err := factory.NewTestConsensus(params, "TestConsensus_GetBlockInfo") if err != nil { diff --git a/domain/consensus/model/pow/pow.go b/domain/consensus/model/pow/pow.go index 7ac8b668a..17edd68dc 100644 --- a/domain/consensus/model/pow/pow.go +++ b/domain/consensus/model/pow/pow.go @@ -35,23 +35,17 @@ func calcPowValue(header *externalapi.DomainBlockHeader) *big.Int { header.TimeInMilliseconds, header.Nonce = timestamp, nonce // PRE_POW_HASH || TIME || 32 zero byte padding || NONCE - writer := hashes.NewHashWriter() - _, err := writer.Write(prePowHash[:]) + writer := hashes.NewPoWHashWriter() + writer.InfallibleWrite(prePowHash[:]) + err := serialization.WriteElement(writer, timestamp) if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) - } - err = serialization.WriteElement(writer, timestamp) - if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error")) } zeroes := [32]byte{} - _, err = writer.Write(zeroes[:]) - if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) - } + writer.InfallibleWrite(zeroes[:]) err = serialization.WriteElement(writer, nonce) if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error")) } return hashes.ToBig(writer.Finalize()) } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 277c05c9c..a3668bfde 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -136,10 +136,10 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ }, }, HashMerkleRoot: externalapi.DomainHash{ - 0xa2, 0x60, 0x5a, 0x45, 0xfe, 0x01, 0x41, 0xc9, - 0xc2, 0x8d, 0xe2, 0xc3, 0x2d, 0x00, 0xa4, 0x29, - 0xd4, 0x01, 0x57, 0x2d, 0x2f, 0xcd, 0x49, 0xd4, - 0xff, 0x6f, 0xab, 0xd2, 0xd1, 0x96, 0x38, 0xb9, + 0xf8, 0x55, 0x7b, 0xd0, 0xda, 0xf2, 0x06, 0x8b, + 0x3b, 0xb1, 0x93, 0x5a, 0x2c, 0x52, 0x43, 0xf0, + 0x02, 0xf2, 0xb1, 0x40, 0x81, 0x2c, 0x0c, 0x15, + 0x8d, 0x04, 0x3d, 0xe2, 0x23, 0x54, 0x98, 0x88, }, AcceptedIDMerkleRoot: externalapi.DomainHash{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, @@ -186,10 +186,10 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ SubnetworkID: subnetworks.SubnetworkIDCoinbase, Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, PayloadHash: externalapi.DomainHash{ - 0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0, - 0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc, - 0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16, - 0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7, + 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, + 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, + 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, + 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, }, }, { @@ -410,10 +410,10 @@ var exampleValidBlock = externalapi.DomainBlock{ }, }, HashMerkleRoot: externalapi.DomainHash{ - 0xce, 0xea, 0x78, 0x53, 0x7e, 0x89, 0x67, 0xaf, - 0xdc, 0x4a, 0xd1, 0x67, 0xb0, 0xc4, 0xfc, 0x6e, - 0xe5, 0x4b, 0x87, 0xb0, 0x55, 0x8f, 0xf4, 0x6b, - 0x05, 0x4d, 0x43, 0x0a, 0xb6, 0xbb, 0xe8, 0xdf, + 0x33, 0x70, 0xa7, 0x40, 0x9f, 0x2d, 0x87, 0xe1, + 0x26, 0xaf, 0x0f, 0x5c, 0x7e, 0xc3, 0x84, 0x5e, + 0x4f, 0x68, 0x42, 0x0a, 0xbf, 0x90, 0xcd, 0xef, + 0x94, 0x9b, 0xe1, 0x9a, 0xf7, 0xdd, 0xb0, 0xb5, }, AcceptedIDMerkleRoot: externalapi.DomainHash{ 0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3, @@ -458,10 +458,10 @@ var exampleValidBlock = externalapi.DomainBlock{ SubnetworkID: subnetworks.SubnetworkIDCoinbase, Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, PayloadHash: externalapi.DomainHash{ - 0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0, - 0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc, - 0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16, - 0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7, + 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, + 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, + 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, + 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, }, }, { @@ -765,10 +765,10 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ SubnetworkID: subnetworks.SubnetworkIDCoinbase, Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, PayloadHash: externalapi.DomainHash{ - 0x95, 0x7b, 0xde, 0x03, 0xa6, 0x26, 0x1f, 0xf0, - 0x95, 0x5d, 0x2c, 0x92, 0x07, 0x4b, 0x5c, 0xdc, - 0xd5, 0xbb, 0x9f, 0x7d, 0x8f, 0xeb, 0x61, 0x16, - 0xe3, 0xe5, 0x77, 0x16, 0x5e, 0x98, 0x82, 0xa7, + 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, + 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, + 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, + 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, }, }, { diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index 21c66980b..a9146818e 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -48,7 +48,7 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom return nil, err } - payloadHash := hashes.HashData(payload) + payloadHash := hashes.PayloadHash(payload) return &externalapi.DomainTransaction{ Version: constants.TransactionVersion, diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 50162c744..1f5922ccc 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -129,37 +129,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "C", "H", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "H", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "H", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "H", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "H", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, }, }, "kaspa-devnet": { @@ -181,12 +181,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"C", "D"}, id: "E", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"C", "D"}, id: "F", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -201,37 +201,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "H", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "H", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "H", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"}, }, }, "kaspa-simnet": { @@ -251,14 +251,14 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"C", "D"}, + parents: []string{"D", "C"}, id: "E", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"C", "D"}, + parents: []string{"D", "C"}, id: "F", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -273,37 +273,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "D", "H", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "C", "H", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "H", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "H", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "H", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "H", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "H", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "H", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "H", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "H", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"}, }, }, } diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index 86ad3d352..d2b150809 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -34,8 +34,8 @@ func TestPruning(t *testing.T) { "dag-for-test-pruning.json": { "kaspa-mainnet": "503", "kaspa-simnet": "502", - "kaspa-devnet": "502", - "kaspa-testnet": "502", + "kaspa-devnet": "503", + "kaspa-testnet": "503", }, } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index 021d427b9..e6ad7e4ef 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -127,7 +127,7 @@ func (v *transactionValidator) checkCoinbaseLength(tx *externalapi.DomainTransac func (v *transactionValidator) checkTransactionPayloadHash(tx *externalapi.DomainTransaction) error { if tx.SubnetworkID != subnetworks.SubnetworkIDNative { - payloadHash := hashes.HashData(tx.Payload) + payloadHash := hashes.PayloadHash(tx.Payload) if tx.PayloadHash != *payloadHash { return errors.Wrapf(ruleerrors.ErrInvalidPayloadHash, "invalid payload hash") } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go index 15d12ab62..54cafe183 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -1,13 +1,13 @@ package transactionvalidator_test import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "testing" "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" @@ -113,7 +113,7 @@ func TestValidateTransactionInIsolation(t *testing.T) { subnetworks.SubnetworkIDNative, nil, func(tx *externalapi.DomainTransaction) { - tx.PayloadHash = *hashes.HashData(tx.Payload) + tx.PayloadHash = *hashes.PayloadHash(tx.Payload) }, ruleerrors.ErrInvalidPayloadHash}, } diff --git a/domain/consensus/ruleerrors/rule_error_test.go b/domain/consensus/ruleerrors/rule_error_test.go index 5aafee0df..5c95aafff 100644 --- a/domain/consensus/ruleerrors/rule_error_test.go +++ b/domain/consensus/ruleerrors/rule_error_test.go @@ -41,7 +41,7 @@ func TestNewErrMissingTxOut(t *testing.T) { func TestNewErrInvalidTransactionsInNewBlock(t *testing.T) { outer := NewErrInvalidTransactionsInNewBlock([]InvalidTransaction{{&externalapi.DomainTransaction{Fee: 1337}, ErrNoTxInputs}}) //TODO: Implement Stringer for `DomainTransaction` - expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(3a464e1e43410c7add1dd81c3f10486f41eb473bb43e8d64feca3c7f0c8028d3: ErrNoTxInputs)]" + expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(4ea5363088df94b7b52afa9df9db7b44561e0a2219f2bf85b2f1d699cade933e: ErrNoTxInputs)]" inner := &ErrInvalidTransactionsInNewBlock{} if !errors.As(outer, inner) { t.Fatal("TestNewErrInvalidTransactionsInNewBlock: Outer should contain ErrInvalidTransactionsInNewBlock in it") diff --git a/domain/consensus/utils/consensushashing/block.go b/domain/consensus/utils/consensushashing/block.go index be4c2c8f2..83c5d5ede 100644 --- a/domain/consensus/utils/consensushashing/block.go +++ b/domain/consensus/utils/consensushashing/block.go @@ -17,15 +17,15 @@ func BlockHash(block *externalapi.DomainBlock) *externalapi.DomainHash { // HeaderHash returns the given header's hash func HeaderHash(header *externalapi.DomainBlockHeader) *externalapi.DomainHash { - // Encode the header and double sha256 everything prior to the number of + // Encode the header and hash everything prior to the number of // transactions. - writer := hashes.NewHashWriter() + writer := hashes.NewBlockHashWriter() err := serializeHeader(writer, header) if err != nil { // It seems like this could only happen if the writer returned an error. // and this writer should never return an error (no allocations or possible failures) // the only non-writer error path here is unknown types in `WriteElement` - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error")) } return writer.Finalize() diff --git a/domain/consensus/utils/consensushashing/transaction.go b/domain/consensus/utils/consensushashing/transaction.go index 182f00136..79c3ad2f6 100644 --- a/domain/consensus/utils/consensushashing/transaction.go +++ b/domain/consensus/utils/consensushashing/transaction.go @@ -30,9 +30,9 @@ const ( // TransactionHashForSigning hashes the transaction and the given hash type in a way that is intended for // signatures. func TransactionHashForSigning(tx *externalapi.DomainTransaction, hashType uint32) *externalapi.DomainHash { - // Encode the header and double sha256 everything prior to the number of + // Encode the header and hash everything prior to the number of // transactions. - writer := hashes.NewHashWriter() + writer := hashes.NewTransactionSigningHashWriter() err := serializeTransaction(writer, tx, txEncodingExcludePayload) if err != nil { // It seems like this could only happen if the writer returned an error. @@ -43,7 +43,7 @@ func TransactionHashForSigning(tx *externalapi.DomainTransaction, hashType uint3 err = serialization.WriteElement(writer, hashType) if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) + panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error")) } return writer.Finalize() @@ -51,9 +51,9 @@ func TransactionHashForSigning(tx *externalapi.DomainTransaction, hashType uint3 // TransactionHash returns the transaction hash. func TransactionHash(tx *externalapi.DomainTransaction) *externalapi.DomainHash { - // Encode the header and double sha256 everything prior to the number of + // Encode the header and hash everything prior to the number of // transactions. - writer := hashes.NewHashWriter() + writer := hashes.NewTransactionHashWriter() err := serializeTransaction(writer, tx, txEncodingExcludePayload) if err != nil { // It seems like this could only happen if the writer returned an error. @@ -73,12 +73,12 @@ func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransac } // Encode the transaction, replace signature script with zeroes, cut off - // payload and calculate double sha256 on the result. + // payload and hash the result. var encodingFlags txEncoding if !transactionhelper.IsCoinBase(tx) { encodingFlags = txEncodingExcludeSignatureScript | txEncodingExcludePayload } - writer := hashes.NewHashWriter() + writer := hashes.NewTransactionIDWriter() err := serializeTransaction(writer, tx, encodingFlags) if err != nil { // this writer never return errors (no allocations or possible failures) so errors can only come from validity checks, diff --git a/domain/consensus/utils/hashes/domains.go b/domain/consensus/utils/hashes/domains.go new file mode 100644 index 000000000..7dd5cdd4c --- /dev/null +++ b/domain/consensus/utils/hashes/domains.go @@ -0,0 +1,79 @@ +package hashes + +import ( + "github.com/pkg/errors" + "golang.org/x/crypto/blake2b" +) + +const ( + transcationHashDomain = "TransactionHash" + transcationIDDomain = "TransactionID" + transcationSigningDomain = "TransactionSigningHash" + payloadDomain = "PayloadHash" + blockDomain = "BlockHash" + proofOfWorkDomain = "ProofOfWorkHash" + merkleBranchDomain = "MerkleBranchHash" +) + +// NewTransactionHashWriter Returns a new HashWriter used for transaction hashes +func NewTransactionHashWriter() HashWriter { + blake, err := blake2b.New256([]byte(transcationHashDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", transcationHashDomain)) + } + return HashWriter{blake} +} + +// NewTransactionIDWriter Returns a new HashWriter used for transaction IDs +func NewTransactionIDWriter() HashWriter { + blake, err := blake2b.New256([]byte(transcationIDDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", transcationIDDomain)) + } + return HashWriter{blake} +} + +// NewTransactionSigningHashWriter Returns a new HashWriter used for signing on a transaction +func NewTransactionSigningHashWriter() HashWriter { + blake, err := blake2b.New256([]byte(transcationSigningDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", transcationSigningDomain)) + } + return HashWriter{blake} +} + +// NewPayloadHashWriter Returns a new HashWriter used for hashing a transaction payload +func NewPayloadHashWriter() HashWriter { + blake, err := blake2b.New256([]byte(payloadDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", payloadDomain)) + } + return HashWriter{blake} +} + +// NewBlockHashWriter Returns a new HashWriter used for hashing blocks +func NewBlockHashWriter() HashWriter { + blake, err := blake2b.New256([]byte(blockDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", blockDomain)) + } + return HashWriter{blake} +} + +// NewPoWHashWriter Returns a new HashWriter used for the PoW function +func NewPoWHashWriter() HashWriter { + blake, err := blake2b.New256([]byte(proofOfWorkDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", proofOfWorkDomain)) + } + return HashWriter{blake} +} + +// NewMerkleBranchHashWriter Returns a new HashWriter used for a merkle tree branch +func NewMerkleBranchHashWriter() HashWriter { + blake, err := blake2b.New256([]byte(merkleBranchDomain)) + if err != nil { + panic(errors.Wrapf(err, "this should never happen. %s is less than 64 bytes", merkleBranchDomain)) + } + return HashWriter{blake} +} diff --git a/domain/consensus/utils/hashes/helpers.go b/domain/consensus/utils/hashes/helpers.go new file mode 100644 index 000000000..f7a20f872 --- /dev/null +++ b/domain/consensus/utils/hashes/helpers.go @@ -0,0 +1,10 @@ +package hashes + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// PayloadHash returns the payload hash. +func PayloadHash(payload []byte) *externalapi.DomainHash { + writer := NewPayloadHashWriter() + writer.InfallibleWrite(payload) + return writer.Finalize() +} diff --git a/domain/consensus/utils/hashes/writers.go b/domain/consensus/utils/hashes/writers.go index 22384c7d1..7b5958dda 100644 --- a/domain/consensus/utils/hashes/writers.go +++ b/domain/consensus/utils/hashes/writers.go @@ -1,45 +1,32 @@ package hashes import ( - "crypto/sha256" - "hash" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" + "hash" ) // HashWriter is used to incrementally hash data without concatenating all of the data to a single buffer // it exposes an io.Writer api and a Finalize function to get the resulting hash. -// The used hash function is double-sha256. +// The used hash function is blake2b. +// This can only be created via one of the domain separated constructors type HashWriter struct { - inner hash.Hash + hash.Hash } -// NewHashWriter Returns a new HashWriter -func NewHashWriter() *HashWriter { - return &HashWriter{sha256.New()} +// InfallibleWrite is just like write but doesn't return anything +func (h HashWriter) InfallibleWrite(p []byte) { + // This write can never return an error, this is part of the hash.Hash interface contract. + _, err := h.Write(p) + if err != nil { + panic(errors.Wrap(err, "this should never happen. hash.Hash interface promises to not return errors.")) + } } -// Write will always return (len(p), nil) -func (h *HashWriter) Write(p []byte) (n int, err error) { - return h.inner.Write(p) -} - -// Finalize returns the resulting double hash -func (h *HashWriter) Finalize() *externalapi.DomainHash { - firstHashInTheSum := h.inner.Sum(nil) - sum := externalapi.DomainHash(sha256.Sum256(firstHashInTheSum)) - +// Finalize returns the resulting hash +func (h HashWriter) Finalize() *externalapi.DomainHash { + var sum externalapi.DomainHash + // This should prevent `Sum` for allocating an output buffer, by using the DomainHash buffer. we still copy because we don't want to rely on that. + copy(sum[:], h.Sum(sum[:0])) return &sum } - -// HashData hashes the given byte slice -func HashData(data []byte) *externalapi.DomainHash { - w := NewHashWriter() - _, err := w.Write(data) - if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) - } - - return w.Finalize() -} diff --git a/domain/consensus/utils/merkle/merkle.go b/domain/consensus/utils/merkle/merkle.go index 432c4e3b4..9eb6686a3 100644 --- a/domain/consensus/utils/merkle/merkle.go +++ b/domain/consensus/utils/merkle/merkle.go @@ -6,7 +6,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/pkg/errors" ) // nextPowerOfTwo returns the next highest power of two from a given number if @@ -28,17 +27,10 @@ func nextPowerOfTwo(n int) int { // function used to aid in the generation of a merkle tree. func hashMerkleBranches(left, right *externalapi.DomainHash) *externalapi.DomainHash { // Concatenate the left and right nodes. - w := hashes.NewHashWriter() + w := hashes.NewMerkleBranchHashWriter() - _, err := w.Write(left[:]) - if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) - } - - _, err = w.Write(right[:]) - if err != nil { - panic(errors.Wrap(err, "this should never happen. SHA256's digest should never return an error")) - } + w.InfallibleWrite(left[:]) + w.InfallibleWrite(right[:]) return w.Finalize() } @@ -90,12 +82,12 @@ func merkleRoot(hashes []*externalapi.DomainHash) *externalapi.DomainHash { merkles[offset] = nil // When there is no right child, the parent is generated by - // hashing the concatenation of the left child with itself. + // hashing the concatenation of the left child with zeros. case merkles[i+1] == nil: - newHash := hashMerkleBranches(merkles[i], merkles[i]) + newHash := hashMerkleBranches(merkles[i], &externalapi.DomainHash{}) merkles[offset] = newHash - // The normal case sets the parent node to the double sha256 + // The normal case sets the parent node to the hash // of the concatentation of the left and right children. default: newHash := hashMerkleBranches(merkles[i], merkles[i+1]) diff --git a/domain/consensus/utils/transactionhelper/new.go b/domain/consensus/utils/transactionhelper/new.go index 927d3c032..b796baf27 100644 --- a/domain/consensus/utils/transactionhelper/new.go +++ b/domain/consensus/utils/transactionhelper/new.go @@ -11,7 +11,7 @@ func NewSubnetworkTransaction(version int32, inputs []*externalapi.DomainTransac outputs []*externalapi.DomainTransactionOutput, subnetworkID *externalapi.DomainSubnetworkID, gas uint64, payload []byte) *externalapi.DomainTransaction { - payloadHash := hashes.HashData(payload) + payloadHash := hashes.PayloadHash(payload) return &externalapi.DomainTransaction{ Version: version, Inputs: inputs, diff --git a/domain/consensus/utils/txscript/data/script_tests.json b/domain/consensus/utils/txscript/data/script_tests.json index 62e93c31a..5e53e21ce 100644 --- a/domain/consensus/utils/txscript/data/script_tests.json +++ b/domain/consensus/utils/txscript/data/script_tests.json @@ -1197,12 +1197,6 @@ "", "OK" ], - [ - "''", - "DUP HASH256 SWAP SHA256 SHA256 EQUAL", - "", - "OK" - ], [ "''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", @@ -1224,19 +1218,19 @@ ], [ "''", - "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", + "BLAKE2B 0x20 0x0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8 EQUAL", "", "OK" ], [ "'a'", - "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", + "BLAKE2B 0x20 0x8928aae63c84d87ea098564d1e03ad813f107add474e56aedd286349c0c03ea4 EQUAL", "", "OK" ], [ "'abcdefghijklmnopqrstuvwxyz'", - "HASH256 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", + "BLAKE2B 0x20 0x117ad6b940f5e8292c007d9c7e7350cd33cf85b5887e8da71c7957830f536e7c EQUAL", "", "OK" ], @@ -2225,7 +2219,7 @@ ], [ "0", - "HASH256", + "BLAKE2B", "", "OK" ], @@ -4326,7 +4320,7 @@ ], [ "", - "HASH256", + "BLAKE2B", "", "INVALID_STACK_OPERATION" ], @@ -4803,7 +4797,7 @@ ], [ "", - "HASH256 1", + "BLAKE2B 1", "", "INVALID_STACK_OPERATION" ], diff --git a/domain/consensus/utils/txscript/opcode.go b/domain/consensus/utils/txscript/opcode.go index 6c83230f7..3bc115284 100644 --- a/domain/consensus/utils/txscript/opcode.go +++ b/domain/consensus/utils/txscript/opcode.go @@ -10,13 +10,12 @@ import ( "crypto/sha256" "encoding/binary" "fmt" + "golang.org/x/crypto/blake2b" "hash" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/go-secp256k1" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "golang.org/x/crypto/ripemd160" ) @@ -205,7 +204,7 @@ const ( OpSHA1 = 0xa7 // 167 OpSHA256 = 0xa8 // 168 OpHash160 = 0xa9 // 169 - OpHash256 = 0xaa // 170 + OpBlake2b = 0xaa // 170 OpUnknown171 = 0xab // 171 OpCheckSig = 0xac // 172 OpCheckSigVerify = 0xad // 173 @@ -489,7 +488,7 @@ var opcodeArray = [256]opcode{ OpSHA1: {OpSHA1, "OP_SHA1", 1, opcodeSha1}, OpSHA256: {OpSHA256, "OP_SHA256", 1, opcodeSha256}, OpHash160: {OpHash160, "OP_HASH160", 1, opcodeHash160}, - OpHash256: {OpHash256, "OP_HASH256", 1, opcodeHash256}, + OpBlake2b: {OpBlake2b, "OP_BLAKE2B", 1, opcodeBlake2b}, OpCheckSig: {OpCheckSig, "OP_CHECKSIG", 1, opcodeCheckSig}, OpCheckSigVerify: {OpCheckSigVerify, "OP_CHECKSIGVERIFY", 1, opcodeCheckSigVerify}, OpCheckMultiSig: {OpCheckMultiSig, "OP_CHECKMULTISIG", 1, opcodeCheckMultiSig}, @@ -1962,17 +1961,17 @@ func opcodeHash160(op *parsedOpcode, vm *Engine) error { return nil } -// opcodeHash256 treats the top item of the data stack as raw bytes and replaces -// it with sha256(sha256(data)). +// opcodeBlake2b treats the top item of the data stack as raw bytes and replaces +// it with blake2b(data). // -// Stack transformation: [... x1] -> [... sha256(sha256(x1))] -func opcodeHash256(op *parsedOpcode, vm *Engine) error { +// Stack transformation: [... x1] -> [... blake2b(x1)] +func opcodeBlake2b(op *parsedOpcode, vm *Engine) error { buf, err := vm.dstack.PopByteArray() if err != nil { return err } - - vm.dstack.PushByteArray(hashes.HashData(buf)[:]) + hash := blake2b.Sum256(buf) + vm.dstack.PushByteArray(hash[:]) return nil } diff --git a/domain/consensus/utils/txscript/opcode_test.go b/domain/consensus/utils/txscript/opcode_test.go index 348da8f46..ec5075c7d 100644 --- a/domain/consensus/utils/txscript/opcode_test.go +++ b/domain/consensus/utils/txscript/opcode_test.go @@ -72,7 +72,7 @@ func TestOpcodeDisasm(t *testing.T) { 0xa1: "OP_LESSTHANOREQUAL", 0xa2: "OP_GREATERTHANOREQUAL", 0xa3: "OP_MIN", 0xa4: "OP_MAX", 0xa5: "OP_WITHIN", 0xa6: "OP_RIPEMD160", 0xa7: "OP_SHA1", 0xa8: "OP_SHA256", - 0xa9: "OP_HASH160", 0xaa: "OP_HASH256", + 0xa9: "OP_HASH160", 0xaa: "OP_BLAKE2B", 0xac: "OP_CHECKSIG", 0xad: "OP_CHECKSIGVERIFY", 0xae: "OP_CHECKMULTISIG", 0xaf: "OP_CHECKMULTISIGVERIFY", 0xb0: "OP_CHECKLOCKTIMEVERIFY", 0xb1: "OP_CHECKSEQUENCEVERIFY", diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index acbaaf5a4..b287ff257 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -358,7 +358,7 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *external txCopy.Inputs = txCopy.Inputs[idx : idx+1] } - // The final hash is the double sha256 of both the serialized modified + // The final hash is the hash of both the serialized modified // transaction and the hash type (encoded as a 4-byte little-endian // value) appended. return consensushashing.TransactionHashForSigning(&txCopy, uint32(hashType)), nil diff --git a/domain/consensus/utils/txscript/script_test.go b/domain/consensus/utils/txscript/script_test.go index 70a08e21e..d5052e20c 100644 --- a/domain/consensus/utils/txscript/script_test.go +++ b/domain/consensus/utils/txscript/script_test.go @@ -3363,17 +3363,17 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { expectedErr: scriptError(ErrInternal, ""), }, { - name: "OP_HASH256", + name: "OP_BLAKE2B", pop: &parsedOpcode{ - opcode: &opcodeArray[OpHash256], + opcode: &opcodeArray[OpBlake2b], data: nil, }, expectedErr: nil, }, { - name: "OP_HASH256 long", + name: "OP_BLAKE2B long", pop: &parsedOpcode{ - opcode: &opcodeArray[OpHash256], + opcode: &opcodeArray[OpBlake2b], data: make([]byte, 1), }, expectedErr: scriptError(ErrInternal, ""), diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 2b3b1c604..162ef8d23 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -28,19 +28,19 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.DomainHash{ - 0xfe, 0x18, 0xeb, 0xc3, 0x20, 0xe2, 0xdf, 0x7b, - 0xf5, 0x62, 0x27, 0xe4, 0x8c, 0x32, 0xdd, 0x06, - 0x19, 0xe2, 0xf9, 0xb1, 0xef, 0xf4, 0x96, 0x38, - 0x6b, 0x1f, 0x11, 0xba, 0x0b, 0x9f, 0x92, 0xa8, + 0x8c, 0x74, 0x62, 0xc9, 0xb6, 0xa8, 0xb2, 0x7c, + 0x8d, 0x03, 0xa3, 0x7e, 0x45, 0x73, 0x31, 0x77, + 0xc7, 0xe1, 0x00, 0xa8, 0xc7, 0x75, 0xe9, 0xaa, + 0x31, 0x02, 0xa9, 0x82, 0x9f, 0xad, 0x34, 0xc8, } // genesisMerkleRoot is the hash of the first transaction in the genesis block // for the main network. var genesisMerkleRoot = externalapi.DomainHash{ - 0x2f, 0x55, 0x37, 0x11, 0x8a, 0x30, 0xcd, 0xcd, - 0xa7, 0xdb, 0xe5, 0xe6, 0x42, 0xf9, 0x1b, 0xf3, - 0xb4, 0x62, 0xd6, 0xb6, 0xed, 0xc0, 0x5c, 0xe1, - 0x6e, 0xee, 0x0f, 0x3c, 0xdc, 0xf6, 0x01, 0x15, + 0x32, 0xea, 0x93, 0x9a, 0x1f, 0x00, 0x50, 0xc3, + 0x97, 0x2c, 0x3d, 0xdf, 0x28, 0xb4, 0x8f, 0x1d, + 0x75, 0x9f, 0xb1, 0x82, 0x99, 0x79, 0x7a, 0x48, + 0xc9, 0xf6, 0x05, 0xc6, 0xae, 0x30, 0x49, 0xf7, } // genesisBlock defines the genesis block of the block DAG which serves as the @@ -54,7 +54,7 @@ var genesisBlock = externalapi.DomainBlock{ UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x1763db5c4a9, Bits: 0x207fffff, - Nonce: 0x0, + Nonce: 0x1, }, Transactions: []*externalapi.DomainTransaction{genesisCoinbaseTx}, } @@ -79,19 +79,19 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.DomainHash{ - 0x13, 0x2d, 0xfc, 0xf3, 0xcf, 0x03, 0xfb, 0x21, - 0x30, 0xb8, 0x67, 0x79, 0xbc, 0x2e, 0x18, 0x4e, - 0x08, 0xd7, 0xeb, 0xf7, 0xb6, 0x86, 0x3c, 0x3e, - 0xe0, 0x8c, 0x8d, 0x02, 0x3c, 0xfd, 0xfe, 0x66, + 0xee, 0xce, 0x68, 0x63, 0x61, 0xb4, 0xa8, 0x09, + 0x5d, 0xa3, 0x91, 0x6c, 0x12, 0x20, 0x27, 0xdd, + 0xf8, 0x16, 0x74, 0x8e, 0xd8, 0x7a, 0xfe, 0x2c, + 0xb7, 0x98, 0xe6, 0x9d, 0x47, 0x07, 0x02, 0xc5, } // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. var devnetGenesisMerkleRoot = externalapi.DomainHash{ - 0x00, 0x94, 0xfd, 0xff, 0x4d, 0xb2, 0x4d, 0x18, - 0x95, 0x21, 0x36, 0x2a, 0x14, 0xfb, 0x19, 0x7a, - 0x99, 0x51, 0x7e, 0x3f, 0x44, 0xf6, 0x2e, 0x0b, - 0xe7, 0xb3, 0xc0, 0xbb, 0x00, 0x3b, 0x0b, 0xbd, + 0xdf, 0x52, 0x65, 0x3a, 0x5a, 0xd4, 0x07, 0x4e, + 0xad, 0xac, 0xb3, 0xd7, 0xd6, 0x9a, 0xf5, 0xd3, + 0x68, 0x05, 0x4d, 0xef, 0xd9, 0x41, 0x28, 0x84, + 0xa9, 0x56, 0xdd, 0x68, 0x60, 0x1b, 0x8d, 0x2c, } // devnetGenesisBlock defines the genesis block of the block DAG which serves as the @@ -105,7 +105,7 @@ var devnetGenesisBlock = externalapi.DomainBlock{ UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x1763db5c4a9, Bits: 0x1e7fffff, - Nonce: 0x281ad, + Nonce: 0xb6c8, }, Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -129,19 +129,19 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0xda, 0xcc, 0x82, 0xd2, 0xf2, 0x53, 0x49, 0x48, - 0x18, 0x9e, 0x08, 0x8f, 0xd3, 0xe1, 0xbc, 0xce, - 0xb6, 0x0d, 0x48, 0xa6, 0x51, 0x53, 0xe1, 0xc1, - 0xa7, 0xa7, 0x10, 0x8a, 0xde, 0x96, 0xa3, 0x4d, + 0xe3, 0xa4, 0x4a, 0xe5, 0xdc, 0x3d, 0x39, 0x6a, + 0xc8, 0x5b, 0x1b, 0x95, 0x30, 0x05, 0x7d, 0xb9, + 0xd4, 0xfa, 0x30, 0x9a, 0x20, 0x7a, 0x42, 0x54, + 0xf8, 0x10, 0x73, 0xc0, 0x15, 0x31, 0xf5, 0x1a, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. var simnetGenesisMerkleRoot = externalapi.DomainHash{ - 0x79, 0x77, 0x9c, 0xad, 0x8d, 0x5a, 0x37, 0x57, - 0x75, 0x8b, 0x2f, 0xa5, 0x82, 0x47, 0x2f, 0xb6, - 0xbe, 0x24, 0x5f, 0xcb, 0x21, 0x68, 0x21, 0x44, - 0x45, 0x39, 0x44, 0xaf, 0xab, 0x9f, 0x0f, 0xc1, + 0x16, 0x07, 0x15, 0x0f, 0x1b, 0xc0, 0x26, 0x27, + 0x42, 0xc5, 0x84, 0x77, 0xdb, 0x58, 0xf7, 0x87, + 0xa8, 0xe9, 0x9f, 0x21, 0x73, 0xa0, 0x9d, 0x96, + 0x6a, 0x99, 0x55, 0x46, 0x7b, 0xb2, 0x1b, 0x99, } // simnetGenesisBlock defines the genesis block of the block DAG which serves as the @@ -153,7 +153,7 @@ var simnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: simnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1763db5c5de, + TimeInMilliseconds: 0x1763db5c4a9, Bits: 0x207fffff, Nonce: 0x0, }, @@ -177,19 +177,19 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.DomainHash{ - 0x97, 0xb5, 0xd5, 0xf6, 0x0d, 0xfe, 0x77, 0x83, - 0x87, 0xe8, 0x06, 0x52, 0xd5, 0xbe, 0xd2, 0x5e, - 0x92, 0x5a, 0x70, 0x03, 0x2b, 0x7a, 0x75, 0x5c, - 0xc5, 0xe4, 0x73, 0xa0, 0x23, 0x47, 0x25, 0x2f, + 0x17, 0xb3, 0x16, 0xd3, 0x4f, 0xb5, 0x2c, 0xc1, + 0x22, 0x53, 0x1a, 0xc9, 0xde, 0x79, 0xc3, 0x03, + 0x53, 0xa2, 0x1a, 0x0d, 0x00, 0x40, 0x7d, 0x49, + 0x66, 0x0c, 0x76, 0xf2, 0x61, 0xe4, 0x9a, 0x23, } // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for testnet. var testnetGenesisMerkleRoot = externalapi.DomainHash{ - 0x7c, 0x5a, 0x9a, 0xb4, 0xa6, 0xd5, 0x03, 0xf3, - 0x19, 0x3c, 0x26, 0x82, 0xf5, 0x45, 0xdf, 0xe3, - 0x08, 0x6d, 0x94, 0xfc, 0x7d, 0xb9, 0x42, 0x4b, - 0x2c, 0x38, 0xf2, 0x5c, 0x64, 0xbc, 0xb4, 0x98, + 0xd7, 0x16, 0x4a, 0x38, 0x3b, 0x8a, 0x67, 0xc2, + 0x3b, 0x89, 0x12, 0x1c, 0xcb, 0x97, 0x89, 0xe1, + 0x12, 0x82, 0x12, 0xc2, 0x69, 0x95, 0x7f, 0x03, + 0x29, 0xd1, 0x4f, 0xdd, 0xf1, 0x93, 0xd8, 0x47, } // testnetGenesisBlock defines the genesis block of the block DAG which serves as the @@ -201,9 +201,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{ HashMerkleRoot: testnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1763db5c5de, + TimeInMilliseconds: 0x1763db5c4a9, Bits: 0x1e7fffff, - Nonce: 0xec6f, + Nonce: 0x493d, }, Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } From 21a459c0f4ae893bee86e6b3ae6de48cdc2896c0 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 21 Dec 2020 14:43:32 +0200 Subject: [PATCH 144/351] Implement virtual selected parent chain RPC methods (#1249) * [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-1597] Begin implementing UTXOIndex. * [NOD-1597] Connect UTXOIndex to RPC. * [NOD-1597] Connect Consensus to UTXOIndex. * [NOD-1597] Add AcceptanceData to BlockInfo. * [NOD-1597] Implement UTXOIndex.Update(). * [NOD-1597] Implement add(), remove(), and discard() in utxoIndexStore. * [NOD-1597] Add error cases to add() and remove(). * [NOD-1597] Add special cases to add() and remove(). * [NOD-1597] Implement commit. * [NOD-1597] Add a mutex around UTXOIndex.Update(). * [NOD-1597] Return changes to the UTXO from Update(). * [NOD-1597] Add NotifyUTXOsChangedRequestMessage and related structs. * [NOD-1597] Implement HandleNotifyUTXOsChanged. * [NOD-1597] Begin implementing TestUTXOIndex. * [NOD-1597] Implement RegisterForUTXOsChangedNotifications. * [NOD-1597] Fix bad transaction.ID usage. * [NOD-1597] Implement convertUTXOChangesToUTXOsChangedNotification. * [NOD-1597] Make UTXOsChangedNotificationMessage.Removed UTXOsByAddressesEntry instead of just RPCOutpoint so that the client can discern which address was the UTXO removed for. * [NOD-1597] Collect outpoints in TestUTXOIndex. * [NOD-1597] Rename RPC stuff. * [NOD-1597] Add messages for GetUTXOsByAddresses. * [NOD-1597] Implement HandleGetUTXOsByAddresses. * [NOD-1597] Implement GetUTXOsByAddresses. * [NOD-1597] Implement UTXOs(). * [NOD-1597] Implement getUTXOOutpointEntryPairs(). * [NOD-1597] Expand TestUTXOIndex. * [NOD-1597] Convert SubmitTransaction to use RPCTransaction instead of MsgTx. * [NOD-1597] Finish implementing TestUTXOIndex. * [NOD-1597] Add messages for GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement HandleGetVirtualSelectedParentBlueScore and GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement NotifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Expand TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement notifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Make go lint happy. * [NOD-1593] Fix merge errors. * [NOD-1593] Rename findSelectedParentChainChanges to calculateSelectedParentChainChanges. * [NOD-1593] Expand TestCalculateSelectedParentChainChanges. * [NOD-1597] Add logs to utxoindex.go. * [NOD-1597] Add logs to utxoindex/store.go. * [NOD-1597] Add logs to RPCManager.NotifyXXX functions. * Implement notifySelectedParentChainChanged. * Implement TestSelectedParentChain. * Rename NotifyChainChanged to NotifyVirtualSelectedParentChainChanged. * Rename GetChainFromBlock to GetVirtualSelectedParentChainFromBlock. * Remove AcceptanceIndex from the config. * Implement HandleGetVirtualSelectedParentChainFromBlock. * Expand TestVirtualSelectedParentChain. * Fix merge errors. * Add a comment. * Move a comment. --- app/appmessage/message.go | 20 +- app/appmessage/rpc_get_chain_from_block.go | 49 - ...irtual_selected_parent_chain_from_block.go | 45 + app/appmessage/rpc_notify_chain_changed.go | 69 - ...y_virtual_selected_parent_chain_changed.go | 69 + app/protocol/flowcontext/blocks.go | 15 +- app/protocol/flowcontext/orphans.go | 31 +- app/rpc/manager.go | 19 +- app/rpc/rpc.go | 4 +- app/rpc/rpccontext/chain_changed.go | 46 + app/rpc/rpccontext/notificationmanager.go | 16 +- app/rpc/rpchandlers/get_chain_from_block.go | 20 - ...irtual_selected_parent_chain_from_block.go | 44 + app/rpc/rpchandlers/notify_chain_changed.go | 19 - ...y_virtual_selected_parent_chain_changed.go | 19 + domain/consensus/consensus.go | 7 + .../database/serialization/acceptancedata.go | 9 + .../database/serialization/dbobjects.pb.go | 324 ++--- .../database/serialization/dbobjects.proto | 1 + .../model/externalapi/acceptancedata.go | 6 +- .../consensus/model/externalapi/consensus.go | 1 + .../model/externalapi/insertblockresult.go | 2 +- ...terface_processes_consensusstatemanager.go | 1 + .../blockprocessor/validateandinsertblock.go | 2 +- .../calculate_past_utxo.go | 1 + .../find_selected_parent_chain_changes.go | 40 +- ...find_selected_parent_chain_changes_test.go | 6 +- infrastructure/config/config.go | 14 - .../grpcserver/protowire/messages.pb.go | 1201 +++++++++-------- .../grpcserver/protowire/messages.proto | 23 +- .../protowire/rpc_get_chain_from_block.go | 79 -- ...irtual_selected_parent_chain_from_block.go | 58 + .../protowire/rpc_notify_chain_changed.go | 94 -- ...y_virtual_selected_parent_chain_changed.go | 94 ++ .../server/grpcserver/protowire/wire.go | 20 +- .../rpcclient/rpc_get_chain_from_block.go | 16 +- .../network/rpcclient/rpc_on_chain_changed.go | 16 +- .../integration/selected_parent_chain_test.go | 130 ++ 38 files changed, 1439 insertions(+), 1191 deletions(-) delete mode 100644 app/appmessage/rpc_get_chain_from_block.go create mode 100644 app/appmessage/rpc_get_virtual_selected_parent_chain_from_block.go delete mode 100644 app/appmessage/rpc_notify_chain_changed.go create mode 100644 app/appmessage/rpc_notify_virtual_selected_parent_chain_changed.go create mode 100644 app/rpc/rpccontext/chain_changed.go delete mode 100644 app/rpc/rpchandlers/get_chain_from_block.go create mode 100644 app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go delete mode 100644 app/rpc/rpchandlers/notify_chain_changed.go create mode 100644 app/rpc/rpchandlers/notify_virtual_selected_parent_chain_changed.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_chain_from_block.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_chain_from_block.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_chain_changed.go create mode 100644 testing/integration/selected_parent_chain_test.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 381ca4436..45b2a9918 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -79,15 +79,15 @@ const ( CmdAddPeerResponseMessage CmdSubmitTransactionRequestMessage CmdSubmitTransactionResponseMessage - CmdNotifyChainChangedRequestMessage - CmdNotifyChainChangedResponseMessage - CmdChainChangedNotificationMessage + CmdNotifyVirtualSelectedParentChainChangedRequestMessage + CmdNotifyVirtualSelectedParentChainChangedResponseMessage + CmdVirtualSelectedParentChainChangedNotificationMessage CmdGetBlockRequestMessage CmdGetBlockResponseMessage CmdGetSubnetworkRequestMessage CmdGetSubnetworkResponseMessage - CmdGetChainFromBlockRequestMessage - CmdGetChainFromBlockResponseMessage + CmdGetVirtualSelectedParentChainFromBlockRequestMessage + CmdGetVirtualSelectedParentChainFromBlockResponseMessage CmdGetBlocksRequestMessage CmdGetBlocksResponseMessage CmdGetBlockCountRequestMessage @@ -171,15 +171,15 @@ var RPCMessageCommandToString = map[MessageCommand]string{ CmdAddPeerResponseMessage: "AddPeerResponse", CmdSubmitTransactionRequestMessage: "SubmitTransactionRequest", CmdSubmitTransactionResponseMessage: "SubmitTransactionResponse", - CmdNotifyChainChangedRequestMessage: "NotifyChainChangedRequest", - CmdNotifyChainChangedResponseMessage: "NotifyChainChangedResponse", - CmdChainChangedNotificationMessage: "ChainChangedNotification", + CmdNotifyVirtualSelectedParentChainChangedRequestMessage: "NotifyVirtualSelectedParentChainChangedRequest", + CmdNotifyVirtualSelectedParentChainChangedResponseMessage: "NotifyVirtualSelectedParentChainChangedResponse", + CmdVirtualSelectedParentChainChangedNotificationMessage: "VirtualSelectedParentChainChangedNotification", CmdGetBlockRequestMessage: "GetBlockRequest", CmdGetBlockResponseMessage: "GetBlockResponse", CmdGetSubnetworkRequestMessage: "GetSubnetworkRequest", CmdGetSubnetworkResponseMessage: "GetSubnetworkResponse", - CmdGetChainFromBlockRequestMessage: "GetChainFromBlockRequest", - CmdGetChainFromBlockResponseMessage: "GetChainFromBlockResponse", + CmdGetVirtualSelectedParentChainFromBlockRequestMessage: "GetVirtualSelectedParentChainFromBlockRequest", + CmdGetVirtualSelectedParentChainFromBlockResponseMessage: "GetVirtualSelectedParentChainFromBlockResponse", CmdGetBlocksRequestMessage: "GetBlocksRequest", CmdGetBlocksResponseMessage: "GetBlocksResponse", CmdGetBlockCountRequestMessage: "GetBlockCountRequest", diff --git a/app/appmessage/rpc_get_chain_from_block.go b/app/appmessage/rpc_get_chain_from_block.go deleted file mode 100644 index 09103b04e..000000000 --- a/app/appmessage/rpc_get_chain_from_block.go +++ /dev/null @@ -1,49 +0,0 @@ -package appmessage - -// GetChainFromBlockRequestMessage is an appmessage corresponding to -// its respective RPC message -type GetChainFromBlockRequestMessage struct { - baseMessage - StartHash string - IncludeBlockVerboseData bool -} - -// Command returns the protocol command string for the message -func (msg *GetChainFromBlockRequestMessage) Command() MessageCommand { - return CmdGetChainFromBlockRequestMessage -} - -// NewGetChainFromBlockRequestMessage returns a instance of the message -func NewGetChainFromBlockRequestMessage(startHash string, includeBlockVerboseData bool) *GetChainFromBlockRequestMessage { - return &GetChainFromBlockRequestMessage{ - StartHash: startHash, - IncludeBlockVerboseData: includeBlockVerboseData, - } -} - -// GetChainFromBlockResponseMessage is an appmessage corresponding to -// its respective RPC message -type GetChainFromBlockResponseMessage struct { - baseMessage - RemovedChainBlockHashes []string - AddedChainBlocks []*ChainBlock - BlockVerboseData []*BlockVerboseData - - Error *RPCError -} - -// Command returns the protocol command string for the message -func (msg *GetChainFromBlockResponseMessage) Command() MessageCommand { - return CmdGetChainFromBlockResponseMessage -} - -// NewGetChainFromBlockResponseMessage returns a instance of the message -func NewGetChainFromBlockResponseMessage(removedChainBlockHashes []string, - addedChainBlocks []*ChainBlock, blockVerboseData []*BlockVerboseData) *GetChainFromBlockResponseMessage { - - return &GetChainFromBlockResponseMessage{ - RemovedChainBlockHashes: removedChainBlockHashes, - AddedChainBlocks: addedChainBlocks, - BlockVerboseData: blockVerboseData, - } -} diff --git a/app/appmessage/rpc_get_virtual_selected_parent_chain_from_block.go b/app/appmessage/rpc_get_virtual_selected_parent_chain_from_block.go new file mode 100644 index 000000000..f4fb1f890 --- /dev/null +++ b/app/appmessage/rpc_get_virtual_selected_parent_chain_from_block.go @@ -0,0 +1,45 @@ +package appmessage + +// GetVirtualSelectedParentChainFromBlockRequestMessage is an appmessage corresponding to +// its respective RPC message +type GetVirtualSelectedParentChainFromBlockRequestMessage struct { + baseMessage + StartHash string +} + +// Command returns the protocol command string for the message +func (msg *GetVirtualSelectedParentChainFromBlockRequestMessage) Command() MessageCommand { + return CmdGetVirtualSelectedParentChainFromBlockRequestMessage +} + +// NewGetVirtualSelectedParentChainFromBlockRequestMessage returns a instance of the message +func NewGetVirtualSelectedParentChainFromBlockRequestMessage(startHash string) *GetVirtualSelectedParentChainFromBlockRequestMessage { + return &GetVirtualSelectedParentChainFromBlockRequestMessage{ + StartHash: startHash, + } +} + +// GetVirtualSelectedParentChainFromBlockResponseMessage is an appmessage corresponding to +// its respective RPC message +type GetVirtualSelectedParentChainFromBlockResponseMessage struct { + baseMessage + RemovedChainBlockHashes []string + AddedChainBlocks []*ChainBlock + + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *GetVirtualSelectedParentChainFromBlockResponseMessage) Command() MessageCommand { + return CmdGetVirtualSelectedParentChainFromBlockResponseMessage +} + +// NewGetVirtualSelectedParentChainFromBlockResponseMessage returns a instance of the message +func NewGetVirtualSelectedParentChainFromBlockResponseMessage(removedChainBlockHashes []string, + addedChainBlocks []*ChainBlock) *GetVirtualSelectedParentChainFromBlockResponseMessage { + + return &GetVirtualSelectedParentChainFromBlockResponseMessage{ + RemovedChainBlockHashes: removedChainBlockHashes, + AddedChainBlocks: addedChainBlocks, + } +} diff --git a/app/appmessage/rpc_notify_chain_changed.go b/app/appmessage/rpc_notify_chain_changed.go deleted file mode 100644 index d559c138c..000000000 --- a/app/appmessage/rpc_notify_chain_changed.go +++ /dev/null @@ -1,69 +0,0 @@ -package appmessage - -// NotifyChainChangedRequestMessage is an appmessage corresponding to -// its respective RPC message -type NotifyChainChangedRequestMessage struct { - baseMessage -} - -// Command returns the protocol command string for the message -func (msg *NotifyChainChangedRequestMessage) Command() MessageCommand { - return CmdNotifyChainChangedRequestMessage -} - -// NewNotifyChainChangedRequestMessage returns a instance of the message -func NewNotifyChainChangedRequestMessage() *NotifyChainChangedRequestMessage { - return &NotifyChainChangedRequestMessage{} -} - -// NotifyChainChangedResponseMessage is an appmessage corresponding to -// its respective RPC message -type NotifyChainChangedResponseMessage struct { - baseMessage - Error *RPCError -} - -// Command returns the protocol command string for the message -func (msg *NotifyChainChangedResponseMessage) Command() MessageCommand { - return CmdNotifyChainChangedResponseMessage -} - -// NewNotifyChainChangedResponseMessage returns a instance of the message -func NewNotifyChainChangedResponseMessage() *NotifyChainChangedResponseMessage { - return &NotifyChainChangedResponseMessage{} -} - -// ChainChangedNotificationMessage is an appmessage corresponding to -// its respective RPC message -type ChainChangedNotificationMessage struct { - baseMessage - RemovedChainBlockHashes []string - AddedChainBlocks []*ChainBlock -} - -// ChainBlock represents a DAG chain-block -type ChainBlock struct { - Hash string - AcceptedBlocks []*AcceptedBlock -} - -// AcceptedBlock represents a block accepted into the DAG -type AcceptedBlock struct { - Hash string - AcceptedTransactionIDs []string -} - -// Command returns the protocol command string for the message -func (msg *ChainChangedNotificationMessage) Command() MessageCommand { - return CmdChainChangedNotificationMessage -} - -// NewChainChangedNotificationMessage returns a instance of the message -func NewChainChangedNotificationMessage(removedChainBlockHashes []string, - addedChainBlocks []*ChainBlock) *ChainChangedNotificationMessage { - - return &ChainChangedNotificationMessage{ - RemovedChainBlockHashes: removedChainBlockHashes, - AddedChainBlocks: addedChainBlocks, - } -} diff --git a/app/appmessage/rpc_notify_virtual_selected_parent_chain_changed.go b/app/appmessage/rpc_notify_virtual_selected_parent_chain_changed.go new file mode 100644 index 000000000..c01099083 --- /dev/null +++ b/app/appmessage/rpc_notify_virtual_selected_parent_chain_changed.go @@ -0,0 +1,69 @@ +package appmessage + +// NotifyVirtualSelectedParentChainChangedRequestMessage is an appmessage corresponding to +// its respective RPC message +type NotifyVirtualSelectedParentChainChangedRequestMessage struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *NotifyVirtualSelectedParentChainChangedRequestMessage) Command() MessageCommand { + return CmdNotifyVirtualSelectedParentChainChangedRequestMessage +} + +// NewNotifyVirtualSelectedParentChainChangedRequestMessage returns a instance of the message +func NewNotifyVirtualSelectedParentChainChangedRequestMessage() *NotifyVirtualSelectedParentChainChangedRequestMessage { + return &NotifyVirtualSelectedParentChainChangedRequestMessage{} +} + +// NotifyVirtualSelectedParentChainChangedResponseMessage is an appmessage corresponding to +// its respective RPC message +type NotifyVirtualSelectedParentChainChangedResponseMessage struct { + baseMessage + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *NotifyVirtualSelectedParentChainChangedResponseMessage) Command() MessageCommand { + return CmdNotifyVirtualSelectedParentChainChangedResponseMessage +} + +// NewNotifyVirtualSelectedParentChainChangedResponseMessage returns a instance of the message +func NewNotifyVirtualSelectedParentChainChangedResponseMessage() *NotifyVirtualSelectedParentChainChangedResponseMessage { + return &NotifyVirtualSelectedParentChainChangedResponseMessage{} +} + +// VirtualSelectedParentChainChangedNotificationMessage is an appmessage corresponding to +// its respective RPC message +type VirtualSelectedParentChainChangedNotificationMessage struct { + baseMessage + RemovedChainBlockHashes []string + AddedChainBlocks []*ChainBlock +} + +// ChainBlock represents a DAG chain-block +type ChainBlock struct { + Hash string + AcceptedBlocks []*AcceptedBlock +} + +// AcceptedBlock represents a block accepted into the DAG +type AcceptedBlock struct { + Hash string + AcceptedTransactionIDs []string +} + +// Command returns the protocol command string for the message +func (msg *VirtualSelectedParentChainChangedNotificationMessage) Command() MessageCommand { + return CmdVirtualSelectedParentChainChangedNotificationMessage +} + +// NewVirtualSelectedParentChainChangedNotificationMessage returns a instance of the message +func NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes []string, + addedChainBlocks []*ChainBlock) *VirtualSelectedParentChainChangedNotificationMessage { + + return &VirtualSelectedParentChainChangedNotificationMessage{ + RemovedChainBlockHashes: removedChainBlockHashes, + AddedChainBlocks: addedChainBlocks, + } +} diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index d83c18906..d6393ccf9 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -23,15 +23,21 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, hash := consensushashing.BlockHash(block) log.Debugf("OnNewBlock start for block %s", hash) defer log.Debugf("OnNewBlock end for block %s", hash) - unorphanedBlocks, err := f.UnorphanBlocks(block) + unorphaningResults, err := f.UnorphanBlocks(block) if err != nil { return err } - log.Debugf("OnNewBlock: block %s unorphaned %d blocks", hash, len(unorphanedBlocks)) + log.Debugf("OnNewBlock: block %s unorphaned %d blocks", hash, len(unorphaningResults)) - newBlocks := append([]*externalapi.DomainBlock{block}, unorphanedBlocks...) - for _, newBlock := range newBlocks { + newBlocks := []*externalapi.DomainBlock{block} + newBlockInsertionResults := []*externalapi.BlockInsertionResult{blockInsertionResult} + for _, unorphaningResult := range unorphaningResults { + newBlocks = append(newBlocks, unorphaningResult.block) + newBlockInsertionResults = append(newBlockInsertionResults, unorphaningResult.blockInsertionResult) + } + + for i, newBlock := range newBlocks { blocklogger.LogBlock(block) log.Tracef("OnNewBlock: passing block %s transactions to mining manager", hash) @@ -39,6 +45,7 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, if f.onBlockAddedToDAGHandler != nil { log.Tracef("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash) + blockInsertionResult = newBlockInsertionResults[i] err := f.onBlockAddedToDAGHandler(newBlock, blockInsertionResult) if err != nil { return err diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 8cdc0058d..c57afd95a 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -13,6 +13,12 @@ import ( // on: 2^orphanResolutionRange * PHANTOM K. const maxOrphans = 600 +// UnorphaningResult is the result of unorphaning a block +type UnorphaningResult struct { + block *externalapi.DomainBlock + blockInsertionResult *externalapi.BlockInsertionResult +} + // AddOrphan adds the block to the orphan set func (f *FlowContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { f.orphansMutex.Lock() @@ -49,7 +55,7 @@ func (f *FlowContext) IsOrphan(blockHash *externalapi.DomainHash) bool { } // UnorphanBlocks removes the block from the orphan set, and remove all of the blocks that are not orphans anymore. -func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*externalapi.DomainBlock, error) { +func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*UnorphaningResult, error) { f.orphansMutex.Lock() defer f.orphansMutex.Unlock() @@ -58,7 +64,7 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*ext rootBlockHash := consensushashing.BlockHash(rootBlock) processQueue := f.addChildOrphansToProcessQueue(rootBlockHash, []externalapi.DomainHash{}) - var unorphanedBlocks []*externalapi.DomainBlock + var unorphaningResults []*UnorphaningResult for len(processQueue) > 0 { var orphanHash externalapi.DomainHash orphanHash, processQueue = processQueue[0], processQueue[1:] @@ -82,16 +88,19 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*ext } } if canBeUnorphaned { - err := f.unorphanBlock(orphanHash) + blockInsertionResult, err := f.unorphanBlock(orphanHash) if err != nil { return nil, err } - unorphanedBlocks = append(unorphanedBlocks, orphanBlock) + unorphaningResults = append(unorphaningResults, &UnorphaningResult{ + block: orphanBlock, + blockInsertionResult: blockInsertionResult, + }) processQueue = f.addChildOrphansToProcessQueue(&orphanHash, processQueue) } } - return unorphanedBlocks, nil + return unorphaningResults, nil } // addChildOrphansToProcessQueue finds all child orphans of `blockHash` @@ -130,22 +139,22 @@ func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) return childOrphans } -func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) error { +func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externalapi.BlockInsertionResult, error) { orphanBlock, ok := f.orphans[orphanHash] if !ok { - return errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash) + return nil, errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash) } delete(f.orphans, orphanHash) - _, err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock) + blockInsertionResult, 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) - return nil + return nil, nil } - return err + return nil, err } log.Infof("Unorphaned block %s", orphanHash) - return nil + return blockInsertionResult, nil } diff --git a/app/rpc/manager.go b/app/rpc/manager.go index c1d44d146..403061282 100644 --- a/app/rpc/manager.go +++ b/app/rpc/manager.go @@ -64,6 +64,11 @@ func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock, blockIns return err } + err = m.notifyVirtualSelectedParentChainChanged(blockInsertionResult) + if err != nil { + return err + } + blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(appmessage.DomainBlockToMsgBlock(block)) return m.context.NotificationManager.NotifyBlockAdded(blockAddedNotification) } @@ -90,7 +95,7 @@ func (m *Manager) notifyUTXOsChanged(blockInsertionResult *externalapi.BlockInse onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyUTXOsChanged") defer onEnd() - utxoIndexChanges, err := m.context.UTXOIndex.Update(blockInsertionResult.SelectedParentChainChanges) + utxoIndexChanges, err := m.context.UTXOIndex.Update(blockInsertionResult.VirtualSelectedParentChainChanges) if err != nil { return err } @@ -108,3 +113,15 @@ func (m *Manager) notifyVirtualSelectedParentBlueScoreChanged() error { notification := appmessage.NewVirtualSelectedParentBlueScoreChangedNotificationMessage(virtualInfo.BlueScore) return m.context.NotificationManager.NotifyVirtualSelectedParentBlueScoreChanged(notification) } + +func (m *Manager) notifyVirtualSelectedParentChainChanged(blockInsertionResult *externalapi.BlockInsertionResult) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualSelectedParentChainChanged") + defer onEnd() + + notification, err := m.context.ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage( + blockInsertionResult.VirtualSelectedParentChainChanges) + if err != nil { + return err + } + return m.context.NotificationManager.NotifyVirtualSelectedParentChainChanged(notification) +} diff --git a/app/rpc/rpc.go b/app/rpc/rpc.go index 0f73929cb..bcc34b53e 100644 --- a/app/rpc/rpc.go +++ b/app/rpc/rpc.go @@ -22,10 +22,10 @@ var handlers = map[appmessage.MessageCommand]handler{ appmessage.CmdGetConnectedPeerInfoRequestMessage: rpchandlers.HandleGetConnectedPeerInfo, appmessage.CmdAddPeerRequestMessage: rpchandlers.HandleAddPeer, appmessage.CmdSubmitTransactionRequestMessage: rpchandlers.HandleSubmitTransaction, - appmessage.CmdNotifyChainChangedRequestMessage: rpchandlers.HandleNotifyChainChanged, + appmessage.CmdNotifyVirtualSelectedParentChainChangedRequestMessage: rpchandlers.HandleNotifyVirtualSelectedParentChainChanged, appmessage.CmdGetBlockRequestMessage: rpchandlers.HandleGetBlock, appmessage.CmdGetSubnetworkRequestMessage: rpchandlers.HandleGetSubnetwork, - appmessage.CmdGetChainFromBlockRequestMessage: rpchandlers.HandleGetChainFromBlock, + appmessage.CmdGetVirtualSelectedParentChainFromBlockRequestMessage: rpchandlers.HandleGetVirtualSelectedParentChainFromBlock, appmessage.CmdGetBlocksRequestMessage: rpchandlers.HandleGetBlocks, appmessage.CmdGetBlockCountRequestMessage: rpchandlers.HandleGetBlockCount, appmessage.CmdGetBlockDAGInfoRequestMessage: rpchandlers.HandleGetBlockDAGInfo, diff --git a/app/rpc/rpccontext/chain_changed.go b/app/rpc/rpccontext/chain_changed.go new file mode 100644 index 000000000..d3f0dd6b3 --- /dev/null +++ b/app/rpc/rpccontext/chain_changed.go @@ -0,0 +1,46 @@ +package rpccontext + +import ( + "encoding/hex" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" +) + +// ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage converts +// VirtualSelectedParentChainChanges to VirtualSelectedParentChainChangedNotificationMessage +func (ctx *Context) ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage( + selectedParentChainChanges *externalapi.SelectedParentChainChanges) (*appmessage.VirtualSelectedParentChainChangedNotificationMessage, error) { + + removedChainBlockHashes := make([]string, len(selectedParentChainChanges.Removed)) + for i, removed := range selectedParentChainChanges.Removed { + removedChainBlockHashes[i] = hex.EncodeToString(removed[:]) + } + + addedChainBlocks := make([]*appmessage.ChainBlock, len(selectedParentChainChanges.Added)) + for i, added := range selectedParentChainChanges.Added { + acceptanceData, err := ctx.Domain.Consensus().GetBlockAcceptanceData(added) + if err != nil { + return nil, err + } + acceptedBlocks := make([]*appmessage.AcceptedBlock, len(acceptanceData)) + for j, acceptedBlock := range acceptanceData { + acceptedTransactionIDs := make([]string, len(acceptedBlock.TransactionAcceptanceData)) + for k, transaction := range acceptedBlock.TransactionAcceptanceData { + transactionID := consensushashing.TransactionID(transaction.Transaction) + acceptedTransactionIDs[k] = hex.EncodeToString(transactionID[:]) + } + acceptedBlocks[j] = &appmessage.AcceptedBlock{ + Hash: hex.EncodeToString(acceptedBlock.BlockHash[:]), + AcceptedTransactionIDs: acceptedTransactionIDs, + } + } + + addedChainBlocks[i] = &appmessage.ChainBlock{ + Hash: hex.EncodeToString(added[:]), + AcceptedBlocks: acceptedBlocks, + } + } + + return appmessage.NewVirtualSelectedParentChainChangedNotificationMessage(removedChainBlockHashes, addedChainBlocks), nil +} diff --git a/app/rpc/rpccontext/notificationmanager.go b/app/rpc/rpccontext/notificationmanager.go index f69ac59a1..5fc44ac6d 100644 --- a/app/rpc/rpccontext/notificationmanager.go +++ b/app/rpc/rpccontext/notificationmanager.go @@ -25,7 +25,7 @@ type UTXOsChangedNotificationAddress struct { // NotificationListener represents a registered RPC notification listener type NotificationListener struct { propagateBlockAddedNotifications bool - propagateChainChangedNotifications bool + propagateVirtualSelectedParentChainChangedNotifications bool propagateFinalityConflictNotifications bool propagateFinalityConflictResolvedNotifications bool propagateUTXOsChangedNotifications bool @@ -88,13 +88,13 @@ func (nm *NotificationManager) NotifyBlockAdded(notification *appmessage.BlockAd return nil } -// NotifyChainChanged notifies the notification manager that the DAG's selected parent chain has changed -func (nm *NotificationManager) NotifyChainChanged(notification *appmessage.ChainChangedNotificationMessage) error { +// NotifyVirtualSelectedParentChainChanged notifies the notification manager that the DAG's selected parent chain has changed +func (nm *NotificationManager) NotifyVirtualSelectedParentChainChanged(notification *appmessage.VirtualSelectedParentChainChangedNotificationMessage) error { nm.RLock() defer nm.RUnlock() for router, listener := range nm.listeners { - if listener.propagateChainChangedNotifications { + if listener.propagateVirtualSelectedParentChainChangedNotifications { err := router.OutgoingRoute().Enqueue(notification) if err != nil { return err @@ -183,7 +183,7 @@ func (nm *NotificationManager) NotifyVirtualSelectedParentBlueScoreChanged( func newNotificationListener() *NotificationListener { return &NotificationListener{ propagateBlockAddedNotifications: false, - propagateChainChangedNotifications: false, + propagateVirtualSelectedParentChainChangedNotifications: false, propagateFinalityConflictNotifications: false, propagateFinalityConflictResolvedNotifications: false, propagateUTXOsChangedNotifications: false, @@ -197,10 +197,10 @@ func (nl *NotificationListener) PropagateBlockAddedNotifications() { nl.propagateBlockAddedNotifications = true } -// PropagateChainChangedNotifications instructs the listener to send chain changed notifications +// PropagateVirtualSelectedParentChainChangedNotifications instructs the listener to send chain changed notifications // to the remote listener -func (nl *NotificationListener) PropagateChainChangedNotifications() { - nl.propagateChainChangedNotifications = true +func (nl *NotificationListener) PropagateVirtualSelectedParentChainChangedNotifications() { + nl.propagateVirtualSelectedParentChainChangedNotifications = true } // PropagateFinalityConflictNotifications instructs the listener to send finality conflict notifications diff --git a/app/rpc/rpchandlers/get_chain_from_block.go b/app/rpc/rpchandlers/get_chain_from_block.go deleted file mode 100644 index 321cc52f4..000000000 --- a/app/rpc/rpchandlers/get_chain_from_block.go +++ /dev/null @@ -1,20 +0,0 @@ -package rpchandlers - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" -) - -const ( - // maxBlocksInGetChainFromBlockResponse is the max amount of blocks that - // are allowed in a GetChainFromBlockResponse. - maxBlocksInGetChainFromBlockResponse = 1000 -) - -// HandleGetChainFromBlock handles the respectively named RPC command -func HandleGetChainFromBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - response := &appmessage.GetChainFromBlockResponseMessage{} - response.Error = appmessage.RPCErrorf("not implemented") - return response, nil -} diff --git a/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go b/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go new file mode 100644 index 000000000..c0a5789dd --- /dev/null +++ b/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go @@ -0,0 +1,44 @@ +package rpchandlers + +import ( + "encoding/hex" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleGetVirtualSelectedParentChainFromBlock handles the respectively named RPC command +func HandleGetVirtualSelectedParentChainFromBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { + getVirtualSelectedParentChainFromBlockRequest := request.(*appmessage.GetVirtualSelectedParentChainFromBlockRequestMessage) + + startHashBytes, err := hex.DecodeString(getVirtualSelectedParentChainFromBlockRequest.StartHash) + if err != nil { + errorMessage := &appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not parse startHash: %s", err) + return errorMessage, nil + } + startHash, err := hashes.FromBytes(startHashBytes) + if err != nil { + errorMessage := &appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not parse startHash: %s", err) + return errorMessage, nil + } + + virtualSelectedParentChain, err := context.Domain.Consensus().GetVirtualSelectedParentChainFromBlock(startHash) + if err != nil { + response := &appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage{} + response.Error = appmessage.RPCErrorf("Could not build virtual "+ + "selected parent chain from %s: %s", getVirtualSelectedParentChainFromBlockRequest.StartHash, err) + return response, nil + } + + chainChangedNotification, err := context.ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage(virtualSelectedParentChain) + if err != nil { + return nil, err + } + + response := appmessage.NewGetVirtualSelectedParentChainFromBlockResponseMessage( + chainChangedNotification.RemovedChainBlockHashes, chainChangedNotification.AddedChainBlocks) + return response, nil +} diff --git a/app/rpc/rpchandlers/notify_chain_changed.go b/app/rpc/rpchandlers/notify_chain_changed.go deleted file mode 100644 index 20efb292d..000000000 --- a/app/rpc/rpchandlers/notify_chain_changed.go +++ /dev/null @@ -1,19 +0,0 @@ -package rpchandlers - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" -) - -// HandleNotifyChainChanged handles the respectively named RPC command -func HandleNotifyChainChanged(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) { - listener, err := context.NotificationManager.Listener(router) - if err != nil { - return nil, err - } - listener.PropagateChainChangedNotifications() - - response := appmessage.NewNotifyChainChangedResponseMessage() - return response, nil -} diff --git a/app/rpc/rpchandlers/notify_virtual_selected_parent_chain_changed.go b/app/rpc/rpchandlers/notify_virtual_selected_parent_chain_changed.go new file mode 100644 index 000000000..6031c40db --- /dev/null +++ b/app/rpc/rpchandlers/notify_virtual_selected_parent_chain_changed.go @@ -0,0 +1,19 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleNotifyVirtualSelectedParentChainChanged handles the respectively named RPC command +func HandleNotifyVirtualSelectedParentChainChanged(context *rpccontext.Context, router *router.Router, _ appmessage.Message) (appmessage.Message, error) { + listener, err := context.NotificationManager.Listener(router) + if err != nil { + return nil, err + } + listener.PropagateVirtualSelectedParentChainChangedNotifications() + + response := appmessage.NewNotifyVirtualSelectedParentChainChangedResponseMessage() + return response, nil +} diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 9643ed182..6ad01c6a9 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -258,3 +258,10 @@ func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { return s.syncManager.GetSyncInfo() } + +func (s *consensus) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { + s.lock.Lock() + defer s.lock.Unlock() + + return s.consensusStateManager.GetVirtualSelectedParentChainFromBlock(blockHash) +} diff --git a/domain/consensus/database/serialization/acceptancedata.go b/domain/consensus/database/serialization/acceptancedata.go index 56730436a..40f38f7c9 100644 --- a/domain/consensus/database/serialization/acceptancedata.go +++ b/domain/consensus/database/serialization/acceptancedata.go @@ -20,7 +20,10 @@ func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData externalapi.Acc } } + blockHash := DomainHashToDbHash(blockAcceptanceData.BlockHash) + dbBlockAcceptanceData[i] = &DbBlockAcceptanceData{ + BlockHash: blockHash, TransactionAcceptanceData: dbTransactionAcceptanceData, } } @@ -49,7 +52,13 @@ func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) } } + blockHash, err := DbHashToDomainHash(dbBlockAcceptanceData.BlockHash) + if err != nil { + return nil, err + } + domainAcceptanceData[i] = &externalapi.BlockAcceptanceData{ + BlockHash: blockHash, TransactionAcceptanceData: domainTransactionAcceptanceData, } } diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index 731b42013..5d4ad688a 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -653,6 +653,7 @@ type DbBlockAcceptanceData struct { unknownFields protoimpl.UnknownFields TransactionAcceptanceData []*DbTransactionAcceptanceData `protobuf:"bytes,1,rep,name=transactionAcceptanceData,proto3" json:"transactionAcceptanceData,omitempty"` + BlockHash *DbHash `protobuf:"bytes,2,opt,name=blockHash,proto3" json:"blockHash,omitempty"` } func (x *DbBlockAcceptanceData) Reset() { @@ -694,6 +695,13 @@ func (x *DbBlockAcceptanceData) GetTransactionAcceptanceData() []*DbTransactionA return nil } +func (x *DbBlockAcceptanceData) GetBlockHash() *DbHash { + if x != nil { + return x.BlockHash + } + return nil +} + type DbTransactionAcceptanceData struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1829,7 +1837,7 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0x81, 0x01, 0x0a, 0x15, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, + 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb6, 0x01, 0x0a, 0x15, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x68, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, @@ -1837,140 +1845,143 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8f, 0x01, 0x0a, 0x1b, 0x44, 0x62, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0b, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, - 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, - 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x22, 0x76, 0x0a, 0x10, 0x44, - 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, - 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xdb, 0x02, 0x0a, - 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, 0x73, 0x74, 0x64, 0x61, 0x67, - 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x12, 0x3d, - 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x73, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x3b, 0x0a, - 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0d, 0x6d, 0x65, 0x72, - 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0c, 0x6d, 0x65, - 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, - 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, - 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, - 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, - 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, 0x6d, 0x0a, 0x14, 0x44, 0x62, - 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, - 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x62, 0x6c, 0x75, - 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, - 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6e, 0x74, - 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, 0x0a, 0x0a, 0x44, 0x62, 0x4d, - 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x75, 0x6c, 0x74, 0x69, - 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x75, 0x6c, 0x74, 0x69, - 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, - 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x14, - 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x75, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, - 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, - 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, - 0x9c, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, - 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x43, 0x0a, 0x11, 0x66, 0x75, 0x74, - 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x11, 0x66, 0x75, 0x74, - 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x22, 0xbd, - 0x01, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, - 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x09, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x8f, + 0x01, 0x0a, 0x1b, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, + 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, + 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, + 0x22, 0x76, 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, + 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, + 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x22, 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, + 0x73, 0x74, 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, + 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, + 0x6f, 0x72, 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x39, 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, + 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, + 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, + 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, + 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, + 0x6d, 0x0a, 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, + 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, + 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, + 0x0a, 0x0a, 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, + 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x22, 0x87, 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x38, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, + 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, + 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, + 0x62, 0x61, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x74, + 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, - 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x40, - 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x65, 0x6e, 0x64, - 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x44, 0x69, 0x66, 0x66, 0x12, - 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, - 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, - 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x3f, 0x0a, 0x08, 0x74, 0x6f, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, - 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, - 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x44, - 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, - 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, - 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, + 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x43, + 0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x74, 0x22, 0xbd, 0x01, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x31, + 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, + 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x12, 0x41, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, + 0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, + 0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x22, 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, - 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x24, - 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, + 0x74, 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, + 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2033,32 +2044,33 @@ var file_dbobjects_proto_depIdxs = []int32{ 6, // 11: serialization.DbOutpoint.transactionID:type_name -> serialization.DbTransactionId 10, // 12: serialization.DbAcceptanceData.blockAcceptanceData:type_name -> serialization.DbBlockAcceptanceData 11, // 13: serialization.DbBlockAcceptanceData.transactionAcceptanceData:type_name -> serialization.DbTransactionAcceptanceData - 3, // 14: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction - 2, // 15: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash - 2, // 16: serialization.DbBlockRelations.children:type_name -> serialization.DbHash - 2, // 17: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash - 2, // 18: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash - 2, // 19: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash - 15, // 20: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes - 2, // 21: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash - 18, // 22: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem - 5, // 23: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint - 19, // 24: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry - 21, // 25: serialization.DbReachabilityData.treeNode:type_name -> serialization.DbReachabilityTreeNode - 2, // 26: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash - 2, // 27: serialization.DbReachabilityTreeNode.children:type_name -> serialization.DbHash - 2, // 28: serialization.DbReachabilityTreeNode.parent:type_name -> serialization.DbHash - 22, // 29: serialization.DbReachabilityTreeNode.interval:type_name -> serialization.DbReachabilityInterval - 18, // 30: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem - 18, // 31: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem - 2, // 32: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash - 2, // 33: serialization.DbTips.tips:type_name -> serialization.DbHash - 2, // 34: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash - 35, // [35:35] is the sub-list for method output_type - 35, // [35:35] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 2, // 14: serialization.DbBlockAcceptanceData.blockHash:type_name -> serialization.DbHash + 3, // 15: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction + 2, // 16: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash + 2, // 17: serialization.DbBlockRelations.children:type_name -> serialization.DbHash + 2, // 18: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash + 2, // 19: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash + 2, // 20: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash + 15, // 21: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes + 2, // 22: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash + 18, // 23: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem + 5, // 24: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint + 19, // 25: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry + 21, // 26: serialization.DbReachabilityData.treeNode:type_name -> serialization.DbReachabilityTreeNode + 2, // 27: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash + 2, // 28: serialization.DbReachabilityTreeNode.children:type_name -> serialization.DbHash + 2, // 29: serialization.DbReachabilityTreeNode.parent:type_name -> serialization.DbHash + 22, // 30: serialization.DbReachabilityTreeNode.interval:type_name -> serialization.DbReachabilityInterval + 18, // 31: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem + 18, // 32: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem + 2, // 33: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash + 2, // 34: serialization.DbTips.tips:type_name -> serialization.DbHash + 2, // 35: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash + 36, // [36:36] is the sub-list for method output_type + 36, // [36:36] is the sub-list for method input_type + 36, // [36:36] is the sub-list for extension type_name + 36, // [36:36] is the sub-list for extension extendee + 0, // [0:36] is the sub-list for field type_name } func init() { file_dbobjects_proto_init() } diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 2e2061bce..434887c10 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -64,6 +64,7 @@ message DbAcceptanceData { message DbBlockAcceptanceData { repeated DbTransactionAcceptanceData transactionAcceptanceData = 1; + DbHash blockHash = 2; } message DbTransactionAcceptanceData { diff --git a/domain/consensus/model/externalapi/acceptancedata.go b/domain/consensus/model/externalapi/acceptancedata.go index 8ec60d112..b3bde56b0 100644 --- a/domain/consensus/model/externalapi/acceptancedata.go +++ b/domain/consensus/model/externalapi/acceptancedata.go @@ -20,6 +20,7 @@ func (ad AcceptanceData) Clone() AcceptanceData { // BlockAcceptanceData stores all transactions in a block with an indication // if they were accepted or not by some other block type BlockAcceptanceData struct { + BlockHash *DomainHash TransactionAcceptanceData []*TransactionAcceptanceData } @@ -29,7 +30,10 @@ func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData { return nil } - clone := &BlockAcceptanceData{TransactionAcceptanceData: make([]*TransactionAcceptanceData, len(bad.TransactionAcceptanceData))} + clone := &BlockAcceptanceData{ + BlockHash: bad.BlockHash, + TransactionAcceptanceData: make([]*TransactionAcceptanceData, len(bad.TransactionAcceptanceData)), + } for i, acceptanceData := range bad.TransactionAcceptanceData { clone.TransactionAcceptanceData[i] = acceptanceData.Clone() } diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 1628b0737..8cebe6634 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -21,4 +21,5 @@ type Consensus interface { GetSyncInfo() (*SyncInfo, error) Tips() ([]*DomainHash, error) GetVirtualInfo() (*VirtualInfo, error) + GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) } diff --git a/domain/consensus/model/externalapi/insertblockresult.go b/domain/consensus/model/externalapi/insertblockresult.go index 357492a8f..48379a32d 100644 --- a/domain/consensus/model/externalapi/insertblockresult.go +++ b/domain/consensus/model/externalapi/insertblockresult.go @@ -2,7 +2,7 @@ package externalapi // BlockInsertionResult is auxiliary data returned from ValidateAndInsertBlock type BlockInsertionResult struct { - SelectedParentChainChanges *SelectedParentChainChanges + VirtualSelectedParentChainChanges *SelectedParentChainChanges } // SelectedParentChainChanges is the set of changes made to the selected parent chain diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index 08367b299..be966c26d 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -9,4 +9,5 @@ type ConsensusStateManager interface { UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, externalapi.AcceptanceData, Multiset, error) + GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 63db91e55..10ed66614 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -142,7 +142,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, } return &externalapi.BlockInsertionResult{ - SelectedParentChainChanges: selectedParentChainChanges, + VirtualSelectedParentChainChanges: selectedParentChainChanges, }, nil } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index addb85ff2..42d214bbf 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -133,6 +133,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH blueBlockHash := consensushashing.BlockHash(blueBlock) log.Tracef("Applying blue block %s", blueBlockHash) blockAcceptanceData := &externalapi.BlockAcceptanceData{ + BlockHash: blueBlockHash, TransactionAcceptanceData: make([]*externalapi.TransactionAcceptanceData, len(blueBlock.Transactions)), } isSelectedParent := i == 0 diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go index 33cc1dcd4..965354283 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go @@ -1,19 +1,37 @@ package consensusstatemanager -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +func (csm *consensusStateManager) GetVirtualSelectedParentChainFromBlock( + blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { + + // Calculate chain changes between the given blockHash and the + // virtual's selected parent. Note that we explicitly don't + // do the calculation against the virtual itself so that we + // won't later need to remove it from the result. + virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) + if err != nil { + return nil, err + } + virtualSelectedParent := virtualGHOSTDAGData.SelectedParent() + + return csm.calculateSelectedParentChainChanges(blockHash, virtualSelectedParent) +} func (csm *consensusStateManager) calculateSelectedParentChainChanges( - oldVirtualSelectedParent, newVirtualSelectedParent *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { + fromBlockHash, toBlockHash *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 + // Walk down from fromBlockHash until we reach the common selected + // parent chain ancestor of fromBlockHash and toBlockHash. Note + // that this slice will be empty if fromBlockHash is the selected + // parent of toBlockHash var removed []*externalapi.DomainHash - current := oldVirtualSelectedParent + current := fromBlockHash for { - isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent, err := csm.dagTopologyManager.IsInSelectedParentChainOf(current, newVirtualSelectedParent) + isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent, err := csm.dagTopologyManager.IsInSelectedParentChainOf(current, toBlockHash) if err != nil { return nil, err } @@ -30,9 +48,9 @@ func (csm *consensusStateManager) calculateSelectedParentChainChanges( } commonAncestor := current - // Walk down from the new virtual down to the common ancestor + // Walk down from the toBlockHash to the common ancestor var added []*externalapi.DomainHash - current = newVirtualSelectedParent + current = toBlockHash for *current != *commonAncestor { added = append(added, current) currentGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, current) diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go index f297295c5..f2306e142 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go @@ -23,7 +23,7 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { if err != nil { t.Fatalf("Error adding block A: %+v", err) } - blockASelectedParentChainChanges := blockAInsertionResult.SelectedParentChainChanges + blockASelectedParentChainChanges := blockAInsertionResult.VirtualSelectedParentChainChanges // Make sure that the removed slice is empty if len(blockASelectedParentChainChanges.Removed) > 0 { @@ -63,7 +63,7 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { if err != nil { t.Fatalf("Error adding block C: %+v", err) } - blockCSelectedParentChainChanges := blockCInsertionResult.SelectedParentChainChanges + blockCSelectedParentChainChanges := blockCInsertionResult.VirtualSelectedParentChainChanges // Make sure that the removed slice contains only the block that was previously // the selected parent @@ -96,7 +96,7 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { if err != nil { t.Fatalf("Error adding block D: %+v", err) } - blockDSelectedParentChainChanges := blockDInsertionResult.SelectedParentChainChanges + blockDSelectedParentChainChanges := blockDInsertionResult.VirtualSelectedParentChainChanges // Make sure that both the added and the removed slices are empty if len(blockDSelectedParentChainChanges.Added) > 0 { diff --git a/infrastructure/config/config.go b/infrastructure/config/config.go index 05b2727ee..fe2dae758 100644 --- a/infrastructure/config/config.go +++ b/infrastructure/config/config.go @@ -55,7 +55,6 @@ const ( DefaultMaxOrphanTxSize = 100000 defaultSigCacheMaxSize = 100000 sampleConfigFilename = "sample-kaspad.conf" - defaultAcceptanceIndex = false defaultMaxUTXOCacheSize = 5000000000 ) @@ -117,8 +116,6 @@ type Flags struct { NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"` SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"` BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."` - AcceptanceIndex bool `long:"acceptanceindex" description:"Maintain a full hash-based acceptance index which makes the getChainFromBlock RPC available"` - DropAcceptanceIndex bool `long:"dropacceptanceindex" description:"Deletes the hash-based acceptance index from the database on start up and then exits."` RelayNonStd bool `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."` RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."` ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."` @@ -189,7 +186,6 @@ func defaultFlags() *Flags { MaxOrphanTxs: defaultMaxOrphanTransactions, SigCacheMaxSize: defaultSigCacheMaxSize, MinRelayTxFee: defaultMinRelayTxFee, - AcceptanceIndex: defaultAcceptanceIndex, MaxUTXOCacheSize: defaultMaxUTXOCacheSize, ServiceOptions: &ServiceOptions{}, } @@ -513,16 +509,6 @@ func LoadConfig() (*Config, error) { } } - // --acceptanceindex and --dropacceptanceindex do not mix. - if cfg.AcceptanceIndex && cfg.DropAcceptanceIndex { - err := errors.Errorf("%s: the --acceptanceindex and --dropacceptanceindex "+ - "options may not be activated at the same time", - funcName) - fmt.Fprintln(os.Stderr, err) - fmt.Fprintln(os.Stderr, usageMessage) - return nil, err - } - // Add default port to all listener addresses if needed and remove // duplicate addresses. cfg.Listeners, err = network.NormalizeAddresses(cfg.Listeners, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index ce748049a..3c4c3ff73 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -77,15 +77,15 @@ type KaspadMessage struct { // *KaspadMessage_AddPeerResponse // *KaspadMessage_SubmitTransactionRequest // *KaspadMessage_SubmitTransactionResponse - // *KaspadMessage_NotifyChainChangedRequest - // *KaspadMessage_NotifyChainChangedResponse - // *KaspadMessage_ChainChangedNotification + // *KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest + // *KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse + // *KaspadMessage_VirtualSelectedParentChainChangedNotification // *KaspadMessage_GetBlockRequest // *KaspadMessage_GetBlockResponse // *KaspadMessage_GetSubnetworkRequest // *KaspadMessage_GetSubnetworkResponse - // *KaspadMessage_GetChainFromBlockRequest - // *KaspadMessage_GetChainFromBlockResponse + // *KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest + // *KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse // *KaspadMessage_GetBlocksRequest // *KaspadMessage_GetBlocksResponse // *KaspadMessage_GetBlockCountRequest @@ -478,23 +478,23 @@ func (x *KaspadMessage) GetSubmitTransactionResponse() *SubmitTransactionRespons return nil } -func (x *KaspadMessage) GetNotifyChainChangedRequest() *NotifyChainChangedRequestMessage { - if x, ok := x.GetPayload().(*KaspadMessage_NotifyChainChangedRequest); ok { - return x.NotifyChainChangedRequest +func (x *KaspadMessage) GetNotifyVirtualSelectedParentChainChangedRequest() *NotifyVirtualSelectedParentChainChangedRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest); ok { + return x.NotifyVirtualSelectedParentChainChangedRequest } return nil } -func (x *KaspadMessage) GetNotifyChainChangedResponse() *NotifyChainChangedResponseMessage { - if x, ok := x.GetPayload().(*KaspadMessage_NotifyChainChangedResponse); ok { - return x.NotifyChainChangedResponse +func (x *KaspadMessage) GetNotifyVirtualSelectedParentChainChangedResponse() *NotifyVirtualSelectedParentChainChangedResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse); ok { + return x.NotifyVirtualSelectedParentChainChangedResponse } return nil } -func (x *KaspadMessage) GetChainChangedNotification() *ChainChangedNotificationMessage { - if x, ok := x.GetPayload().(*KaspadMessage_ChainChangedNotification); ok { - return x.ChainChangedNotification +func (x *KaspadMessage) GetVirtualSelectedParentChainChangedNotification() *VirtualSelectedParentChainChangedNotificationMessage { + if x, ok := x.GetPayload().(*KaspadMessage_VirtualSelectedParentChainChangedNotification); ok { + return x.VirtualSelectedParentChainChangedNotification } return nil } @@ -527,16 +527,16 @@ func (x *KaspadMessage) GetGetSubnetworkResponse() *GetSubnetworkResponseMessage return nil } -func (x *KaspadMessage) GetGetChainFromBlockRequest() *GetChainFromBlockRequestMessage { - if x, ok := x.GetPayload().(*KaspadMessage_GetChainFromBlockRequest); ok { - return x.GetChainFromBlockRequest +func (x *KaspadMessage) GetGetVirtualSelectedParentChainFromBlockRequest() *GetVirtualSelectedParentChainFromBlockRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest); ok { + return x.GetVirtualSelectedParentChainFromBlockRequest } return nil } -func (x *KaspadMessage) GetGetChainFromBlockResponse() *GetChainFromBlockResponseMessage { - if x, ok := x.GetPayload().(*KaspadMessage_GetChainFromBlockResponse); ok { - return x.GetChainFromBlockResponse +func (x *KaspadMessage) GetGetVirtualSelectedParentChainFromBlockResponse() *GetVirtualSelectedParentChainFromBlockResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse); ok { + return x.GetVirtualSelectedParentChainFromBlockResponse } return nil } @@ -925,16 +925,16 @@ type KaspadMessage_SubmitTransactionResponse struct { SubmitTransactionResponse *SubmitTransactionResponseMessage `protobuf:"bytes,1021,opt,name=submitTransactionResponse,proto3,oneof"` } -type KaspadMessage_NotifyChainChangedRequest struct { - NotifyChainChangedRequest *NotifyChainChangedRequestMessage `protobuf:"bytes,1022,opt,name=notifyChainChangedRequest,proto3,oneof"` +type KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest struct { + NotifyVirtualSelectedParentChainChangedRequest *NotifyVirtualSelectedParentChainChangedRequestMessage `protobuf:"bytes,1022,opt,name=notifyVirtualSelectedParentChainChangedRequest,proto3,oneof"` } -type KaspadMessage_NotifyChainChangedResponse struct { - NotifyChainChangedResponse *NotifyChainChangedResponseMessage `protobuf:"bytes,1023,opt,name=notifyChainChangedResponse,proto3,oneof"` +type KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse struct { + NotifyVirtualSelectedParentChainChangedResponse *NotifyVirtualSelectedParentChainChangedResponseMessage `protobuf:"bytes,1023,opt,name=notifyVirtualSelectedParentChainChangedResponse,proto3,oneof"` } -type KaspadMessage_ChainChangedNotification struct { - ChainChangedNotification *ChainChangedNotificationMessage `protobuf:"bytes,1024,opt,name=chainChangedNotification,proto3,oneof"` +type KaspadMessage_VirtualSelectedParentChainChangedNotification struct { + VirtualSelectedParentChainChangedNotification *VirtualSelectedParentChainChangedNotificationMessage `protobuf:"bytes,1024,opt,name=virtualSelectedParentChainChangedNotification,proto3,oneof"` } type KaspadMessage_GetBlockRequest struct { @@ -953,12 +953,12 @@ type KaspadMessage_GetSubnetworkResponse struct { GetSubnetworkResponse *GetSubnetworkResponseMessage `protobuf:"bytes,1028,opt,name=getSubnetworkResponse,proto3,oneof"` } -type KaspadMessage_GetChainFromBlockRequest struct { - GetChainFromBlockRequest *GetChainFromBlockRequestMessage `protobuf:"bytes,1029,opt,name=getChainFromBlockRequest,proto3,oneof"` +type KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest struct { + GetVirtualSelectedParentChainFromBlockRequest *GetVirtualSelectedParentChainFromBlockRequestMessage `protobuf:"bytes,1029,opt,name=getVirtualSelectedParentChainFromBlockRequest,proto3,oneof"` } -type KaspadMessage_GetChainFromBlockResponse struct { - GetChainFromBlockResponse *GetChainFromBlockResponseMessage `protobuf:"bytes,1030,opt,name=getChainFromBlockResponse,proto3,oneof"` +type KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse struct { + GetVirtualSelectedParentChainFromBlockResponse *GetVirtualSelectedParentChainFromBlockResponseMessage `protobuf:"bytes,1030,opt,name=getVirtualSelectedParentChainFromBlockResponse,proto3,oneof"` } type KaspadMessage_GetBlocksRequest struct { @@ -1165,11 +1165,11 @@ func (*KaspadMessage_SubmitTransactionRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_SubmitTransactionResponse) isKaspadMessage_Payload() {} -func (*KaspadMessage_NotifyChainChangedRequest) isKaspadMessage_Payload() {} +func (*KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest) isKaspadMessage_Payload() {} -func (*KaspadMessage_NotifyChainChangedResponse) isKaspadMessage_Payload() {} +func (*KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse) isKaspadMessage_Payload() {} -func (*KaspadMessage_ChainChangedNotification) isKaspadMessage_Payload() {} +func (*KaspadMessage_VirtualSelectedParentChainChangedNotification) isKaspadMessage_Payload() {} func (*KaspadMessage_GetBlockRequest) isKaspadMessage_Payload() {} @@ -1179,9 +1179,9 @@ func (*KaspadMessage_GetSubnetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetSubnetworkResponse) isKaspadMessage_Payload() {} -func (*KaspadMessage_GetChainFromBlockRequest) isKaspadMessage_Payload() {} +func (*KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest) isKaspadMessage_Payload() {} -func (*KaspadMessage_GetChainFromBlockResponse) isKaspadMessage_Payload() {} +func (*KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse) isKaspadMessage_Payload() {} func (*KaspadMessage_GetBlocksRequest) isKaspadMessage_Payload() {} @@ -4323,14 +4323,14 @@ func (x *SubmitTransactionResponseMessage) GetError() *RPCError { return nil } -type NotifyChainChangedRequestMessage struct { +type NotifyVirtualSelectedParentChainChangedRequestMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *NotifyChainChangedRequestMessage) Reset() { - *x = NotifyChainChangedRequestMessage{} +func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { + *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4338,13 +4338,13 @@ func (x *NotifyChainChangedRequestMessage) Reset() { } } -func (x *NotifyChainChangedRequestMessage) String() string { +func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NotifyChainChangedRequestMessage) ProtoMessage() {} +func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} -func (x *NotifyChainChangedRequestMessage) ProtoReflect() protoreflect.Message { +func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4356,12 +4356,12 @@ func (x *NotifyChainChangedRequestMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NotifyChainChangedRequestMessage.ProtoReflect.Descriptor instead. -func (*NotifyChainChangedRequestMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{59} } -type NotifyChainChangedResponseMessage struct { +type NotifyVirtualSelectedParentChainChangedResponseMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -4369,8 +4369,8 @@ type NotifyChainChangedResponseMessage struct { Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } -func (x *NotifyChainChangedResponseMessage) Reset() { - *x = NotifyChainChangedResponseMessage{} +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { + *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4378,13 +4378,13 @@ func (x *NotifyChainChangedResponseMessage) Reset() { } } -func (x *NotifyChainChangedResponseMessage) String() string { +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NotifyChainChangedResponseMessage) ProtoMessage() {} +func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} -func (x *NotifyChainChangedResponseMessage) ProtoReflect() protoreflect.Message { +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4396,19 +4396,19 @@ func (x *NotifyChainChangedResponseMessage) ProtoReflect() protoreflect.Message return mi.MessageOf(x) } -// Deprecated: Use NotifyChainChangedResponseMessage.ProtoReflect.Descriptor instead. -func (*NotifyChainChangedResponseMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{60} } -func (x *NotifyChainChangedResponseMessage) GetError() *RPCError { +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { if x != nil { return x.Error } return nil } -type ChainChangedNotificationMessage struct { +type VirtualSelectedParentChainChangedNotificationMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -4417,8 +4417,8 @@ type ChainChangedNotificationMessage struct { AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` } -func (x *ChainChangedNotificationMessage) Reset() { - *x = ChainChangedNotificationMessage{} +func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { + *x = VirtualSelectedParentChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4426,13 +4426,13 @@ func (x *ChainChangedNotificationMessage) Reset() { } } -func (x *ChainChangedNotificationMessage) String() string { +func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ChainChangedNotificationMessage) ProtoMessage() {} +func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} -func (x *ChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { +func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -4444,19 +4444,19 @@ func (x *ChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ChainChangedNotificationMessage.ProtoReflect.Descriptor instead. -func (*ChainChangedNotificationMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. +func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{61} } -func (x *ChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { +func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { if x != nil { return x.RemovedChainBlockHashes } return nil } -func (x *ChainChangedNotificationMessage) GetAddedChainBlocks() []*ChainBlock { +func (x *VirtualSelectedParentChainChangedNotificationMessage) GetAddedChainBlocks() []*ChainBlock { if x != nil { return x.AddedChainBlocks } @@ -5363,17 +5363,16 @@ func (x *GetSubnetworkResponseMessage) GetError() *RPCError { return nil } -type GetChainFromBlockRequestMessage struct { +type GetVirtualSelectedParentChainFromBlockRequestMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - StartHash string `protobuf:"bytes,1,opt,name=startHash,proto3" json:"startHash,omitempty"` - IncludeBlockVerboseData bool `protobuf:"varint,2,opt,name=includeBlockVerboseData,proto3" json:"includeBlockVerboseData,omitempty"` + StartHash string `protobuf:"bytes,1,opt,name=startHash,proto3" json:"startHash,omitempty"` } -func (x *GetChainFromBlockRequestMessage) Reset() { - *x = GetChainFromBlockRequestMessage{} +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { + *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -5381,13 +5380,13 @@ func (x *GetChainFromBlockRequestMessage) Reset() { } } -func (x *GetChainFromBlockRequestMessage) String() string { +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetChainFromBlockRequestMessage) ProtoMessage() {} +func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} -func (x *GetChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -5399,38 +5398,30 @@ func (x *GetChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. -func (*GetChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{74} } -func (x *GetChainFromBlockRequestMessage) GetStartHash() string { +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { if x != nil { return x.StartHash } return "" } -func (x *GetChainFromBlockRequestMessage) GetIncludeBlockVerboseData() bool { - if x != nil { - return x.IncludeBlockVerboseData - } - return false -} - -type GetChainFromBlockResponseMessage struct { +type GetVirtualSelectedParentChainFromBlockResponseMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - RemovedChainBlockHashes []string `protobuf:"bytes,1,rep,name=removedChainBlockHashes,proto3" json:"removedChainBlockHashes,omitempty"` - AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` - BlockVerboseData []*BlockVerboseData `protobuf:"bytes,3,rep,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` + RemovedChainBlockHashes []string `protobuf:"bytes,1,rep,name=removedChainBlockHashes,proto3" json:"removedChainBlockHashes,omitempty"` + AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } -func (x *GetChainFromBlockResponseMessage) Reset() { - *x = GetChainFromBlockResponseMessage{} +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { + *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -5438,13 +5429,13 @@ func (x *GetChainFromBlockResponseMessage) Reset() { } } -func (x *GetChainFromBlockResponseMessage) String() string { +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetChainFromBlockResponseMessage) ProtoMessage() {} +func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} -func (x *GetChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -5456,33 +5447,26 @@ func (x *GetChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. -func (*GetChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{75} } -func (x *GetChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { if x != nil { return x.RemovedChainBlockHashes } return nil } -func (x *GetChainFromBlockResponseMessage) GetAddedChainBlocks() []*ChainBlock { +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetAddedChainBlocks() []*ChainBlock { if x != nil { return x.AddedChainBlocks } return nil } -func (x *GetChainFromBlockResponseMessage) GetBlockVerboseData() []*BlockVerboseData { - if x != nil { - return x.BlockVerboseData - } - return nil -} - -func (x *GetChainFromBlockResponseMessage) GetError() *RPCError { +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetError() *RPCError { if x != nil { return x.Error } @@ -7239,7 +7223,7 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xb9, 0x40, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xf9, 0x42, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -7490,26 +7474,38 @@ var file_messages_proto_rawDesc = []byte{ 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x63, 0x68, 0x61, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, @@ -7533,19 +7529,27 @@ var file_messages_proto_rawDesc = []byte{ 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, - 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 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, 0x48, + 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, @@ -8109,431 +8113,429 @@ var file_messages_proto_rawDesc = []byte{ 0x6e, 0x49, 0x64, 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, - 0x22, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x9e, 0x01, 0x0a, 0x1f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 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, + 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 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, 0xb3, + 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 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, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, + 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 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, 0x54, 0x0a, + 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, + 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, 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, 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, + 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 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, 0x95, 0x01, 0x0a, 0x1f, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, - 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, - 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, - 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, 0x05, - 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, - 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, - 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, - 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, - 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, - 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, - 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, - 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, - 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x2a, 0x0a, + 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 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, 0x22, 0x40, + 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, + 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, + 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, + 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, + 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, + 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, + 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, + 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, + 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, + 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 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, 0x31, + 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, - 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 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, + 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 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, 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, 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, + 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 ( @@ -8609,9 +8611,9 @@ var file_messages_proto_goTypes = []interface{}{ (*AddPeerResponseMessage)(nil), // 56: protowire.AddPeerResponseMessage (*SubmitTransactionRequestMessage)(nil), // 57: protowire.SubmitTransactionRequestMessage (*SubmitTransactionResponseMessage)(nil), // 58: protowire.SubmitTransactionResponseMessage - (*NotifyChainChangedRequestMessage)(nil), // 59: protowire.NotifyChainChangedRequestMessage - (*NotifyChainChangedResponseMessage)(nil), // 60: protowire.NotifyChainChangedResponseMessage - (*ChainChangedNotificationMessage)(nil), // 61: protowire.ChainChangedNotificationMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 59: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 60: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 61: protowire.VirtualSelectedParentChainChangedNotificationMessage (*ChainBlock)(nil), // 62: protowire.ChainBlock (*AcceptedBlock)(nil), // 63: protowire.AcceptedBlock (*GetBlockRequestMessage)(nil), // 64: protowire.GetBlockRequestMessage @@ -8624,8 +8626,8 @@ var file_messages_proto_goTypes = []interface{}{ (*ScriptPubKeyResult)(nil), // 71: protowire.ScriptPubKeyResult (*GetSubnetworkRequestMessage)(nil), // 72: protowire.GetSubnetworkRequestMessage (*GetSubnetworkResponseMessage)(nil), // 73: protowire.GetSubnetworkResponseMessage - (*GetChainFromBlockRequestMessage)(nil), // 74: protowire.GetChainFromBlockRequestMessage - (*GetChainFromBlockResponseMessage)(nil), // 75: protowire.GetChainFromBlockResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 74: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 75: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage (*GetBlocksRequestMessage)(nil), // 76: protowire.GetBlocksRequestMessage (*GetBlocksResponseMessage)(nil), // 77: protowire.GetBlocksResponseMessage (*GetBlockCountRequestMessage)(nil), // 78: protowire.GetBlockCountRequestMessage @@ -8706,15 +8708,15 @@ var file_messages_proto_depIdxs = []int32{ 56, // 43: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage 57, // 44: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage 58, // 45: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 59, // 46: protowire.KaspadMessage.notifyChainChangedRequest:type_name -> protowire.NotifyChainChangedRequestMessage - 60, // 47: protowire.KaspadMessage.notifyChainChangedResponse:type_name -> protowire.NotifyChainChangedResponseMessage - 61, // 48: protowire.KaspadMessage.chainChangedNotification:type_name -> protowire.ChainChangedNotificationMessage + 59, // 46: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 60, // 47: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 61, // 48: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage 64, // 49: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage 65, // 50: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage 72, // 51: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage 73, // 52: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 74, // 53: protowire.KaspadMessage.getChainFromBlockRequest:type_name -> protowire.GetChainFromBlockRequestMessage - 75, // 54: protowire.KaspadMessage.getChainFromBlockResponse:type_name -> protowire.GetChainFromBlockResponseMessage + 74, // 53: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 75, // 54: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage 76, // 55: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage 77, // 56: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage 78, // 57: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage @@ -8793,8 +8795,8 @@ var file_messages_proto_depIdxs = []int32{ 32, // 130: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError 96, // 131: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction 32, // 132: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 32, // 133: protowire.NotifyChainChangedResponseMessage.error:type_name -> protowire.RPCError - 62, // 134: protowire.ChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 32, // 133: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 62, // 134: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock 63, // 135: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock 66, // 136: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData 32, // 137: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError @@ -8804,38 +8806,37 @@ var file_messages_proto_depIdxs = []int32{ 69, // 141: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig 71, // 142: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult 32, // 143: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 62, // 144: protowire.GetChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 66, // 145: protowire.GetChainFromBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 146: protowire.GetChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 66, // 147: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 148: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 32, // 149: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 32, // 150: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 32, // 151: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 32, // 152: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 32, // 153: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 32, // 154: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 32, // 155: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 95, // 156: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 95, // 157: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 99, // 158: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 100, // 159: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 97, // 160: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 98, // 161: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 99, // 162: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 95, // 163: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 32, // 164: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 32, // 165: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 32, // 166: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 0, // 167: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 168: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 169: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 170: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 169, // [169:171] is the sub-list for method output_type - 167, // [167:169] is the sub-list for method input_type - 167, // [167:167] is the sub-list for extension type_name - 167, // [167:167] is the sub-list for extension extendee - 0, // [0:167] is the sub-list for field type_name + 62, // 144: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 32, // 145: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 66, // 146: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 32, // 147: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 32, // 148: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 32, // 149: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 32, // 150: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 32, // 151: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 32, // 152: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 32, // 153: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 32, // 154: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 95, // 155: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 95, // 156: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 99, // 157: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 100, // 158: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 97, // 159: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 98, // 160: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 99, // 161: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 95, // 162: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 32, // 163: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 32, // 164: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 32, // 165: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 0, // 166: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 167: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 168: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 169: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 168, // [168:170] is the sub-list for method output_type + 166, // [166:168] is the sub-list for method input_type + 166, // [166:166] is the sub-list for extension type_name + 166, // [166:166] is the sub-list for extension extendee + 0, // [0:166] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -9553,7 +9554,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyChainChangedRequestMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { case 0: return &v.state case 1: @@ -9565,7 +9566,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyChainChangedResponseMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { case 0: return &v.state case 1: @@ -9577,7 +9578,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainChangedNotificationMessage); i { + switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -9733,7 +9734,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetChainFromBlockRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9745,7 +9746,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetChainFromBlockResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { case 0: return &v.state case 1: @@ -10188,15 +10189,15 @@ func file_messages_proto_init() { (*KaspadMessage_AddPeerResponse)(nil), (*KaspadMessage_SubmitTransactionRequest)(nil), (*KaspadMessage_SubmitTransactionResponse)(nil), - (*KaspadMessage_NotifyChainChangedRequest)(nil), - (*KaspadMessage_NotifyChainChangedResponse)(nil), - (*KaspadMessage_ChainChangedNotification)(nil), + (*KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest)(nil), + (*KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse)(nil), + (*KaspadMessage_VirtualSelectedParentChainChangedNotification)(nil), (*KaspadMessage_GetBlockRequest)(nil), (*KaspadMessage_GetBlockResponse)(nil), (*KaspadMessage_GetSubnetworkRequest)(nil), (*KaspadMessage_GetSubnetworkResponse)(nil), - (*KaspadMessage_GetChainFromBlockRequest)(nil), - (*KaspadMessage_GetChainFromBlockResponse)(nil), + (*KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest)(nil), + (*KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse)(nil), (*KaspadMessage_GetBlocksRequest)(nil), (*KaspadMessage_GetBlocksResponse)(nil), (*KaspadMessage_GetBlockCountRequest)(nil), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 434982c54..63aa88c13 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -52,15 +52,15 @@ message KaspadMessage { AddPeerResponseMessage addPeerResponse = 1019; SubmitTransactionRequestMessage submitTransactionRequest = 1020; SubmitTransactionResponseMessage submitTransactionResponse = 1021; - NotifyChainChangedRequestMessage notifyChainChangedRequest = 1022; - NotifyChainChangedResponseMessage notifyChainChangedResponse = 1023; - ChainChangedNotificationMessage chainChangedNotification = 1024; + NotifyVirtualSelectedParentChainChangedRequestMessage notifyVirtualSelectedParentChainChangedRequest = 1022; + NotifyVirtualSelectedParentChainChangedResponseMessage notifyVirtualSelectedParentChainChangedResponse = 1023; + VirtualSelectedParentChainChangedNotificationMessage virtualSelectedParentChainChangedNotification = 1024; GetBlockRequestMessage getBlockRequest = 1025; GetBlockResponseMessage getBlockResponse = 1026; GetSubnetworkRequestMessage getSubnetworkRequest = 1027; GetSubnetworkResponseMessage getSubnetworkResponse = 1028; - GetChainFromBlockRequestMessage getChainFromBlockRequest = 1029; - GetChainFromBlockResponseMessage getChainFromBlockResponse = 1030; + GetVirtualSelectedParentChainFromBlockRequestMessage getVirtualSelectedParentChainFromBlockRequest = 1029; + GetVirtualSelectedParentChainFromBlockResponseMessage getVirtualSelectedParentChainFromBlockResponse = 1030; GetBlocksRequestMessage getBlocksRequest = 1031; GetBlocksResponseMessage getBlocksResponse = 1032; GetBlockCountRequestMessage getBlockCountRequest = 1033; @@ -431,14 +431,14 @@ message SubmitTransactionResponseMessage{ RPCError error = 1000; } -message NotifyChainChangedRequestMessage{ +message NotifyVirtualSelectedParentChainChangedRequestMessage{ } -message NotifyChainChangedResponseMessage{ +message NotifyVirtualSelectedParentChainChangedResponseMessage{ RPCError error = 1000; } -message ChainChangedNotificationMessage{ +message VirtualSelectedParentChainChangedNotificationMessage{ repeated string removedChainBlockHashes = 1; repeated ChainBlock addedChainBlocks = 2; } @@ -533,15 +533,14 @@ message GetSubnetworkResponseMessage{ RPCError error = 1000; } -message GetChainFromBlockRequestMessage{ +message GetVirtualSelectedParentChainFromBlockRequestMessage{ string startHash = 1; - bool includeBlockVerboseData = 2; } -message GetChainFromBlockResponseMessage{ +message GetVirtualSelectedParentChainFromBlockResponseMessage{ repeated string removedChainBlockHashes = 1; repeated ChainBlock addedChainBlocks = 2; - repeated BlockVerboseData blockVerboseData = 3; + RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_chain_from_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_chain_from_block.go deleted file mode 100644 index cb8b6d169..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_chain_from_block.go +++ /dev/null @@ -1,79 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_GetChainFromBlockRequest) toAppMessage() (appmessage.Message, error) { - return &appmessage.GetChainFromBlockRequestMessage{ - StartHash: x.GetChainFromBlockRequest.StartHash, - IncludeBlockVerboseData: x.GetChainFromBlockRequest.IncludeBlockVerboseData, - }, nil -} - -func (x *KaspadMessage_GetChainFromBlockRequest) fromAppMessage(message *appmessage.GetChainFromBlockRequestMessage) error { - x.GetChainFromBlockRequest = &GetChainFromBlockRequestMessage{ - StartHash: message.StartHash, - IncludeBlockVerboseData: message.IncludeBlockVerboseData, - } - return nil -} - -func (x *KaspadMessage_GetChainFromBlockResponse) toAppMessage() (appmessage.Message, error) { - var err *appmessage.RPCError - if x.GetChainFromBlockResponse.Error != nil { - err = &appmessage.RPCError{Message: x.GetChainFromBlockResponse.Error.Message} - } - addedChainBlocks := make([]*appmessage.ChainBlock, len(x.GetChainFromBlockResponse.AddedChainBlocks)) - for i, addedChainBlock := range x.GetChainFromBlockResponse.AddedChainBlocks { - appAddedChainBlock, err := addedChainBlock.toAppMessage() - if err != nil { - return nil, err - } - addedChainBlocks[i] = appAddedChainBlock - } - blockVerboseData := make([]*appmessage.BlockVerboseData, len(x.GetChainFromBlockResponse.BlockVerboseData)) - for i, blockVerboseDatum := range x.GetChainFromBlockResponse.BlockVerboseData { - appBlockVerboseDatum, err := blockVerboseDatum.toAppMessage() - if err != nil { - return nil, err - } - blockVerboseData[i] = appBlockVerboseDatum - } - return &appmessage.GetChainFromBlockResponseMessage{ - RemovedChainBlockHashes: x.GetChainFromBlockResponse.RemovedChainBlockHashes, - AddedChainBlocks: addedChainBlocks, - BlockVerboseData: blockVerboseData, - Error: err, - }, nil -} - -func (x *KaspadMessage_GetChainFromBlockResponse) fromAppMessage(message *appmessage.GetChainFromBlockResponseMessage) error { - var err *RPCError - if message.Error != nil { - err = &RPCError{Message: message.Error.Message} - } - addedChainBlocks := make([]*ChainBlock, len(message.AddedChainBlocks)) - for i, addedChainBlock := range message.AddedChainBlocks { - protoAddedChainBlock := &ChainBlock{} - err := protoAddedChainBlock.fromAppMessage(addedChainBlock) - if err != nil { - return err - } - addedChainBlocks[i] = protoAddedChainBlock - } - blockVerboseData := make([]*BlockVerboseData, len(message.BlockVerboseData)) - for i, blockVerboseDatum := range message.BlockVerboseData { - protoBlockVerboseDatum := &BlockVerboseData{} - err := protoBlockVerboseDatum.fromAppMessage(blockVerboseDatum) - if err != nil { - return err - } - blockVerboseData[i] = protoBlockVerboseDatum - } - x.GetChainFromBlockResponse = &GetChainFromBlockResponseMessage{ - RemovedChainBlockHashes: message.RemovedChainBlockHashes, - AddedChainBlocks: addedChainBlocks, - BlockVerboseData: blockVerboseData, - Error: err, - } - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_chain_from_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_chain_from_block.go new file mode 100644 index 000000000..53ebe1551 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_virtual_selected_parent_chain_from_block.go @@ -0,0 +1,58 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.GetVirtualSelectedParentChainFromBlockRequestMessage{ + StartHash: x.GetVirtualSelectedParentChainFromBlockRequest.StartHash, + }, nil +} + +func (x *KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest) fromAppMessage(message *appmessage.GetVirtualSelectedParentChainFromBlockRequestMessage) error { + x.GetVirtualSelectedParentChainFromBlockRequest = &GetVirtualSelectedParentChainFromBlockRequestMessage{ + StartHash: message.StartHash, + } + return nil +} + +func (x *KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.GetVirtualSelectedParentChainFromBlockResponse.Error != nil { + err = &appmessage.RPCError{Message: x.GetVirtualSelectedParentChainFromBlockResponse.Error.Message} + } + addedChainBlocks := make([]*appmessage.ChainBlock, len(x.GetVirtualSelectedParentChainFromBlockResponse.AddedChainBlocks)) + for i, addedChainBlock := range x.GetVirtualSelectedParentChainFromBlockResponse.AddedChainBlocks { + appAddedChainBlock, err := addedChainBlock.toAppMessage() + if err != nil { + return nil, err + } + addedChainBlocks[i] = appAddedChainBlock + } + return &appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage{ + RemovedChainBlockHashes: x.GetVirtualSelectedParentChainFromBlockResponse.RemovedChainBlockHashes, + AddedChainBlocks: addedChainBlocks, + Error: err, + }, nil +} + +func (x *KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse) fromAppMessage(message *appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + addedChainBlocks := make([]*ChainBlock, len(message.AddedChainBlocks)) + for i, addedChainBlock := range message.AddedChainBlocks { + protoAddedChainBlock := &ChainBlock{} + err := protoAddedChainBlock.fromAppMessage(addedChainBlock) + if err != nil { + return err + } + addedChainBlocks[i] = protoAddedChainBlock + } + x.GetVirtualSelectedParentChainFromBlockResponse = &GetVirtualSelectedParentChainFromBlockResponseMessage{ + RemovedChainBlockHashes: message.RemovedChainBlockHashes, + AddedChainBlocks: addedChainBlocks, + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go deleted file mode 100644 index 84c00c28d..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_chain_changed.go +++ /dev/null @@ -1,94 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_NotifyChainChangedRequest) toAppMessage() (appmessage.Message, error) { - return &appmessage.NotifyChainChangedRequestMessage{}, nil -} - -func (x *KaspadMessage_NotifyChainChangedRequest) fromAppMessage(_ *appmessage.NotifyChainChangedRequestMessage) error { - x.NotifyChainChangedRequest = &NotifyChainChangedRequestMessage{} - return nil -} - -func (x *KaspadMessage_NotifyChainChangedResponse) toAppMessage() (appmessage.Message, error) { - var err *appmessage.RPCError - if x.NotifyChainChangedResponse.Error != nil { - err = &appmessage.RPCError{Message: x.NotifyChainChangedResponse.Error.Message} - } - return &appmessage.NotifyChainChangedResponseMessage{ - Error: err, - }, nil -} - -func (x *KaspadMessage_NotifyChainChangedResponse) fromAppMessage(message *appmessage.NotifyChainChangedResponseMessage) error { - var err *RPCError - if message.Error != nil { - err = &RPCError{Message: message.Error.Message} - } - x.NotifyChainChangedResponse = &NotifyChainChangedResponseMessage{ - Error: err, - } - return nil -} - -func (x *KaspadMessage_ChainChangedNotification) toAppMessage() (appmessage.Message, error) { - addedChainBlocks := make([]*appmessage.ChainBlock, len(x.ChainChangedNotification.AddedChainBlocks)) - for i, addedChainBlock := range x.ChainChangedNotification.AddedChainBlocks { - appAddedChainBlock, err := addedChainBlock.toAppMessage() - if err != nil { - return nil, err - } - addedChainBlocks[i] = appAddedChainBlock - } - return &appmessage.ChainChangedNotificationMessage{ - RemovedChainBlockHashes: x.ChainChangedNotification.RemovedChainBlockHashes, - AddedChainBlocks: addedChainBlocks, - }, nil -} - -func (x *KaspadMessage_ChainChangedNotification) fromAppMessage(message *appmessage.ChainChangedNotificationMessage) error { - addedChainBlocks := make([]*ChainBlock, len(message.AddedChainBlocks)) - for i, addedChainBlock := range message.AddedChainBlocks { - protoAddedChainBlock := &ChainBlock{} - err := protoAddedChainBlock.fromAppMessage(addedChainBlock) - if err != nil { - return err - } - addedChainBlocks[i] = protoAddedChainBlock - } - x.ChainChangedNotification = &ChainChangedNotificationMessage{ - RemovedChainBlockHashes: message.RemovedChainBlockHashes, - AddedChainBlocks: addedChainBlocks, - } - return nil -} - -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, - AcceptedTransactionIDs: acceptedBlock.AcceptedTransactionIds, - } - } - return &appmessage.ChainBlock{ - Hash: x.Hash, - AcceptedBlocks: acceptedBlocks, - }, nil -} - -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, - AcceptedTransactionIds: acceptedBlock.AcceptedTransactionIDs, - } - } - *x = ChainBlock{ - Hash: message.Hash, - AcceptedBlocks: acceptedBlocks, - } - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_chain_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_chain_changed.go new file mode 100644 index 000000000..60471b676 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_virtual_selected_parent_chain_changed.go @@ -0,0 +1,94 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.NotifyVirtualSelectedParentChainChangedRequestMessage{}, nil +} + +func (x *KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest) fromAppMessage(_ *appmessage.NotifyVirtualSelectedParentChainChangedRequestMessage) error { + x.NotifyVirtualSelectedParentChainChangedRequest = &NotifyVirtualSelectedParentChainChangedRequestMessage{} + return nil +} + +func (x *KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.NotifyVirtualSelectedParentChainChangedResponse.Error != nil { + err = &appmessage.RPCError{Message: x.NotifyVirtualSelectedParentChainChangedResponse.Error.Message} + } + return &appmessage.NotifyVirtualSelectedParentChainChangedResponseMessage{ + Error: err, + }, nil +} + +func (x *KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse) fromAppMessage(message *appmessage.NotifyVirtualSelectedParentChainChangedResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.NotifyVirtualSelectedParentChainChangedResponse = &NotifyVirtualSelectedParentChainChangedResponseMessage{ + Error: err, + } + return nil +} + +func (x *KaspadMessage_VirtualSelectedParentChainChangedNotification) toAppMessage() (appmessage.Message, error) { + addedChainBlocks := make([]*appmessage.ChainBlock, len(x.VirtualSelectedParentChainChangedNotification.AddedChainBlocks)) + for i, addedChainBlock := range x.VirtualSelectedParentChainChangedNotification.AddedChainBlocks { + appAddedChainBlock, err := addedChainBlock.toAppMessage() + if err != nil { + return nil, err + } + addedChainBlocks[i] = appAddedChainBlock + } + return &appmessage.VirtualSelectedParentChainChangedNotificationMessage{ + RemovedChainBlockHashes: x.VirtualSelectedParentChainChangedNotification.RemovedChainBlockHashes, + AddedChainBlocks: addedChainBlocks, + }, nil +} + +func (x *KaspadMessage_VirtualSelectedParentChainChangedNotification) fromAppMessage(message *appmessage.VirtualSelectedParentChainChangedNotificationMessage) error { + addedChainBlocks := make([]*ChainBlock, len(message.AddedChainBlocks)) + for i, addedChainBlock := range message.AddedChainBlocks { + protoAddedChainBlock := &ChainBlock{} + err := protoAddedChainBlock.fromAppMessage(addedChainBlock) + if err != nil { + return err + } + addedChainBlocks[i] = protoAddedChainBlock + } + x.VirtualSelectedParentChainChangedNotification = &VirtualSelectedParentChainChangedNotificationMessage{ + RemovedChainBlockHashes: message.RemovedChainBlockHashes, + AddedChainBlocks: addedChainBlocks, + } + return nil +} + +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, + AcceptedTransactionIDs: acceptedBlock.AcceptedTransactionIds, + } + } + return &appmessage.ChainBlock{ + Hash: x.Hash, + AcceptedBlocks: acceptedBlocks, + }, nil +} + +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, + AcceptedTransactionIds: acceptedBlock.AcceptedTransactionIDs, + } + } + *x = ChainBlock{ + Hash: message.Hash, + AcceptedBlocks: acceptedBlocks, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index 89e647b9e..e50fd9c69 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -386,22 +386,22 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.NotifyChainChangedRequestMessage: - payload := new(KaspadMessage_NotifyChainChangedRequest) + case *appmessage.NotifyVirtualSelectedParentChainChangedRequestMessage: + payload := new(KaspadMessage_NotifyVirtualSelectedParentChainChangedRequest) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.NotifyChainChangedResponseMessage: - payload := new(KaspadMessage_NotifyChainChangedResponse) + case *appmessage.NotifyVirtualSelectedParentChainChangedResponseMessage: + payload := new(KaspadMessage_NotifyVirtualSelectedParentChainChangedResponse) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.ChainChangedNotificationMessage: - payload := new(KaspadMessage_ChainChangedNotification) + case *appmessage.VirtualSelectedParentChainChangedNotificationMessage: + payload := new(KaspadMessage_VirtualSelectedParentChainChangedNotification) err := payload.fromAppMessage(message) if err != nil { return nil, err @@ -435,15 +435,15 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.GetChainFromBlockRequestMessage: - payload := new(KaspadMessage_GetChainFromBlockRequest) + case *appmessage.GetVirtualSelectedParentChainFromBlockRequestMessage: + payload := new(KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.GetChainFromBlockResponseMessage: - payload := new(KaspadMessage_GetChainFromBlockResponse) + case *appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage: + payload := new(KaspadMessage_GetVirtualSelectedParentChainFromBlockResponse) err := payload.fromAppMessage(message) if err != nil { return nil, err diff --git a/infrastructure/network/rpcclient/rpc_get_chain_from_block.go b/infrastructure/network/rpcclient/rpc_get_chain_from_block.go index 2e7748f0d..cc8085fc0 100644 --- a/infrastructure/network/rpcclient/rpc_get_chain_from_block.go +++ b/infrastructure/network/rpcclient/rpc_get_chain_from_block.go @@ -2,19 +2,19 @@ package rpcclient import "github.com/kaspanet/kaspad/app/appmessage" -// GetChainFromBlock sends an RPC request respective to the function's name and returns the RPC server's response -func (c *RPCClient) GetChainFromBlock(startHash string, includeBlockVerboseData bool) (*appmessage.GetChainFromBlockResponseMessage, error) { - err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetChainFromBlockRequestMessage(startHash, includeBlockVerboseData)) +// GetVirtualSelectedParentChainFromBlock sends an RPC request respective to the function's name and returns the RPC server's response +func (c *RPCClient) GetVirtualSelectedParentChainFromBlock(startHash string) (*appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage, error) { + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetVirtualSelectedParentChainFromBlockRequestMessage(startHash)) if err != nil { return nil, err } - response, err := c.route(appmessage.CmdGetChainFromBlockResponseMessage).DequeueWithTimeout(c.timeout) + response, err := c.route(appmessage.CmdGetVirtualSelectedParentChainFromBlockResponseMessage).DequeueWithTimeout(c.timeout) if err != nil { return nil, err } - GetChainFromBlockResponse := response.(*appmessage.GetChainFromBlockResponseMessage) - if GetChainFromBlockResponse.Error != nil { - return nil, c.convertRPCError(GetChainFromBlockResponse.Error) + GetVirtualSelectedParentChainFromBlockResponse := response.(*appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage) + if GetVirtualSelectedParentChainFromBlockResponse.Error != nil { + return nil, c.convertRPCError(GetVirtualSelectedParentChainFromBlockResponse.Error) } - return GetChainFromBlockResponse, nil + return GetVirtualSelectedParentChainFromBlockResponse, nil } diff --git a/infrastructure/network/rpcclient/rpc_on_chain_changed.go b/infrastructure/network/rpcclient/rpc_on_chain_changed.go index 328af0231..4e28d9a1f 100644 --- a/infrastructure/network/rpcclient/rpc_on_chain_changed.go +++ b/infrastructure/network/rpcclient/rpc_on_chain_changed.go @@ -6,31 +6,31 @@ import ( "github.com/pkg/errors" ) -// RegisterForChainChangedNotifications sends an RPC request respective to the function's name and returns the RPC server's response. +// RegisterForVirtualSelectedParentChainChangedNotifications sends an RPC request respective to the function's name and returns the RPC server's response. // Additionally, it starts listening for the appropriate notification using the given handler function -func (c *RPCClient) RegisterForChainChangedNotifications(onChainChanged func(notification *appmessage.ChainChangedNotificationMessage)) error { - err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewNotifyChainChangedRequestMessage()) +func (c *RPCClient) RegisterForVirtualSelectedParentChainChangedNotifications(onChainChanged func(notification *appmessage.VirtualSelectedParentChainChangedNotificationMessage)) error { + err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewNotifyVirtualSelectedParentChainChangedRequestMessage()) if err != nil { return err } - response, err := c.route(appmessage.CmdNotifyChainChangedResponseMessage).DequeueWithTimeout(c.timeout) + response, err := c.route(appmessage.CmdNotifyVirtualSelectedParentChainChangedResponseMessage).DequeueWithTimeout(c.timeout) if err != nil { return err } - notifyChainChangedResponse := response.(*appmessage.NotifyChainChangedResponseMessage) + notifyChainChangedResponse := response.(*appmessage.NotifyVirtualSelectedParentChainChangedResponseMessage) if notifyChainChangedResponse.Error != nil { return c.convertRPCError(notifyChainChangedResponse.Error) } - spawn("RegisterForChainChangedNotifications", func() { + spawn("RegisterForVirtualSelectedParentChainChangedNotifications", func() { for { - notification, err := c.route(appmessage.CmdChainChangedNotificationMessage).Dequeue() + notification, err := c.route(appmessage.CmdVirtualSelectedParentChainChangedNotificationMessage).Dequeue() if err != nil { if errors.Is(err, routerpkg.ErrRouteClosed) { break } panic(err) } - ChainChangedNotification := notification.(*appmessage.ChainChangedNotificationMessage) + ChainChangedNotification := notification.(*appmessage.VirtualSelectedParentChainChangedNotificationMessage) onChainChanged(ChainChangedNotification) } }) diff --git a/testing/integration/selected_parent_chain_test.go b/testing/integration/selected_parent_chain_test.go new file mode 100644 index 000000000..8b5812d76 --- /dev/null +++ b/testing/integration/selected_parent_chain_test.go @@ -0,0 +1,130 @@ +package integration + +import ( + "encoding/hex" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "testing" +) + +func TestVirtualSelectedParentChain(t *testing.T) { + // Setup a couple of kaspad instances + kaspad1, kaspad2, _, teardown := standardSetup(t) + defer teardown() + + // Register to virtual selected parent chain changes + onVirtualSelectedParentChainChangedChan := make(chan *appmessage.VirtualSelectedParentChainChangedNotificationMessage) + err := kaspad1.rpcClient.RegisterForVirtualSelectedParentChainChangedNotifications( + func(notification *appmessage.VirtualSelectedParentChainChangedNotificationMessage) { + onVirtualSelectedParentChainChangedChan <- notification + }) + if err != nil { + t.Fatalf("Failed to register for virtual selected parent chain change notifications: %s", err) + } + + // In kaspad1, mine a chain over the genesis and make sure + // each chain changed notifications contains only one entry + // in `added` and nothing in `removed` + chain1TipHash := consensushashing.BlockHash(kaspad1.config.NetParams().GenesisBlock) + chain1TipHashHex := hex.EncodeToString(chain1TipHash[:]) + const blockAmountToMine = 10 + for i := 0; i < blockAmountToMine; i++ { + minedBlock := mineNextBlock(t, kaspad1) + notification := <-onVirtualSelectedParentChainChangedChan + if len(notification.RemovedChainBlockHashes) > 0 { + t.Fatalf("RemovedChainBlockHashes is unexpectedly not empty") + } + if len(notification.AddedChainBlocks) != 1 { + t.Fatalf("Unexpected length of AddedChainBlocks. Want: %d, got: %d", + 1, len(notification.AddedChainBlocks)) + } + + minedBlockHash := consensushashing.BlockHash(minedBlock) + minedBlockHashHex := hex.EncodeToString(minedBlockHash[:]) + if minedBlockHashHex != notification.AddedChainBlocks[0].Hash { + t.Fatalf("Unexpected block hash in AddedChainBlocks. Want: %s, got: %s", + minedBlockHashHex, notification.AddedChainBlocks[0].Hash) + } + chain1TipHashHex = minedBlockHashHex + } + + // In kaspad2, mine a different chain of `blockAmountToMine` + // blocks over the genesis + for i := 0; i < blockAmountToMine; i++ { + mineNextBlock(t, kaspad2) + } + + // Connect the two kaspads + connect(t, kaspad1, kaspad2) + + // In kaspad2, mine another block. This should trigger sync + // between the two nodes + chain2Tip := mineNextBlock(t, kaspad2) + chain2TipHash := consensushashing.BlockHash(chain2Tip) + chain2TipHashHex := hex.EncodeToString(chain2TipHash[:]) + + // For the first `blockAmountToMine - 1` blocks we don't expect + // the chain to change at all + for i := 0; i < blockAmountToMine-1; i++ { + notification := <-onVirtualSelectedParentChainChangedChan + if len(notification.RemovedChainBlockHashes) > 0 { + t.Fatalf("RemovedChainBlockHashes is unexpectedly not empty") + } + if len(notification.AddedChainBlocks) > 0 { + t.Fatalf("AddedChainBlocks is unexpectedly not empty") + } + } + + // Either the next block could cause a reorg or the one + // after it + potentialReorgNotification1 := <-onVirtualSelectedParentChainChangedChan + potentialReorgNotification2 := <-onVirtualSelectedParentChainChangedChan + var reorgNotification *appmessage.VirtualSelectedParentChainChangedNotificationMessage + var nonReorgNotification *appmessage.VirtualSelectedParentChainChangedNotificationMessage + if len(potentialReorgNotification1.RemovedChainBlockHashes) > 0 { + reorgNotification = potentialReorgNotification1 + nonReorgNotification = potentialReorgNotification2 + } else { + reorgNotification = potentialReorgNotification2 + nonReorgNotification = potentialReorgNotification1 + } + + // Make sure that the non-reorg notification has nothing + // in `removed` + if len(nonReorgNotification.RemovedChainBlockHashes) > 0 { + t.Fatalf("nonReorgNotification.RemovedChainBlockHashes is unexpectedly not empty") + } + + // Make sure that the reorg notification contains exactly + // `blockAmountToMine` blocks in its `removed` + if len(reorgNotification.RemovedChainBlockHashes) != blockAmountToMine { + t.Fatalf("Unexpected length of reorgNotification.RemovedChainBlockHashes. Want: %d, got: %d", + blockAmountToMine, len(reorgNotification.RemovedChainBlockHashes)) + } + + // Get the virtual selected parent chain from the tip of + // the first chain + virtualSelectedParentChainFromChain1Tip, err := kaspad1.rpcClient.GetVirtualSelectedParentChainFromBlock(chain1TipHashHex) + if err != nil { + t.Fatalf("GetVirtualSelectedParentChainFromBlock failed: %s", err) + } + + // Make sure that `blockAmountToMine` blocks were removed + // and `blockAmountToMine + 1` blocks were added + if len(virtualSelectedParentChainFromChain1Tip.RemovedChainBlockHashes) != blockAmountToMine { + t.Fatalf("Unexpected length of virtualSelectedParentChainFromChain1Tip.RemovedChainBlockHashes. Want: %d, got: %d", + blockAmountToMine, len(virtualSelectedParentChainFromChain1Tip.RemovedChainBlockHashes)) + } + if len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks) != blockAmountToMine+1 { + t.Fatalf("Unexpected length of virtualSelectedParentChainFromChain1Tip.AddedChainBlocks. Want: %d, got: %d", + blockAmountToMine+1, len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks)) + } + + // Make sure that the last block in `added` is the tip + // of chain2 + lastAddedChainBlock := virtualSelectedParentChainFromChain1Tip.AddedChainBlocks[len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks)-1] + if lastAddedChainBlock.Hash != chain2TipHashHex { + t.Fatalf("Unexpected last added chain block. Want: %s, got: %s", + chain2TipHashHex, lastAddedChainBlock.Hash) + } +} From 5632bee49dc3928183de53c01d6a60dfedfb4a77 Mon Sep 17 00:00:00 2001 From: FestinaLente666 <43236326+FestinaLente666@users.noreply.github.com> Date: Tue, 22 Dec 2020 11:44:32 +0200 Subject: [PATCH 145/351] comments on default constants (#1253) * comments on default constants * more comments on default constants * more comments on default constants * more comments on default constants * gofmt * small typos --- domain/dagconfig/consensus_defaults.go | 68 +++++++++++++++++++++----- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/domain/dagconfig/consensus_defaults.go b/domain/dagconfig/consensus_defaults.go index 91a00673a..68781e1b7 100644 --- a/domain/dagconfig/consensus_defaults.go +++ b/domain/dagconfig/consensus_defaults.go @@ -5,20 +5,66 @@ import ( "time" ) +// The documentation refers to the following constants which aren't explicated in the code: +// d - an upper bound on the round trip time of a block +// delta - the expected fraction of time the width of the network exceeds defaultGHOSTDAGK +// +// For more information about defaultGHOSTDAGK, and its dependency on delta and defaultTargetTimePerBlock +// please refer to the PHANTOM paper: https://eprint.iacr.org/2018/104.pdf +// +// For more information about the DAA constants defaultDifficultyAdjustmentWindowSize, defaultTimestampDeviationTolerance, +// and their relation to defaultGHOSTDAGK and defaultTargetTimePerBlock see: +// https://research.kas.pa/t/handling-timestamp-manipulations/97 +// +// For more information about defaultMergeSetSizeLimit, defaultFinalityDuration and their relation to pruning, see: +// https://research.kas.pa/t/a-proposal-for-finality-in-ghostdag/66/17 +// https://research.kas.pa/t/some-of-the-intuition-behind-the-design-of-the-invalidation-rules-for-pruning/95 +// + const ( - defaultMaxCoinbasePayloadLength = 150 - defaultMaxBlockSize = 1_000_000 - defaultMaxBlockParents = 10 - defaultMassPerTxByte = 1 - defaultMassPerScriptPubKeyByte = 10 - defaultMassPerSigOp = 10000 + defaultMaxCoinbasePayloadLength = 150 + // defaultMaxBlockSize is a bound on the size of a block in bytes, larger values increase the bound d + // on the round trip time of a block, which affects the other parameters as described below + defaultMaxBlockSize = 1_000_000 + // defaultMaxBlockParents is the number of blocks any block can point to. + // Should be about d/defaultTargetTimePerBlock where d is a bound on the round trip time of a block. + defaultMaxBlockParents = 10 + defaultMassPerTxByte = 1 + defaultMassPerScriptPubKeyByte = 10 + defaultMassPerSigOp = 10000 + // defaultMergeSetSizeLimit is a bound on the size of the past of a block and the size of the past + // of its selected parent. Any block which violates this bound is invalid. + // Should be at least an order of magnitude smaller than defaultFinalityDuration/defaultTargetTimePerBlock. + // (Higher values make pruning attacks easier by a constant, lower values make merging after a split or a spike + // in block take longer) defaultMergeSetSizeLimit = 1000 defaultMaxMassAcceptedByBlock = 10000000 defaultBaseSubsidy = 50 * constants.SompiPerKaspa defaultCoinbasePayloadScriptPublicKeyMaxLength = 150 - defaultGHOSTDAGK = 18 - defaultDifficultyAdjustmentWindowSize = 2640 - defaultTimestampDeviationTolerance = 132 - defaultFinalityDuration = 24 * time.Hour - defaultTargetTimePerBlock = 1 * time.Second + // defaultGHOSTDAGK is a bound on the number of blue blocks in the anticone of a blue block. Approximates the maximal + // width of the network. + // Formula (1) in section 4.2 of the PHATOM paper shows how to calculate defaultGHOSTDAGK. The delta term represents a bound + // on the expected fraction of the network life in which the width was higher than defaultGHOSTDAGK. The current value of K + // was calculated for d = 5 seconds and delta = 0.05. + defaultGHOSTDAGK = 18 + // defaultDifficultyAdjustmentWindowSize is the number of blocks in a block's past used to calculate its difficulty + // target. + defaultDifficultyAdjustmentWindowSize = 2640 + // defaultTimestampDeviationTolerance is the allowed deviance of an inconming block's timestamp, measured in block delays. + // A new block can't hold a timestamp lower than the median timestamp of the (defaultTimestampDeviationTolerance*2-1) blocks + // with highest accumulated blue work in its past, such blocks are considered invalid. + // A new block can't hold a timestamp higher than the local system time + defaultTimestampDeviationTolerance/defaultTargetTimePerBlock, + // such blocks are not marked as invalid but are rejected. + defaultTimestampDeviationTolerance = 132 + // defaultFinalityDuration is an approximate lower bound of how old the finality block is. The finality block is chosen to + // be the newest block in the selected chain whose blue score difference from the selected tip is at least + // defaultFinalityDuration/defaultTargetTimePerBlock. + // The pruning block is selected similarly, with the following duration: + // pruning block duration = + // 2*defaultFinalityDuration/defaultTargetTimePerBlock + 4*defaultMergeSetSizeLimit*defaultGHOSTDAGK + 2*defaultGHOSTDAGK + 2 + defaultFinalityDuration = 24 * time.Hour + // defaultTargetTimePerBlock represents how much time should pass on average between two consecutive block creations. + // Should be parametrized such that the average width of the DAG is about defaultMaxBlockParents and such that most of the + // time the width of the DAG is at most defaultGHOSTDAGK. + defaultTargetTimePerBlock = 1 * time.Second ) From e7edfaceb753d74762ef79dcb77d43172b72198c Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 22 Dec 2020 14:05:21 +0200 Subject: [PATCH 146/351] Remove redundant rule errors (#1256) * Remove ErrTimeTooNew and rename ErrBlockIsTooMuchInTheFuture to ErrTimeTooMuchInTheFuture * Remove ErrBlockMassTooHigh * Remove ErrHighHash * Remove ErrInvalidSubnetwork + some cleanup around subnetwork validation * Remove ErrTxMassTooHigh * Remove ErrBadTxInput * Remove ErrOverwriteTx * Remove ErrTooManySigOps * Remove ErrParentBlockUnknown * Remove ErrParentBlockIsNotCurrentTips * Remove ErrWithDiff * Remove ErrFinality * Remove ErrDelayedBlockIsNotAllowed + ErrOrphanBlockIsNotAllowed * Remove ErrSelectedParentDisqualifiedFromChain * Remove ErrBuildInTransactionHasGas * Remove ErrBadFees --- .../block_header_in_isolation.go | 2 +- .../transaction_in_context.go | 2 +- .../transaction_in_isolation.go | 8 +-- domain/consensus/ruleerrors/rule_error.go | 69 +------------------ 4 files changed, 8 insertions(+), 73 deletions(-) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 4578aef10..c6402e6f9 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -52,7 +52,7 @@ func (v *blockValidator) checkBlockTimestampInIsolation(header *externalapi.Doma maxCurrentTime := now + int64(v.timestampDeviationTolerance)*v.targetTimePerBlock.Milliseconds() if blockTimestamp > maxCurrentTime { return errors.Wrapf( - ruleerrors.ErrBlockIsTooMuchInTheFuture, "The block timestamp is in the future.") + ruleerrors.ErrTimeTooMuchInTheFuture, "The block timestamp is in the future.") } return nil } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_context.go b/domain/consensus/processes/transactionvalidator/transaction_in_context.go index 57395bf42..f9611f2ac 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_context.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_context.go @@ -136,7 +136,7 @@ func (v *transactionValidator) checkTransactionOutputAmounts(tx *externalapi.Dom totalSompiOut := uint64(0) // Calculate the total output amount for this transaction. It is safe // to ignore overflow and out of range errors here because those error - // conditions would have already been caught by checkTransactionSanity. + // conditions would have already been caught by checkTransactionAmountRanges. for _, output := range tx.Outputs { totalSompiOut += output.Value } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index e6ad7e4ef..eee4d8168 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -45,7 +45,7 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do return err } - // TODO: fill it with the right subnetwork id. + // TODO: fill it with the node's subnetwork id. err = v.checkTransactionSubnetwork(tx, nil) if err != nil { return err @@ -167,7 +167,7 @@ func (v *transactionValidator) checkNativeTransactionPayload(tx *externalapi.Dom } func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.DomainTransaction, - subnetworkID *externalapi.DomainSubnetworkID) error { + localNodeSubnetworkID *externalapi.DomainSubnetworkID) error { if !v.enableNonNativeSubnetworks && tx.SubnetworkID != subnetworks.SubnetworkIDNative && tx.SubnetworkID != subnetworks.SubnetworkIDCoinbase { return errors.Wrapf(ruleerrors.ErrSubnetworksDisabled, "transaction has non native or coinbase "+ @@ -176,8 +176,8 @@ func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.Domain // If we are a partial node, only transactions on built in subnetworks // or our own subnetwork may have a payload - isLocalNodeFull := subnetworkID == nil - shouldTxBeFull := subnetworks.IsBuiltIn(tx.SubnetworkID) || subnetworks.IsEqual(&tx.SubnetworkID, subnetworkID) + isLocalNodeFull := localNodeSubnetworkID == nil + shouldTxBeFull := subnetworks.IsBuiltIn(tx.SubnetworkID) || subnetworks.IsEqual(&tx.SubnetworkID, localNodeSubnetworkID) if !isLocalNodeFull && !shouldTxBeFull && len(tx.Payload) > 0 { return errors.Wrapf(ruleerrors.ErrInvalidPayload, "transaction that was expected to be partial has a payload "+ diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 4cd5e99d5..667e57402 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -14,10 +14,6 @@ var ( // exists. ErrDuplicateBlock = newRuleError("ErrDuplicateBlock") - // ErrBlockMassTooHigh indicates the mass of a block exceeds the maximum - // allowed limits. - ErrBlockMassTooHigh = newRuleError("ErrBlockMassTooHigh") - // ErrBlockVersionTooOld indicates the block version is too old and is // no longer accepted since the majority of the network has upgraded // to a newer version. @@ -27,9 +23,8 @@ var ( // the last several blocks per the DAG consensus rules. ErrTimeTooOld = newRuleError("ErrTimeTooOld") - // ErrTimeTooNew indicates the time is too far in the future as compared - // the current time. - ErrTimeTooNew = newRuleError("ErrTimeTooNew") + //ErrTimeTooMuchInTheFuture indicates that the block timestamp is too much in the future. + ErrTimeTooMuchInTheFuture = newRuleError("ErrTimeTooMuchInTheFuture") // ErrNoParents indicates that the block is missing parents ErrNoParents = newRuleError("ErrNoParents") @@ -47,10 +42,6 @@ var ( // 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") - // ErrBadMerkleRoot indicates the calculated merkle root does not match // the expected value. ErrBadMerkleRoot = newRuleError("ErrBadMerkleRoot") @@ -59,9 +50,6 @@ var ( // the expected value. ErrBadUTXOCommitment = newRuleError("ErrBadUTXOCommitment") - // ErrInvalidSubnetwork indicates the subnetwork is not allowed. - ErrInvalidSubnetwork = newRuleError("ErrInvalidSubnetwork") - // ErrFinalityPointTimeTooOld indicates a block has a timestamp before the // last finality point. ErrFinalityPointTimeTooOld = newRuleError("ErrFinalityPointTimeTooOld") @@ -75,10 +63,6 @@ var ( // valid transaction must have at least one input. ErrNoTxInputs = newRuleError("ErrNoTxInputs") - // ErrTxMassTooHigh indicates the mass of a transaction exceeds the maximum - // allowed limits. - ErrTxMassTooHigh = newRuleError("ErrTxMassTooHigh") - // ErrBadTxOutValue indicates an output value for a transaction is // invalid in some way such as being out of range. ErrBadTxOutValue = newRuleError("ErrBadTxOutValue") @@ -87,11 +71,6 @@ var ( // input more than once. ErrDuplicateTxInputs = newRuleError("ErrDuplicateTxInputs") - // ErrBadTxInput indicates a transaction input is invalid in some way - // such as referencing a previous transaction outpoint which is out of - // range or not referencing one at all. - ErrBadTxInput = newRuleError("ErrBadTxInput") - // ErrDoubleSpendInSameBlock indicates a transaction // that spends an output that was already spent by another // transaction in the same block. @@ -106,11 +85,6 @@ var ( // valid block may only contain unique transactions. ErrDuplicateTx = newRuleError("ErrDuplicateTx") - // ErrOverwriteTx indicates a block contains a transaction that has - // the same hash as a previous transaction which has not been fully - // spent. - ErrOverwriteTx = newRuleError("ErrOverwriteTx") - // ErrImmatureSpend indicates a transaction is attempting to spend a // coinbase that has not yet reached the required maturity. ErrImmatureSpend = newRuleError("ErrImmatureSpend") @@ -119,14 +93,6 @@ var ( // value than the sum of all of its inputs. ErrSpendTooHigh = newRuleError("ErrSpendTooHigh") - // ErrBadFees indicates the total fees for a block are invalid due to - // exceeding the maximum possible value. - ErrBadFees = newRuleError("ErrBadFees") - - // ErrTooManySigOps indicates the total number of signature operations - // for a transaction or block exceed the maximum allowed limits. - ErrTooManySigOps = newRuleError("ErrTooManySigOps") - // ErrFirstTxNotCoinbase indicates the first transaction in a block // is not a coinbase transaction. ErrFirstTxNotCoinbase = newRuleError("ErrFirstTxNotCoinbase") @@ -153,24 +119,10 @@ var ( // the stack. ErrScriptValidation = newRuleError("ErrScriptValidation") - // ErrParentBlockUnknown indicates that the parent block is not known. - ErrParentBlockUnknown = newRuleError("ErrParentBlockUnknown") - // ErrInvalidAncestorBlock indicates that an ancestor of this block has // already failed validation. ErrInvalidAncestorBlock = newRuleError("ErrInvalidAncestorBlock") - // ErrParentBlockNotCurrentTips indicates that the block's parents are not the - // current tips. This is not a block validation rule, but is required - // for block proposals submitted via getblocktemplate RPC. - ErrParentBlockNotCurrentTips = newRuleError("ErrParentBlockNotCurrentTips") - - // ErrWithDiff indicates that there was an error with UTXOSet.WithDiff - ErrWithDiff = newRuleError("ErrWithDiff") - - // ErrFinality indicates that a block doesn't adhere to the finality rules - ErrFinality = newRuleError("ErrFinality") - // ErrTransactionsNotSorted indicates that transactions in block are not // sorted by subnetwork ErrTransactionsNotSorted = newRuleError("ErrTransactionsNotSorted") @@ -197,14 +149,6 @@ var ( // ErrTooManyParents indicates that a block points to more then `MaxNumParentBlocks` parents ErrTooManyParents = newRuleError("ErrTooManyParents") - // ErrDelayedBlockIsNotAllowed indicates that a block with a delayed timestamp was - // submitted with BFDisallowDelay flag raised. - ErrDelayedBlockIsNotAllowed = newRuleError("ErrDelayedBlockIsNotAllowed") - - // ErrOrphanBlockIsNotAllowed indicates that an orphan block was submitted with - // BFDisallowOrphans flag raised. - ErrOrphanBlockIsNotAllowed = newRuleError("ErrOrphanBlockIsNotAllowed") - // ErrViolatingBoundedMergeDepth indicates that a block is violating finality from // its own point of view ErrViolatingBoundedMergeDepth = newRuleError("ErrViolatingBoundedMergeDepth") @@ -216,16 +160,10 @@ var ( // In the same block ErrChainedTransactions = newRuleError("ErrChainedTransactions") - // ErrSelectedParentDisqualifiedFromChain indicates that a block's selectedParent has the status DisqualifiedFromChain - ErrSelectedParentDisqualifiedFromChain = newRuleError("ErrSelectedParentDisqualifiedFromChain") - // ErrBlockSizeTooHigh indicates the size of a block exceeds the maximum // allowed limits. ErrBlockSizeTooHigh = newRuleError("ErrBlockSizeTooHigh") - // ErrBuiltInTransactionHasGas indicates that a transaction with built in subnetwork ID has a non zero gas. - ErrBuiltInTransactionHasGas = newRuleError("ErrBuiltInTransactionHasGas") - ErrKnownInvalid = newRuleError("ErrKnownInvalid") ErrSubnetworksDisabled = newRuleError("ErrSubnetworksDisabled") @@ -238,9 +176,6 @@ var ( //ErrPruningPointViolation indicates that the pruning point isn't in the block past. ErrPruningPointViolation = newRuleError("ErrPruningPointViolation") - //ErrBlockIsTooMuchInTheFuture indicates that the block timestamp is too much in the future. - ErrBlockIsTooMuchInTheFuture = newRuleError("ErrBlockIsTooMuchInTheFuture") - ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint") ) From c2cec2f1706bb3595918413a628e2eebfb9c0e7b Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 22 Dec 2020 16:29:38 +0200 Subject: [PATCH 147/351] Fix the Sequence field in transaction inputs always getting deserialized to MaxUint64. (#1258) --- app/appmessage/p2p_msgtx.go | 6 ++---- app/appmessage/p2p_msgtx_test.go | 3 ++- .../server/grpcserver/protowire/p2p_transaction.go | 2 +- testing/integration/tx_relay_test.go | 2 +- testing/integration/utxo_index_test.go | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index 54c367418..94661b7cf 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -9,8 +9,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "strconv" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" @@ -98,11 +96,11 @@ type TxIn struct { // NewTxIn returns a new kaspa transaction input with the provided // previous outpoint point and signature script with a default sequence of // MaxTxInSequenceNum. -func NewTxIn(prevOut *Outpoint, signatureScript []byte) *TxIn { +func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64) *TxIn { return &TxIn{ PreviousOutpoint: *prevOut, SignatureScript: signatureScript, - Sequence: constants.MaxTxInSequenceNum, + Sequence: sequence, } } diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index 7e25eceea..e85a50601 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -7,6 +7,7 @@ package appmessage import ( "bytes" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "math" "reflect" "testing" @@ -68,7 +69,7 @@ func TestTx(t *testing.T) { // Ensure we get the same transaction input back out. sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} - txIn := NewTxIn(prevOut, sigScript) + txIn := NewTxIn(prevOut, sigScript, constants.MaxTxInSequenceNum) if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) { t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v", spew.Sprint(&txIn.PreviousOutpoint), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go index c2fb5a4c7..f50f8515c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go @@ -25,7 +25,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { } outpoint := appmessage.NewOutpoint(prevTxID, protoInput.PreviousOutpoint.Index) - inputs[i] = appmessage.NewTxIn(outpoint, protoInput.SignatureScript) + inputs[i] = appmessage.NewTxIn(outpoint, protoInput.SignatureScript, protoInput.Sequence) } outputs := make([]*appmessage.TxOut, len(x.Outputs)) diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 86f7e20d2..3c23e0a73 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -88,7 +88,7 @@ func waitForPayeeToReceiveBlock(t *testing.T, payeeBlockAddedChan chan *appmessa func generateTx(t *testing.T, firstBlockCoinbase *externalapi.DomainTransaction, payer, payee *appHarness) *appmessage.MsgTx { txIns := make([]*appmessage.TxIn, 1) - txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensushashing.TransactionID(firstBlockCoinbase), 0), []byte{}) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(consensushashing.TransactionID(firstBlockCoinbase), 0), []byte{}, 0) payeeAddress, err := util.DecodeAddress(payee.miningAddress, util.Bech32PrefixKaspaSim) if err != nil { diff --git a/testing/integration/utxo_index_test.go b/testing/integration/utxo_index_test.go index c1388a335..221085141 100644 --- a/testing/integration/utxo_index_test.go +++ b/testing/integration/utxo_index_test.go @@ -151,7 +151,7 @@ func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAdd } txIns := make([]*appmessage.TxIn, 1) - txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(transactionID, entry.Outpoint.Index), []byte{}) + txIns[0] = appmessage.NewTxIn(appmessage.NewOutpoint(transactionID, entry.Outpoint.Index), []byte{}, 0) payeeAddress, err := util.DecodeAddress(miningAddress1, util.Bech32PrefixKaspaSim) if err != nil { From cb9d7e313d5744f934cde103667a0a926f303835 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 22 Dec 2020 17:38:54 +0200 Subject: [PATCH 148/351] Implement Clone and Equal for all model types (#1155) * [NOD-1575] Implement Clone and Equal for all model types * [NOD-1575] Add assertion for transaction ID equality * [NOD-1575] Use DomainTransaction.Equal to compare to expected coinbase transaction * [NOD-1575] Add TestDomainBlockHeader_Clone * [NOD-1575] Don't clone nil values * [NOD-1575] Add type assertions * [NOD-1575] Don't clone nil values * [NOD-1575] Add missing Equals * [NOD-1575] Add length checks * [NOD-1575] Update comment * [NOD-1575] Check length for TransactionAcceptanceData * [NOD-1575] Explicitly clone nils where needed * [NOD-1575] Clone tx id * [NOD-1575] Flip condition * Nod 1576 make coverage tests for equal clone inside model externalapi (#1177) * [NOD-1576] Make coverage tests for equal and clone inside model and externalapi * Some formatting and naming fixes * Made transactionToCompare type exported * Added some tests and made some changes to the tests code * No changes made * Some formatting and naming changes made * Made better test coverage for externalapi clone and equal functions * Changed expected result for two cases * Added equal and clone functions tests for ghostdag and utxodiff * Added tests * [NOD-1576] Implement reachabilitydata equal/clone unit tests * [NOD-1576] Full coverage of reachabilitydata equal/clone unit tests * Made changes and handling panic to transaction_equal_clone_test.go and formating of utxodiff_equal_clone_test.go * Added recoverForEqual2 for handling panic to transaction_equal_clone_test.go * [NOD-1576] Full coverage of transaction equal unit test * [NOD-1576] Add expects panic * [NOD-1576] Allow composites in go vet * [NOD-1576] Code review fixes (#1223) * [NOD-1576] Code review fixes * [NOD-1576] Code review fixes part 2 * [NOD-1576] Fix wrong name Co-authored-by: karim1king Co-authored-by: Ori Newman Co-authored-by: Karim * Fix merge errors * Use Equal where possible * Use Equal where possible * Use Equal where possible Co-authored-by: andrey-hash <74914043+andrey-hash@users.noreply.github.com> Co-authored-by: karim1king Co-authored-by: Karim --- app/appmessage/p2p_msgblock.go | 2 +- app/appmessage/p2p_msgblock_test.go | 2 +- app/appmessage/p2p_msgrequestheaders_test.go | 2 +- app/appmessage/p2p_msgtx.go | 4 +- app/appmessage/p2p_msgtx_test.go | 10 +- app/protocol/flowcontext/orphans.go | 2 +- .../flows/blockrelay/handle_relay_invs.go | 2 +- app/protocol/flows/blockrelay/ibd.go | 2 +- .../flows/handshake/receiveversion.go | 2 +- build_and_test.sh | 2 +- domain/consensus/consensus.go | 2 +- domain/consensus/finality_test.go | 14 +- .../model/acceptancedata_equal_clone_test.go | 809 ++++++++++++ domain/consensus/model/blockrelations.go | 25 +- .../model/blockrelations_equal_clone_test.go | 115 ++ .../model/externalapi/acceptancedata.go | 78 +- domain/consensus/model/externalapi/block.go | 81 +- .../externalapi/block_equal_clone_test.go | 375 ++++++ .../consensus/model/externalapi/blockinfo.go | 9 + .../model/externalapi/blockinfo_clone_test.go | 45 + .../model/externalapi/blocklocator.go | 5 + .../externalapi/blocklocator_clone_test.go | 67 + .../model/externalapi/blockstatus.go | 9 + .../blockstatus_equal_clone_test.go | 87 ++ .../consensus/model/externalapi/coinbase.go | 14 + .../model/externalapi/coinbase_clone_test.go | 59 + .../consensus/model/externalapi/equal_test.go | 238 ++++ domain/consensus/model/externalapi/hash.go | 31 +- .../externalapi/hash_clone_equal_test.go | 119 ++ .../model/externalapi/subnetworkid.go | 17 +- .../subnetworkid_clone_equal_test.go | 99 ++ domain/consensus/model/externalapi/sync.go | 39 + .../externalapi/sync_equal_clone_test.go | 126 ++ .../model/externalapi/transaction.go | 175 ++- .../transaction_equal_clone_test.go | 1133 +++++++++++++++++ .../consensus/model/externalapi/utxoentry.go | 1 + domain/consensus/model/reachabilitydata.go | 100 +- .../reachabilitydata_equal_clone_test.go | 296 +++++ .../blockprocessor/validateandinsertblock.go | 4 +- .../validateandinsertpruningpoint.go | 2 +- .../blockvalidator/block_body_in_isolation.go | 2 +- .../blockvalidator/block_header_in_context.go | 2 +- .../block_header_in_isolation.go | 2 +- .../add_block_to_virtual.go | 8 +- .../calculate_past_utxo.go | 2 +- .../calculate_past_utxo_test.go | 2 +- .../check_finality_violation.go | 2 +- .../find_selected_parent_chain_changes.go | 2 +- ...find_selected_parent_chain_changes_test.go | 10 +- .../pick_virtual_parents.go | 2 +- .../resolve_block_status.go | 6 +- .../resolve_block_status_test.go | 2 +- .../update_pruning_utxo_set.go | 2 +- .../consensusstatemanager/update_virtual.go | 4 +- .../consensusstatemanager/utxo_diffs.go | 6 +- .../verify_and_build_utxo.go | 6 +- .../dagtopologymanager/dagtopologymanager.go | 8 +- .../selected_child_iterator.go | 2 +- .../finalitymanager/finality_manager.go | 4 +- .../processes/ghostdag2/ghostdagimpl.go | 6 +- .../ghostdagmanager/ghostdag_test.go | 4 +- .../processes/ghostdagmanager/mergeset.go | 2 +- .../headertipsmanager.go | 2 +- .../pruningmanager/pruningmanager.go | 2 +- .../reachability_external_test.go | 10 +- .../reachabilitymanager/reachability_test.go | 4 +- .../processes/reachabilitymanager/tree.go | 16 +- .../processes/syncmanager/syncinfo.go | 2 +- .../transaction_in_isolation.go | 4 +- domain/consensus/utils/hashes/to_big.go | 2 +- domain/consensus/utils/subnetworks/compare.go | 11 - domain/consensus/utils/utxo/utxo_entry.go | 38 +- .../consensus/utils/utxo/utxo_entry_test.go | 113 ++ domain/dagconfig/genesis_test.go | 8 +- domain/dagconfig/params_test.go | 2 +- domain/miningmanager/mempool/mempool.go | 4 +- domain/utxoindex/store.go | 4 +- domain/utxoindex/utxoindex.go | 4 +- testing/integration/basic_sync_test.go | 4 +- 79 files changed, 4346 insertions(+), 174 deletions(-) create mode 100644 domain/consensus/model/acceptancedata_equal_clone_test.go create mode 100644 domain/consensus/model/blockrelations_equal_clone_test.go create mode 100644 domain/consensus/model/externalapi/block_equal_clone_test.go create mode 100644 domain/consensus/model/externalapi/blockinfo_clone_test.go create mode 100644 domain/consensus/model/externalapi/blocklocator_clone_test.go create mode 100644 domain/consensus/model/externalapi/blockstatus_equal_clone_test.go create mode 100644 domain/consensus/model/externalapi/coinbase_clone_test.go create mode 100644 domain/consensus/model/externalapi/equal_test.go create mode 100644 domain/consensus/model/externalapi/hash_clone_equal_test.go create mode 100644 domain/consensus/model/externalapi/subnetworkid_clone_equal_test.go create mode 100644 domain/consensus/model/externalapi/sync_equal_clone_test.go create mode 100644 domain/consensus/model/externalapi/transaction_equal_clone_test.go create mode 100644 domain/consensus/model/reachabilitydata_equal_clone_test.go create mode 100644 domain/consensus/utils/utxo/utxo_entry_test.go diff --git a/app/appmessage/p2p_msgblock.go b/app/appmessage/p2p_msgblock.go index 5d8d3de53..4436d40e8 100644 --- a/app/appmessage/p2p_msgblock.go +++ b/app/appmessage/p2p_msgblock.go @@ -71,7 +71,7 @@ func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { // Note: this operation modifies the block in place. func (msg *MsgBlock) ConvertToPartial(subnetworkID *externalapi.DomainSubnetworkID) { for _, tx := range msg.Transactions { - if tx.SubnetworkID != *subnetworkID { + if !tx.SubnetworkID.Equal(subnetworkID) { tx.Payload = []byte{} } } diff --git a/app/appmessage/p2p_msgblock_test.go b/app/appmessage/p2p_msgblock_test.go index 39d02fca9..347b10556 100644 --- a/app/appmessage/p2p_msgblock_test.go +++ b/app/appmessage/p2p_msgblock_test.go @@ -110,7 +110,7 @@ func TestConvertToPartial(t *testing.T) { for _, testTransaction := range transactions { var subnetworkTx *MsgTx for _, blockTransaction := range block.Transactions { - if blockTransaction.SubnetworkID == *testTransaction.subnetworkID { + if blockTransaction.SubnetworkID.Equal(testTransaction.subnetworkID) { subnetworkTx = blockTransaction } } diff --git a/app/appmessage/p2p_msgrequestheaders_test.go b/app/appmessage/p2p_msgrequestheaders_test.go index 1d475b9d2..9d0a60cd3 100644 --- a/app/appmessage/p2p_msgrequestheaders_test.go +++ b/app/appmessage/p2p_msgrequestheaders_test.go @@ -26,7 +26,7 @@ func TestRequstIBDBlocks(t *testing.T) { // Ensure we get the same data back out. msg := NewMsgRequstHeaders(lowHash, highHash) - if *msg.HighHash != *highHash { + if !msg.HighHash.Equal(highHash) { t.Errorf("NewMsgRequstHeaders: wrong high hash - got %v, want %v", msg.HighHash, highHash) } diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index 94661b7cf..1e65d91ea 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -256,8 +256,8 @@ func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 { // 3. The transaction's subnetwork func (msg *MsgTx) IsSubnetworkCompatible(subnetworkID *externalapi.DomainSubnetworkID) bool { return subnetworkID == nil || - *subnetworkID == subnetworks.SubnetworkIDNative || - *subnetworkID == msg.SubnetworkID + subnetworkID.Equal(&subnetworks.SubnetworkIDNative) || + subnetworkID.Equal(&msg.SubnetworkID) } // newMsgTx returns a new tx message that conforms to the Message interface. diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index e85a50601..c1dba1885 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -53,7 +53,7 @@ func TestTx(t *testing.T) { // testing package functionality. prevOutIndex := uint32(1) prevOut := NewOutpoint(txID, prevOutIndex) - if prevOut.TxID != *txID { + if !prevOut.TxID.Equal(txID) { t.Errorf("NewOutpoint: wrong ID - got %v, want %v", spew.Sprint(&prevOut.TxID), spew.Sprint(txID)) } @@ -179,7 +179,7 @@ func TestTxHashAndID(t *testing.T) { // Ensure the TxID for coinbase transaction is the same as TxHash. tx1ID := tx1.TxID() - if *tx1ID != *wantTxID1 { + if !tx1ID.Equal(wantTxID1) { t.Errorf("TxID: wrong ID - got %v, want %v", spew.Sprint(tx1ID), spew.Sprint(wantTxID1)) } @@ -236,19 +236,19 @@ func TestTxHashAndID(t *testing.T) { // Ensure the hash produced is expected. tx2Hash := tx2.TxHash() - if *tx2Hash != *wantHash2 { + if !tx2Hash.Equal(wantHash2) { t.Errorf("TxHash: wrong hash - got %v, want %v", spew.Sprint(tx2Hash), spew.Sprint(wantHash2)) } // Ensure the TxID for coinbase transaction is the same as TxHash. tx2ID := tx2.TxID() - if *tx2ID != *wantID2 { + if !tx2ID.Equal(wantID2) { t.Errorf("TxID: wrong ID - got %v, want %v", spew.Sprint(tx2ID), spew.Sprint(wantID2)) } - if *tx2ID == (externalapi.DomainTransactionID)(*tx2Hash) { + if tx2ID.Equal((*externalapi.DomainTransactionID)(tx2Hash)) { t.Errorf("tx2ID and tx2Hash shouldn't be the same for non-coinbase transaction with signature and/or payload") } diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index c57afd95a..853462255 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -130,7 +130,7 @@ func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) var childOrphans []externalapi.DomainHash for orphanHash, orphanBlock := range f.orphans { for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes { - if *orphanBlockParentHash == *blockHash { + if orphanBlockParentHash.Equal(blockHash) { childOrphans = append(childOrphans, orphanHash) break } diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 26e335580..8b91c5788 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -171,7 +171,7 @@ func (flow *handleRelayInvsFlow) requestBlock(requestHash *externalapi.DomainHas block := appmessage.MsgBlockToDomainBlock(msgBlock) blockHash := consensushashing.BlockHash(block) - if *blockHash != *requestHash { + if !blockHash.Equal(requestHash) { return nil, false, protocolerrors.Errorf(true, "got unrequested block %s", blockHash) } diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 41745bbab..a43c2e379 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -279,7 +279,7 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do block := appmessage.MsgBlockToDomainBlock(msgIBDBlock.MsgBlock) blockHash := consensushashing.BlockHash(block) - if *expectedHash != *blockHash { + if !expectedHash.Equal(blockHash) { return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash) } diff --git a/app/protocol/flows/handshake/receiveversion.go b/app/protocol/flows/handshake/receiveversion.go index b0191b9b7..f3357dab1 100644 --- a/app/protocol/flows/handshake/receiveversion.go +++ b/app/protocol/flows/handshake/receiveversion.go @@ -90,7 +90,7 @@ func (flow *receiveVersionFlow) start() (*appmessage.NetAddress, error) { isRemoteNodeFull := msgVersion.SubnetworkID == nil isOutbound := flow.peer.Connection().IsOutbound() if (isLocalNodeFull && !isRemoteNodeFull && isOutbound) || - (!isLocalNodeFull && !isRemoteNodeFull && *msgVersion.SubnetworkID != *localSubnetworkID) { + (!isLocalNodeFull && !isRemoteNodeFull && !msgVersion.SubnetworkID.Equal(localSubnetworkID)) { return nil, protocolerrors.New(false, "incompatible subnetworks") } diff --git a/build_and_test.sh b/build_and_test.sh index 1f8fbc0a4..6fd9ac9ba 100755 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -19,7 +19,7 @@ staticcheck -checks "\ SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002, \ SA9003,SA9004,SA9005,SA9006,ST1019" ./... -go vet $FLAGS ./... +go vet -composites=false $FLAGS ./... go build $FLAGS -o kaspad . diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 6ad01c6a9..d4b01df9a 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -171,7 +171,7 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi return nil, err } - if *expectedPruningPointHash != *pruningPointHash { + if !expectedPruningPointHash.Equal(pruningPointHash) { return nil, errors.Wrapf(ruleerrors.ErrWrongPruningPointHash, "expected pruning point %s but got %s", expectedPruningPointHash, pruningPointHash) diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 0c5aa3189..4fc06b148 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -107,7 +107,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) } - if *consensushashing.BlockHash(selectedTip) != *sideChainTipHash { + if !consensushashing.BlockHash(selectedTip).Equal(sideChainTipHash) { t.Fatalf("Overtaking block in side-chain is not selectedTip") } @@ -125,7 +125,7 @@ func TestFinality(t *testing.T) { t.Fatalf("TestFinality: Failed getting the virtual's finality point: %v", err) } - if *virtualFinality == *params.GenesisHash { + if virtualFinality.Equal(params.GenesisHash) { t.Fatalf("virtual's finalityPoint is still genesis after adding finalityInterval + 1 blocks to the main chain") } @@ -309,7 +309,7 @@ func TestBoundedMergeDepth(t *testing.T) { // Make sure it's actually blue found := false for _, blue := range virtualGhotDagData.MergeSetBlues() { - if *blue == *kosherizingBlockHash { + if blue.Equal(kosherizingBlockHash) { found = true break } @@ -329,7 +329,7 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if *consensushashing.BlockHash(virtualSelectedParent) != *consensushashing.BlockHash(pointAtBlueKosherizing) { + if !consensushashing.BlockHash(virtualSelectedParent).Equal(consensushashing.BlockHash(pointAtBlueKosherizing)) { t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(pointAtBlueKosherizing), consensushashing.BlockHash(virtualSelectedParent)) } @@ -346,7 +346,7 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if *consensushashing.BlockHash(virtualSelectedParent) != *tip { + if !consensushashing.BlockHash(virtualSelectedParent).Equal(tip) { t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, consensushashing.BlockHash(virtualSelectedParent)) } @@ -357,7 +357,7 @@ func TestBoundedMergeDepth(t *testing.T) { // Make sure it's actually blue found = false for _, blue := range virtualGhotDagData.MergeSetBlues() { - if *blue == *kosherizingBlockHash { + if blue.Equal(kosherizingBlockHash) { found = true break } @@ -382,7 +382,7 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if *consensushashing.BlockHash(virtualSelectedParent) != *consensushashing.BlockHash(transitiveBlueKosherizing) { + if !consensushashing.BlockHash(virtualSelectedParent).Equal(consensushashing.BlockHash(transitiveBlueKosherizing)) { t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(transitiveBlueKosherizing), consensushashing.BlockHash(virtualSelectedParent)) } diff --git a/domain/consensus/model/acceptancedata_equal_clone_test.go b/domain/consensus/model/acceptancedata_equal_clone_test.go new file mode 100644 index 000000000..73bc29c9a --- /dev/null +++ b/domain/consensus/model/acceptancedata_equal_clone_test.go @@ -0,0 +1,809 @@ +package model_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "reflect" + "testing" +) + +func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAcceptanceData { + + tests := []*externalapi.TransactionAcceptanceData{ + { + &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }, + } + return tests +} + +type testTransactionAcceptanceDataToCompare struct { + transactionAcceptanceData *externalapi.TransactionAcceptanceData + expectedResult bool +} + +type testTransactionAcceptanceDataStruct struct { + baseTransactionAcceptanceData *externalapi.TransactionAcceptanceData + transactionAcceptanceDataToCompareTo []testTransactionAcceptanceDataToCompare +} + +func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStruct { + var testTransactionAcceptanceDataBase = externalapi.TransactionAcceptanceData{ + + &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + } + + var testTransactionAcceptanceData1 = externalapi.TransactionAcceptanceData{ + &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + } + // test 2: different transactions + var testTransactionAcceptanceData2 = externalapi.TransactionAcceptanceData{ + &externalapi.DomainTransaction{ + Version: 2, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + } + //test 3: different Fee + var testTransactionAcceptanceData3 = externalapi.TransactionAcceptanceData{ + &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 2, + true, + } + //test 4: different isAccepted + var testTransactionAcceptanceData4 = externalapi.TransactionAcceptanceData{ + &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + false, + } + + tests := []testTransactionAcceptanceDataStruct{ + { + baseTransactionAcceptanceData: &testTransactionAcceptanceDataBase, + transactionAcceptanceDataToCompareTo: []testTransactionAcceptanceDataToCompare{ + { + transactionAcceptanceData: &testTransactionAcceptanceData1, + expectedResult: true, + }, { + transactionAcceptanceData: &testTransactionAcceptanceData2, + expectedResult: false, + }, { + transactionAcceptanceData: &testTransactionAcceptanceData3, + expectedResult: false, + }, { + transactionAcceptanceData: &testTransactionAcceptanceData4, + expectedResult: false, + }, { + transactionAcceptanceData: nil, + expectedResult: false, + }, + }, + }, { + baseTransactionAcceptanceData: nil, + transactionAcceptanceDataToCompareTo: []testTransactionAcceptanceDataToCompare{ + { + transactionAcceptanceData: &testTransactionAcceptanceData1, + expectedResult: false, + }, { + transactionAcceptanceData: nil, + expectedResult: true, + }, + }, + }, + } + return tests +} + +func TestTransactionAcceptanceData_Equal(t *testing.T) { + acceptanceData := initTransactionAcceptanceDataForEqual() + for i, test := range acceptanceData { + for j, subTest := range test.transactionAcceptanceDataToCompareTo { + result1 := test.baseTransactionAcceptanceData.Equal(subTest.transactionAcceptanceData) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.transactionAcceptanceData.Equal(test.baseTransactionAcceptanceData) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestTransactionAcceptanceData_Clone(t *testing.T) { + + testTransactionAcceptanceData := initTestTransactionAcceptanceDataForClone() + for i, transactionAcceptanceData := range testTransactionAcceptanceData { + transactionAcceptanceDataClone := transactionAcceptanceData.Clone() + if !transactionAcceptanceDataClone.Equal(transactionAcceptanceData) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(transactionAcceptanceData, transactionAcceptanceDataClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} + +func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { + + tests := []*externalapi.BlockAcceptanceData{{&externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{ + { + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}, + }, + } + return tests +} + +type testBlockAcceptanceDataToCompare struct { + blockAcceptanceData *externalapi.BlockAcceptanceData + expectedResult bool +} + +type testBlockAcceptanceDataStruct struct { + baseBlockAcceptanceData *externalapi.BlockAcceptanceData + blockAcceptanceDataToCompareTo []testBlockAcceptanceDataToCompare +} + +func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { + var testBlockAcceptanceDataBase = externalapi.BlockAcceptanceData{ + &externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}} + //test 1: structs are equal + var testBlockAcceptanceData1 = externalapi.BlockAcceptanceData{ + &externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}} + // test 2: different size + var testBlockAcceptanceData2 = externalapi.BlockAcceptanceData{ + &externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }, {}}} + //test 3: different transactions, same size + var testBlockAcceptanceData3 = externalapi.BlockAcceptanceData{ + &externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + false, + }}} + + // test 4 - different block hash + var testBlockAcceptanceData4 = externalapi.BlockAcceptanceData{ + &externalapi.DomainHash{2}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}} + + tests := []testBlockAcceptanceDataStruct{ + { + baseBlockAcceptanceData: &testBlockAcceptanceDataBase, + blockAcceptanceDataToCompareTo: []testBlockAcceptanceDataToCompare{ + { + blockAcceptanceData: &testBlockAcceptanceData1, + expectedResult: true, + }, { + blockAcceptanceData: &testBlockAcceptanceData2, + expectedResult: false, + }, { + blockAcceptanceData: &testBlockAcceptanceData3, + expectedResult: false, + }, { + blockAcceptanceData: nil, + expectedResult: false, + }, + { + blockAcceptanceData: &testBlockAcceptanceData4, + expectedResult: false, + }, + }, + }, { + baseBlockAcceptanceData: nil, + blockAcceptanceDataToCompareTo: []testBlockAcceptanceDataToCompare{ + { + blockAcceptanceData: &testBlockAcceptanceData1, + expectedResult: false, + }, { + blockAcceptanceData: nil, + expectedResult: true, + }, + }, + }, + } + return tests +} + +func TestBlockAcceptanceData_Equal(t *testing.T) { + + blockAcceptances := iniBlockAcceptanceDataForEqual() + for i, test := range blockAcceptances { + for j, subTest := range test.blockAcceptanceDataToCompareTo { + result1 := test.baseBlockAcceptanceData.Equal(subTest.blockAcceptanceData) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.blockAcceptanceData.Equal(test.baseBlockAcceptanceData) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestBlockAcceptanceData_Clone(t *testing.T) { + + testBlockAcceptanceData := initTestBlockAcceptanceDataForClone() + for i, blockAcceptanceData := range testBlockAcceptanceData { + blockAcceptanceDataClone := blockAcceptanceData.Clone() + if !blockAcceptanceDataClone.Equal(blockAcceptanceData) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(blockAcceptanceData, blockAcceptanceDataClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} + +func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { + + test1 := []*externalapi.BlockAcceptanceData{{ + &externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{ + { + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}, + }, + } + tests := []externalapi.AcceptanceData{test1, test1} + return tests +} + +type testAcceptanceDataToCompare struct { + acceptanceData externalapi.AcceptanceData + expectedResult bool +} + +type testAcceptanceDataStruct struct { + baseAcceptanceData externalapi.AcceptanceData + acceptanceDataToCompareTo []testAcceptanceDataToCompare +} + +func initAcceptanceDataForEqual() []testAcceptanceDataStruct { + var testAcceptanceDataBase = []*externalapi.BlockAcceptanceData{ + { + &externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}}} + //test 1: structs are equal + var testAcceptanceData1 = []*externalapi.BlockAcceptanceData{ + {&externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}}} + // test 2: different size + var testAcceptanceData2 = []*externalapi.BlockAcceptanceData{ + {&externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}}, {}} + //test 3: different transactions, same size + var testAcceptanceData3 = []*externalapi.BlockAcceptanceData{ + {&externalapi.DomainHash{1}, + []*externalapi.TransactionAcceptanceData{{ + &externalapi.DomainTransaction{ + 2, + []*externalapi.DomainTransactionInput{{ + externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + 1, + true, + }}}} + + tests := []testAcceptanceDataStruct{ + { + baseAcceptanceData: testAcceptanceDataBase, + acceptanceDataToCompareTo: []testAcceptanceDataToCompare{ + { + acceptanceData: testAcceptanceData1, + expectedResult: true, + }, { + acceptanceData: testAcceptanceData2, + expectedResult: false, + }, { + acceptanceData: testAcceptanceData3, + expectedResult: false, + }, + }, + }, + } + return tests +} + +func TestAcceptanceData_Equal(t *testing.T) { + + acceptances := initAcceptanceDataForEqual() + for i, test := range acceptances { + for j, subTest := range test.acceptanceDataToCompareTo { + result1 := test.baseAcceptanceData.Equal(subTest.acceptanceData) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.acceptanceData.Equal(test.baseAcceptanceData) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestAcceptanceData_Clone(t *testing.T) { + + testAcceptanceData := initTestAcceptanceDataForClone() + for i, acceptanceData := range testAcceptanceData { + acceptanceDataClone := acceptanceData.Clone() + if !acceptanceDataClone.Equal(acceptanceData) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(acceptanceData, acceptanceDataClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/blockrelations.go b/domain/consensus/model/blockrelations.go index 2ed402d46..face57b60 100644 --- a/domain/consensus/model/blockrelations.go +++ b/domain/consensus/model/blockrelations.go @@ -10,12 +10,29 @@ type BlockRelations struct { // Clone returns a clone of BlockRelations func (br *BlockRelations) Clone() *BlockRelations { - if br == nil { - return nil - } - return &BlockRelations{ Parents: externalapi.CloneHashes(br.Parents), Children: externalapi.CloneHashes(br.Children), } } + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &BlockRelations{[]*externalapi.DomainHash{}, []*externalapi.DomainHash{}} + +// Equal returns whether br equals to other +func (br *BlockRelations) Equal(other *BlockRelations) bool { + if br == nil || other == nil { + return br == other + } + + if !externalapi.HashesEqual(br.Parents, other.Parents) { + return false + } + + if !externalapi.HashesEqual(br.Children, other.Children) { + return false + } + + return true +} diff --git a/domain/consensus/model/blockrelations_equal_clone_test.go b/domain/consensus/model/blockrelations_equal_clone_test.go new file mode 100644 index 000000000..39c05e8e3 --- /dev/null +++ b/domain/consensus/model/blockrelations_equal_clone_test.go @@ -0,0 +1,115 @@ +package model + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "reflect" + "testing" +) + +func initTestBlockRelationsForClone() []*BlockRelations { + + tests := []*BlockRelations{ + { + []*externalapi.DomainHash{{1}, {2}}, + []*externalapi.DomainHash{{3}, {4}}, + }, + } + return tests +} + +type testBlockRelationsToCompare struct { + blockRelations *BlockRelations + expectedResult bool +} + +type testBlockRelationsStruct struct { + baseBlockRelations *BlockRelations + blockRelationsToCompareTo []testBlockRelationsToCompare +} + +func initTestBlockRelationsForEqual() []testBlockRelationsStruct { + + var testBlockRelationsBase = BlockRelations{ + []*externalapi.DomainHash{{1}, {2}}, + []*externalapi.DomainHash{{3}, {4}}, + } + //First test: structs are equal + var testBlockRelations1 = BlockRelations{ + []*externalapi.DomainHash{{1}, {2}}, + []*externalapi.DomainHash{{3}, {4}}, + } + //Second test: children changed + var testBlockRelations2 = BlockRelations{ + []*externalapi.DomainHash{{1}, {2}}, + []*externalapi.DomainHash{{3}, {5}}, + } + //Third test: parents changed + var testBlockRelations3 = BlockRelations{ + []*externalapi.DomainHash{{6}, {2}}, + []*externalapi.DomainHash{{3}, {4}}, + } + + tests := []testBlockRelationsStruct{ + { + baseBlockRelations: &testBlockRelationsBase, + blockRelationsToCompareTo: []testBlockRelationsToCompare{ + { + blockRelations: &testBlockRelations1, + expectedResult: true, + }, { + blockRelations: &testBlockRelations2, + expectedResult: false, + }, { + blockRelations: &testBlockRelations3, + expectedResult: false, + }, { + blockRelations: nil, + expectedResult: false, + }, + }, + }, { + baseBlockRelations: nil, + blockRelationsToCompareTo: []testBlockRelationsToCompare{ + { + blockRelations: &testBlockRelations1, + expectedResult: false, + }, { + blockRelations: nil, + expectedResult: true, + }, + }, + }, + } + return tests +} + +func TestBlockRelationsData_Equal(t *testing.T) { + + blockRelationss := initTestBlockRelationsForEqual() + for i, test := range blockRelationss { + for j, subTest := range test.blockRelationsToCompareTo { + result1 := test.baseBlockRelations.Equal(subTest.blockRelations) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.blockRelations.Equal(test.baseBlockRelations) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestBlockRelations_Clone(t *testing.T) { + + testBlockRelations := initTestBlockRelationsForClone() + for i, blockRelations := range testBlockRelations { + blockRelationsClone := blockRelations.Clone() + if !blockRelationsClone.Equal(blockRelations) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(blockRelations, blockRelationsClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/acceptancedata.go b/domain/consensus/model/externalapi/acceptancedata.go index b3bde56b0..1cb4ae965 100644 --- a/domain/consensus/model/externalapi/acceptancedata.go +++ b/domain/consensus/model/externalapi/acceptancedata.go @@ -4,11 +4,27 @@ package externalapi // It's ordered in the same way as the block merge set blues. type AcceptanceData []*BlockAcceptanceData +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ AcceptanceData = []*BlockAcceptanceData{} + +// Equal returns whether ad equals to other +func (ad AcceptanceData) Equal(other AcceptanceData) bool { + if len(ad) != len(other) { + return false + } + + for i, blockAcceptanceData := range ad { + if !blockAcceptanceData.Equal(other[i]) { + return false + } + } + + return true +} + // Clone clones the AcceptanceData func (ad AcceptanceData) Clone() AcceptanceData { - if ad == nil { - return nil - } clone := make(AcceptanceData, len(ad)) for i, blockAcceptanceData := range ad { clone[i] = blockAcceptanceData.Clone() @@ -24,6 +40,33 @@ type BlockAcceptanceData struct { TransactionAcceptanceData []*TransactionAcceptanceData } +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &BlockAcceptanceData{&DomainHash{}, []*TransactionAcceptanceData{}} + +// Equal returns whether bad equals to other +func (bad *BlockAcceptanceData) Equal(other *BlockAcceptanceData) bool { + if bad == nil || other == nil { + return bad == other + } + + if !bad.BlockHash.Equal(other.BlockHash) { + return false + } + + if len(bad.TransactionAcceptanceData) != len(other.TransactionAcceptanceData) { + return false + } + + for i, acceptanceData := range bad.TransactionAcceptanceData { + if !acceptanceData.Equal(other.TransactionAcceptanceData[i]) { + return false + } + } + + return true +} + // Clone returns a clone of BlockAcceptanceData func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData { if bad == nil { @@ -49,12 +92,33 @@ type TransactionAcceptanceData struct { IsAccepted bool } -// Clone returns a clone of TransactionAcceptanceData -func (tad *TransactionAcceptanceData) Clone() *TransactionAcceptanceData { - if tad == nil { - return nil +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &TransactionAcceptanceData{&DomainTransaction{}, 0, false} + +// Equal returns whether tad equals to other +func (tad *TransactionAcceptanceData) Equal(other *TransactionAcceptanceData) bool { + if tad == nil || other == nil { + return tad == other } + if !tad.Transaction.Equal(other.Transaction) { + return false + } + + if tad.Fee != other.Fee { + return false + } + + if tad.IsAccepted != other.IsAccepted { + return false + } + + return true +} + +// Clone returns a clone of TransactionAcceptanceData +func (tad *TransactionAcceptanceData) Clone() *TransactionAcceptanceData { return &TransactionAcceptanceData{ Transaction: tad.Transaction.Clone(), Fee: tad.Fee, diff --git a/domain/consensus/model/externalapi/block.go b/domain/consensus/model/externalapi/block.go index da4990620..07d0d5cbb 100644 --- a/domain/consensus/model/externalapi/block.go +++ b/domain/consensus/model/externalapi/block.go @@ -8,10 +8,6 @@ type DomainBlock struct { // Clone returns a clone of DomainBlock func (block *DomainBlock) Clone() *DomainBlock { - if block == nil { - return nil - } - transactionClone := make([]*DomainTransaction, len(block.Transactions)) for i, tx := range block.Transactions { transactionClone[i] = tx.Clone() @@ -23,6 +19,33 @@ func (block *DomainBlock) Clone() *DomainBlock { } } +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = DomainBlock{&DomainBlockHeader{}, []*DomainTransaction{}} + +// Equal returns whether block equals to other +func (block *DomainBlock) Equal(other *DomainBlock) bool { + if block == nil || other == nil { + return block == other + } + + if len(block.Transactions) != len(other.Transactions) { + return false + } + + if !block.Header.Equal(other.Header) { + return false + } + + for i, tx := range block.Transactions { + if !tx.Equal(other.Transactions[i]) { + return false + } + } + + return true +} + // DomainBlockHeader represents the header part of a Kaspa block type DomainBlockHeader struct { Version int32 @@ -37,10 +60,6 @@ type DomainBlockHeader struct { // Clone returns a clone of DomainBlockHeader func (header *DomainBlockHeader) Clone() *DomainBlockHeader { - if header == nil { - return nil - } - return &DomainBlockHeader{ Version: header.Version, ParentHashes: CloneHashes(header.ParentHashes), @@ -52,3 +71,49 @@ func (header *DomainBlockHeader) Clone() *DomainBlockHeader { Nonce: header.Nonce, } } + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &DomainBlockHeader{0, []*DomainHash{}, DomainHash{}, + DomainHash{}, DomainHash{}, 0, 0, 0} + +// Equal returns whether header equals to other +func (header *DomainBlockHeader) Equal(other *DomainBlockHeader) bool { + if header == nil || other == nil { + return header == other + } + + if header.Version != other.Version { + return false + } + + if !HashesEqual(header.ParentHashes, other.ParentHashes) { + return false + } + + if !header.HashMerkleRoot.Equal(&other.HashMerkleRoot) { + return false + } + + if !header.AcceptedIDMerkleRoot.Equal(&other.AcceptedIDMerkleRoot) { + return false + } + + if !header.UTXOCommitment.Equal(&other.UTXOCommitment) { + return false + } + + if header.TimeInMilliseconds != other.TimeInMilliseconds { + return false + } + + if header.Bits != other.Bits { + return false + } + + if header.Nonce != other.Nonce { + return false + } + + return true +} diff --git a/domain/consensus/model/externalapi/block_equal_clone_test.go b/domain/consensus/model/externalapi/block_equal_clone_test.go new file mode 100644 index 000000000..9a032d847 --- /dev/null +++ b/domain/consensus/model/externalapi/block_equal_clone_test.go @@ -0,0 +1,375 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +type blockToCompare struct { + block *DomainBlock + expectedResult bool +} + +type TestBlockStruct struct { + baseBlock *DomainBlock + blocksToCompareTo []blockToCompare +} + +func initTestBaseTransactions() []*DomainTransaction { + + testTx := []*DomainTransaction{{ + Version: 1, + Inputs: []*DomainTransactionInput{}, + Outputs: []*DomainTransactionOutput{}, + LockTime: 1, + SubnetworkID: DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }} + return testTx +} + +func initTestAnotherTransactions() []*DomainTransaction { + + testTx := []*DomainTransaction{{ + Version: 1, + Inputs: []*DomainTransactionInput{}, + Outputs: []*DomainTransactionOutput{}, + LockTime: 1, + SubnetworkID: DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + }} + return testTx +} + +func initTestTwoTransactions() []*DomainTransaction { + + testTx := []*DomainTransaction{{ + Version: 1, + Inputs: []*DomainTransactionInput{}, + Outputs: []*DomainTransactionOutput{}, + LockTime: 1, + SubnetworkID: DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + }, { + Version: 1, + Inputs: []*DomainTransactionInput{}, + Outputs: []*DomainTransactionOutput{}, + LockTime: 1, + SubnetworkID: DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + }} + return testTx +} + +func initTestBlockStructsForClone() []*DomainBlock { + + tests := []*DomainBlock{ + { + &DomainBlockHeader{ + + 0, + []*DomainHash{{0}}, + DomainHash{1}, + DomainHash{2}, + DomainHash{3}, + 4, + 5, + 6, + }, + initTestBaseTransactions(), + }, { + &DomainBlockHeader{ + + 0, + []*DomainHash{}, + DomainHash{1}, + DomainHash{2}, + DomainHash{3}, + 4, + 5, + 6, + }, + initTestBaseTransactions(), + }, + } + + return tests +} + +func initTestBlockStructsForEqual() *[]TestBlockStruct { + tests := []TestBlockStruct{ + { + baseBlock: nil, + blocksToCompareTo: []blockToCompare{ + { + block: nil, + expectedResult: true, + }, + { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{0}}, + DomainHash{1}, + DomainHash{2}, + DomainHash{3}, + 4, + 5, + 6, + }, + initTestBaseTransactions()}, + expectedResult: false, + }, + }, + }, { + baseBlock: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + initTestBaseTransactions(), + }, + blocksToCompareTo: []blockToCompare{ + { + block: nil, + expectedResult: false, + }, + { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + initTestAnotherTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: true, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}, {2}}, // Changed + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{100}}, // Changed + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + initTestTwoTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{100}, // Changed + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{100}, // Changed + DomainHash{4}, + 5, + 6, + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{100}, // Changed + 5, + 6, + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 100, // Changed + 6, + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 100, // Changed + 7, + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, { + block: &DomainBlock{ + &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 100, // Changed + }, + initTestBaseTransactions(), + }, + expectedResult: false, + }, + }, + }, + } + + return &tests +} + +func TestDomainBlock_Equal(t *testing.T) { + + blockTests := initTestBlockStructsForEqual() + for i, test := range *blockTests { + for j, subTest := range test.blocksToCompareTo { + result1 := test.baseBlock.Equal(subTest.block) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.block.Equal(test.baseBlock) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } + +} + +func TestDomainBlock_Clone(t *testing.T) { + + blocks := initTestBlockStructsForClone() + for i, block := range blocks { + blockClone := block.Clone() + if !blockClone.Equal(block) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(block, blockClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/blockinfo.go b/domain/consensus/model/externalapi/blockinfo.go index dcd7128de..72cd0d8f9 100644 --- a/domain/consensus/model/externalapi/blockinfo.go +++ b/domain/consensus/model/externalapi/blockinfo.go @@ -6,3 +6,12 @@ type BlockInfo struct { BlockStatus BlockStatus BlueScore uint64 } + +// Clone returns a clone of BlockInfo +func (bi *BlockInfo) Clone() *BlockInfo { + return &BlockInfo{ + Exists: bi.Exists, + BlockStatus: bi.BlockStatus.Clone(), + BlueScore: bi.BlueScore, + } +} diff --git a/domain/consensus/model/externalapi/blockinfo_clone_test.go b/domain/consensus/model/externalapi/blockinfo_clone_test.go new file mode 100644 index 000000000..2ff7c2699 --- /dev/null +++ b/domain/consensus/model/externalapi/blockinfo_clone_test.go @@ -0,0 +1,45 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestBlockInfoStructsForClone() []*BlockInfo { + + tests := []*BlockInfo{ + { + true, + BlockStatus(0x01), + 0, + }, { + true, + BlockStatus(0x02), + 0, + }, { + true, + 1, + 1, + }, { + true, + 255, + 2, + }, { + true, + 0, + 3, + }, + } + return tests +} + +func TestBlockInfo_Clone(t *testing.T) { + + blockInfos := initTestBlockInfoStructsForClone() + for i, blockInfo := range blockInfos { + blockInfoClone := blockInfo.Clone() + if !reflect.DeepEqual(blockInfo, blockInfoClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/blocklocator.go b/domain/consensus/model/externalapi/blocklocator.go index 92503d6a4..a730a4df5 100644 --- a/domain/consensus/model/externalapi/blocklocator.go +++ b/domain/consensus/model/externalapi/blocklocator.go @@ -15,3 +15,8 @@ package externalapi // The block locator for block 17 would be the hashes of blocks: // [17 16 14 11 7 2 genesis] type BlockLocator []*DomainHash + +// Clone returns a clone of BlockLocator +func (locator BlockLocator) Clone() BlockLocator { + return CloneHashes(locator) +} diff --git a/domain/consensus/model/externalapi/blocklocator_clone_test.go b/domain/consensus/model/externalapi/blocklocator_clone_test.go new file mode 100644 index 000000000..149a51b2a --- /dev/null +++ b/domain/consensus/model/externalapi/blocklocator_clone_test.go @@ -0,0 +1,67 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestBlockLocatorForClone() []*BlockLocator { + + tests := []*BlockLocator{{ + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + }, { + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1}, + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1, 1}, + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2, 1}, + }, + } + return tests +} + +func TestBlockLocator_Clone(t *testing.T) { + + testBlockLocator := initTestBlockLocatorForClone() + for i, blockLocator := range testBlockLocator { + blockLocatorClone := blockLocator.Clone() + if !reflect.DeepEqual(blockLocator, &blockLocatorClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/blockstatus.go b/domain/consensus/model/externalapi/blockstatus.go index 2c2fd408a..7358bafdd 100644 --- a/domain/consensus/model/externalapi/blockstatus.go +++ b/domain/consensus/model/externalapi/blockstatus.go @@ -8,6 +8,15 @@ func (bs BlockStatus) Clone() BlockStatus { return bs } +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ BlockStatus = 0 + +// Equal returns whether bs equals to other +func (bs BlockStatus) Equal(other BlockStatus) bool { + return bs == other +} + const ( // StatusInvalid indicates that the block is invalid. StatusInvalid BlockStatus = iota diff --git a/domain/consensus/model/externalapi/blockstatus_equal_clone_test.go b/domain/consensus/model/externalapi/blockstatus_equal_clone_test.go new file mode 100644 index 000000000..7737296c1 --- /dev/null +++ b/domain/consensus/model/externalapi/blockstatus_equal_clone_test.go @@ -0,0 +1,87 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestBlockStatusForClone() []BlockStatus { + + tests := []BlockStatus{1, 2, 0xFF, 0} + + return tests +} + +type TestBlockStatusToCompare struct { + blockStatus BlockStatus + expectedResult bool +} + +type TestBlockStatusStruct struct { + baseBlockStatus BlockStatus + blockStatusesToCompareTo []TestBlockStatusToCompare +} + +func initTestBlockStatusForEqual() []TestBlockStatusStruct { + tests := []TestBlockStatusStruct{ + { + baseBlockStatus: 0, + blockStatusesToCompareTo: []TestBlockStatusToCompare{ + { + blockStatus: 1, + expectedResult: false, + }, + { + blockStatus: 0, + expectedResult: true, + }, + }, + }, { + baseBlockStatus: 255, + blockStatusesToCompareTo: []TestBlockStatusToCompare{ + { + blockStatus: 1, + expectedResult: false, + }, + { + blockStatus: 255, + expectedResult: true, + }, + }, + }, + } + return tests +} + +func TestBlockStatus_Equal(t *testing.T) { + + testBlockStatus := initTestBlockStatusForEqual() + + for i, test := range testBlockStatus { + for j, subTest := range test.blockStatusesToCompareTo { + result1 := test.baseBlockStatus.Equal(subTest.blockStatus) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + + result2 := subTest.blockStatus.Equal(test.baseBlockStatus) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestBlockStatus_Clone(t *testing.T) { + + testBlockStatus := initTestBlockStatusForClone() + for i, blockStatus := range testBlockStatus { + blockStatusClone := blockStatus.Clone() + if !blockStatusClone.Equal(blockStatus) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(blockStatus, blockStatusClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/coinbase.go b/domain/consensus/model/externalapi/coinbase.go index a0ce7fead..5770ed48a 100644 --- a/domain/consensus/model/externalapi/coinbase.go +++ b/domain/consensus/model/externalapi/coinbase.go @@ -6,3 +6,17 @@ type DomainCoinbaseData struct { ScriptPublicKey []byte ExtraData []byte } + +// Clone returns a clone of DomainCoinbaseData +func (dcd *DomainCoinbaseData) Clone() *DomainCoinbaseData { + scriptPubKeyClone := make([]byte, len(dcd.ScriptPublicKey)) + copy(scriptPubKeyClone, dcd.ScriptPublicKey) + + extraDataClone := make([]byte, len(dcd.ExtraData)) + copy(extraDataClone, dcd.ExtraData) + + return &DomainCoinbaseData{ + ScriptPublicKey: scriptPubKeyClone, + ExtraData: extraDataClone, + } +} diff --git a/domain/consensus/model/externalapi/coinbase_clone_test.go b/domain/consensus/model/externalapi/coinbase_clone_test.go new file mode 100644 index 000000000..b7c29bbc7 --- /dev/null +++ b/domain/consensus/model/externalapi/coinbase_clone_test.go @@ -0,0 +1,59 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestCoinbaseDataStructsForClone() []*DomainCoinbaseData { + + tests := []*DomainCoinbaseData{ + { + []byte{1, 2, 3, 4, 5, 6}, + []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }, { + []byte{0, 0, 0, 0, 55}, + []byte{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, 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, 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, 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, + 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF}, + }, + } + return tests +} + +func TestDomainCoinbaseData_Clone(t *testing.T) { + + coinbaseData := initTestCoinbaseDataStructsForClone() + for i, coinbase := range coinbaseData { + coinbaseClone := coinbase.Clone() + if !reflect.DeepEqual(coinbase, coinbaseClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/equal_test.go b/domain/consensus/model/externalapi/equal_test.go new file mode 100644 index 000000000..4ccd24508 --- /dev/null +++ b/domain/consensus/model/externalapi/equal_test.go @@ -0,0 +1,238 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func TestDomainBlockHeader_Equal(t *testing.T) { + type headerToCompare struct { + header *DomainBlockHeader + expectedResult bool + } + tests := []struct { + baseHeader *DomainBlockHeader + headersToCompareTo []headerToCompare + }{ + { + baseHeader: nil, + headersToCompareTo: []headerToCompare{ + { + header: nil, + expectedResult: true, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{0}}, + DomainHash{1}, + DomainHash{2}, + DomainHash{3}, + 4, + 5, + 6, + }, + expectedResult: false, + }, + }, + }, + { + baseHeader: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + headersToCompareTo: []headerToCompare{ + { + header: nil, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + expectedResult: true, + }, + { + header: &DomainBlockHeader{ + 100, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}, {2}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{100}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{100}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{100}, + DomainHash{4}, + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{100}, + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 100, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 100, + 7, + }, + expectedResult: false, + }, + { + header: &DomainBlockHeader{ + 0, + []*DomainHash{{1}}, + DomainHash{2}, + DomainHash{3}, + DomainHash{4}, + 5, + 6, + 100, + }, + expectedResult: false, + }, + }, + }, + } + + for i, test := range tests { + for j, subTest := range test.headersToCompareTo { + result1 := test.baseHeader.Equal(subTest.header) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + + result2 := subTest.header.Equal(test.baseHeader) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainBlockHeader_Clone(t *testing.T) { + headers := []*DomainBlockHeader{ + { + 0, + []*DomainHash{{0}}, + DomainHash{1}, + DomainHash{2}, + DomainHash{3}, + 4, + 5, + 6, + }, + { + 0, + []*DomainHash{}, + DomainHash{1}, + DomainHash{2}, + DomainHash{3}, + 4, + 5, + 6, + }, + } + + for i, header := range headers { + clone := header.Clone() + if !clone.Equal(header) { + t.Fatalf("Test #%d: clone should be equal to the original", i) + } + + if !reflect.DeepEqual(header, clone) { + t.Fatalf("Test #%d: clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index 40446d6d1..e7080e1bc 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -19,14 +19,37 @@ func (hash DomainHash) String() string { // Clone clones the hash func (hash *DomainHash) Clone() *DomainHash { - if hash == nil { - return nil - } - hashClone := *hash return &hashClone } +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ DomainHash = [DomainHashSize]byte{} + +// Equal returns whether hash equals to other +func (hash *DomainHash) Equal(other *DomainHash) bool { + if hash == nil || other == nil { + return hash == other + } + + return *hash == *other +} + +// HashesEqual returns whether the given hash slices are equal. +func HashesEqual(a, b []*DomainHash) bool { + if len(a) != len(b) { + return false + } + + for i, hash := range a { + if !hash.Equal(b[i]) { + return false + } + } + return true +} + // CloneHashes returns a clone of the given hashes slice func CloneHashes(hashes []*DomainHash) []*DomainHash { clone := make([]*DomainHash, len(hashes)) diff --git a/domain/consensus/model/externalapi/hash_clone_equal_test.go b/domain/consensus/model/externalapi/hash_clone_equal_test.go new file mode 100644 index 000000000..89e2c844e --- /dev/null +++ b/domain/consensus/model/externalapi/hash_clone_equal_test.go @@ -0,0 +1,119 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestDomainHashForClone() []*DomainHash { + + tests := []*DomainHash{ + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + } + return tests +} + +type testHashToCompare struct { + hash *DomainHash + expectedResult bool +} + +type testHashStruct struct { + baseHash *DomainHash + hashesToCompareTo []testHashToCompare +} + +func initTestDomainHashForEqual() []*testHashStruct { + tests := []*testHashStruct{ + { + baseHash: nil, + hashesToCompareTo: []testHashToCompare{ + { + hash: nil, + expectedResult: true, + }, { + hash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + expectedResult: false, + }, + }, + }, { + baseHash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + hashesToCompareTo: []testHashToCompare{ + { + hash: nil, + expectedResult: false, + }, { + hash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + expectedResult: false, + }, { + hash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + expectedResult: true, + }, + }, + }, + } + return tests +} + +func TestDomainHash_Equal(t *testing.T) { + + hashTests := initTestDomainHashForEqual() + for i, test := range hashTests { + for j, subTest := range test.hashesToCompareTo { + result1 := test.baseHash.Equal(subTest.hash) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.hash.Equal(test.baseHash) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainHash_Clone(t *testing.T) { + + hashes := initTestDomainHashForClone() + for i, hash := range hashes { + hashClone := hash.Clone() + if !hashClone.Equal(hash) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(hash, hashClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/subnetworkid.go b/domain/consensus/model/externalapi/subnetworkid.go index 8a948dff0..16f978eaa 100644 --- a/domain/consensus/model/externalapi/subnetworkid.go +++ b/domain/consensus/model/externalapi/subnetworkid.go @@ -18,10 +18,19 @@ func (id DomainSubnetworkID) String() string { // Clone returns a clone of DomainSubnetworkID func (id *DomainSubnetworkID) Clone() *DomainSubnetworkID { - if id == nil { - return nil - } - idClone := *id return &idClone } + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ DomainSubnetworkID = [DomainSubnetworkIDSize]byte{} + +// Equal returns whether id equals to other +func (id *DomainSubnetworkID) Equal(other *DomainSubnetworkID) bool { + if id == nil || other == nil { + return id == other + } + + return *id == *other +} diff --git a/domain/consensus/model/externalapi/subnetworkid_clone_equal_test.go b/domain/consensus/model/externalapi/subnetworkid_clone_equal_test.go new file mode 100644 index 000000000..dc6d7c5f0 --- /dev/null +++ b/domain/consensus/model/externalapi/subnetworkid_clone_equal_test.go @@ -0,0 +1,99 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestDomainSubnetworkIDForClone() []*DomainSubnetworkID { + + tests := []*DomainSubnetworkID{{1, 0, 0xFF, 0}, {0, 1, 0xFF, 1}, + {0, 1, 0xFF, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}} + return tests +} + +type testDomainSubnetworkIDToCompare struct { + domainSubnetworkID *DomainSubnetworkID + expectedResult bool +} + +type testDomainSubnetworkIDStruct struct { + baseDomainSubnetworkID *DomainSubnetworkID + domainSubnetworkIDToCompareTo []testDomainSubnetworkIDToCompare +} + +func initTestDomainSubnetworkIDForEqual() []testDomainSubnetworkIDStruct { + tests := []testDomainSubnetworkIDStruct{ + { + baseDomainSubnetworkID: nil, + domainSubnetworkIDToCompareTo: []testDomainSubnetworkIDToCompare{ + { + domainSubnetworkID: &DomainSubnetworkID{255, 255, 0xFF, 0}, + expectedResult: false, + }, + { + domainSubnetworkID: nil, + expectedResult: true, + }, + }, + }, { + baseDomainSubnetworkID: &DomainSubnetworkID{0}, + domainSubnetworkIDToCompareTo: []testDomainSubnetworkIDToCompare{ + { + domainSubnetworkID: &DomainSubnetworkID{255, 254, 0xFF, 0}, + expectedResult: false, + }, + { + domainSubnetworkID: &DomainSubnetworkID{0}, + expectedResult: true, + }, + }, + }, { + baseDomainSubnetworkID: &DomainSubnetworkID{0, 1, 0xFF, 1, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + domainSubnetworkIDToCompareTo: []testDomainSubnetworkIDToCompare{ + { + domainSubnetworkID: &DomainSubnetworkID{0, 1, 0xFF, 1, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + expectedResult: true, + }, + { + domainSubnetworkID: &DomainSubnetworkID{0, 10, 0xFF, 0}, + expectedResult: false, + }, + }, + }, + } + return tests +} + +func TestDomainSubnetworkID_Equal(t *testing.T) { + + domainSubnetworkIDs := initTestDomainSubnetworkIDForEqual() + for i, test := range domainSubnetworkIDs { + for j, subTest := range test.domainSubnetworkIDToCompareTo { + result1 := test.baseDomainSubnetworkID.Equal(subTest.domainSubnetworkID) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.domainSubnetworkID.Equal(test.baseDomainSubnetworkID) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainSubnetworkID_Clone(t *testing.T) { + + domainSubnetworkIDs := initTestDomainSubnetworkIDForClone() + for i, domainSubnetworkID := range domainSubnetworkIDs { + domainSubnetworkIDClone := domainSubnetworkID.Clone() + if !domainSubnetworkIDClone.Equal(domainSubnetworkID) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(domainSubnetworkID, domainSubnetworkIDClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index d5f11a499..d1b717857 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -7,3 +7,42 @@ type SyncInfo struct { HeaderCount uint64 BlockCount uint64 } + +// Clone returns a clone of SyncInfo +func (si *SyncInfo) Clone() *SyncInfo { + return &SyncInfo{ + IsAwaitingUTXOSet: si.IsAwaitingUTXOSet, + IBDRootUTXOBlockHash: si.IBDRootUTXOBlockHash.Clone(), + HeaderCount: si.HeaderCount, + BlockCount: si.BlockCount, + } +} + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = SyncInfo{false, &DomainHash{}, 0, 0} + +// Equal returns whether si equals to other +func (si *SyncInfo) Equal(other *SyncInfo) bool { + if si == nil || other == nil { + return si == other + } + + if si.IsAwaitingUTXOSet != other.IsAwaitingUTXOSet { + return false + } + + if !si.IBDRootUTXOBlockHash.Equal(other.IBDRootUTXOBlockHash) { + return false + } + + if si.HeaderCount != other.HeaderCount { + return false + } + + if si.BlockCount != other.BlockCount { + return false + } + + return true +} diff --git a/domain/consensus/model/externalapi/sync_equal_clone_test.go b/domain/consensus/model/externalapi/sync_equal_clone_test.go new file mode 100644 index 000000000..4a216c564 --- /dev/null +++ b/domain/consensus/model/externalapi/sync_equal_clone_test.go @@ -0,0 +1,126 @@ +package externalapi + +import ( + "reflect" + "testing" +) + +func initTestSyncInfoForClone() []*SyncInfo { + + tests := []*SyncInfo{{ + false, + &DomainHash{1, 2}, + 0xF, + 0xF}} + return tests +} + +type testSyncInfoToCompare struct { + syncInfo *SyncInfo + expectedResult bool +} + +type testSyncInfoStruct struct { + baseSyncInfo *SyncInfo + syncInfoToCompareTo []testSyncInfoToCompare +} + +func initTestSyncInfoForEqual() []*testSyncInfoStruct { + tests := []*testSyncInfoStruct{ + { + baseSyncInfo: nil, + syncInfoToCompareTo: []testSyncInfoToCompare{ + { + syncInfo: &SyncInfo{ + false, + &DomainHash{1, 2}, + 0xF, + 0xF}, + expectedResult: false, + }, { + syncInfo: nil, + expectedResult: true, + }, + }}, { + baseSyncInfo: &SyncInfo{ + false, + &DomainHash{1, 2}, + 0xF, + 0xF}, + syncInfoToCompareTo: []testSyncInfoToCompare{ + { + syncInfo: &SyncInfo{ + false, + &DomainHash{1, 2}, + 0xF, + 0xF}, + expectedResult: true, + }, { + syncInfo: &SyncInfo{ + true, + &DomainHash{1, 2}, + 0xF, + 0xF}, + expectedResult: false, + }, + { + syncInfo: &SyncInfo{ + false, + &DomainHash{1, 3}, + 0xF, + 0xF}, + expectedResult: false, + }, + { + syncInfo: &SyncInfo{ + false, + &DomainHash{1, 2}, + 0xF1, + 0xF}, + expectedResult: false, + }, { + syncInfo: nil, + expectedResult: false, + }, { + syncInfo: &SyncInfo{ + false, + &DomainHash{1, 2}, + 0xF, + 0xF1}, + expectedResult: false}, + }, + }, + } + return tests +} + +func TestSyncInfo_Equal(t *testing.T) { + + testSyncState := initTestSyncInfoForEqual() + for i, test := range testSyncState { + for j, subTest := range test.syncInfoToCompareTo { + result1 := test.baseSyncInfo.Equal(subTest.syncInfo) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.syncInfo.Equal(test.baseSyncInfo) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestSyncInfo_Clone(t *testing.T) { + + testSyncInfo := initTestSyncInfoForClone() + for i, syncInfo := range testSyncInfo { + syncStateClone := syncInfo.Clone() + if !syncStateClone.Equal(syncInfo) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(syncInfo, syncStateClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 0ffdf0e48..d0410e9f3 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -1,7 +1,9 @@ package externalapi import ( + "bytes" "fmt" + "github.com/pkg/errors" ) // DomainTransaction represents a Kaspa transaction @@ -25,10 +27,6 @@ type DomainTransaction struct { // Clone returns a clone of DomainTransaction func (tx *DomainTransaction) Clone() *DomainTransaction { - if tx == nil { - return nil - } - payloadClone := make([]byte, len(tx.Payload)) copy(payloadClone, tx.Payload) @@ -42,6 +40,11 @@ func (tx *DomainTransaction) Clone() *DomainTransaction { outputsClone[i] = output.Clone() } + var idClone *DomainTransactionID + if tx.ID != nil { + idClone = tx.ID.Clone() + } + return &DomainTransaction{ Version: tx.Version, Inputs: inputsClone, @@ -53,9 +56,81 @@ func (tx *DomainTransaction) Clone() *DomainTransaction { Payload: payloadClone, Fee: tx.Fee, Mass: tx.Mass, + ID: idClone, } } +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = DomainTransaction{0, []*DomainTransactionInput{}, []*DomainTransactionOutput{}, 0, + DomainSubnetworkID{}, 0, DomainHash{}, []byte{}, 0, 0, + &DomainTransactionID{}} + +// Equal returns whether tx equals to other +func (tx *DomainTransaction) Equal(other *DomainTransaction) bool { + if tx == nil || other == nil { + return tx == other + } + + if tx.Version != other.Version { + return false + } + + if len(tx.Inputs) != len(other.Inputs) { + return false + } + + for i, input := range tx.Inputs { + if !input.Equal(other.Inputs[i]) { + return false + } + } + + if len(tx.Outputs) != len(other.Outputs) { + return false + } + + for i, output := range tx.Outputs { + if !output.Equal(other.Outputs[i]) { + return false + } + } + + if tx.LockTime != other.LockTime { + return false + } + + if !tx.SubnetworkID.Equal(&other.SubnetworkID) { + return false + } + + if tx.Gas != other.Gas { + return false + } + + if !tx.PayloadHash.Equal(&other.PayloadHash) { + return false + } + + if !bytes.Equal(tx.Payload, other.Payload) { + return false + } + + if tx.Fee != other.Fee { + return false + } + + if tx.Mass != other.Mass { + return false + } + + if tx.ID != nil && other.ID != nil && !tx.ID.Equal(other.ID) { + panic(errors.New("identical transactions should always have the same ID")) + } + + return true +} + // DomainTransactionInput represents a Kaspa transaction input type DomainTransactionInput struct { PreviousOutpoint DomainOutpoint @@ -65,12 +140,37 @@ type DomainTransactionInput struct { UTXOEntry UTXOEntry } -// Clone returns a clone of DomainTransactionInput -func (input *DomainTransactionInput) Clone() *DomainTransactionInput { - if input == nil { - return nil +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &DomainTransactionInput{DomainOutpoint{}, []byte{}, 0, nil} + +// Equal returns whether input equals to other +func (input *DomainTransactionInput) Equal(other *DomainTransactionInput) bool { + if input == nil || other == nil { + return input == other } + if !input.PreviousOutpoint.Equal(&other.PreviousOutpoint) { + return false + } + + if !bytes.Equal(input.SignatureScript, other.SignatureScript) { + return false + } + + if input.Sequence != other.Sequence { + return false + } + + if !input.UTXOEntry.Equal(other.UTXOEntry) { + return false + } + + return true +} + +// Clone returns a clone of DomainTransactionInput +func (input *DomainTransactionInput) Clone() *DomainTransactionInput { signatureScriptClone := make([]byte, len(input.SignatureScript)) copy(signatureScriptClone, input.SignatureScript) @@ -88,12 +188,21 @@ type DomainOutpoint struct { Index uint32 } -// Clone returns a clone of DomainOutpoint -func (op *DomainOutpoint) Clone() *DomainOutpoint { - if op == nil { - return nil +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = DomainOutpoint{DomainTransactionID{}, 0} + +// Equal returns whether op equals to other +func (op *DomainOutpoint) Equal(other *DomainOutpoint) bool { + if op == nil || other == nil { + return op == other } + return *op == *other +} + +// Clone returns a clone of DomainOutpoint +func (op *DomainOutpoint) Clone() *DomainOutpoint { return &DomainOutpoint{ TransactionID: *op.TransactionID.Clone(), Index: op.Index, @@ -119,12 +228,29 @@ type DomainTransactionOutput struct { ScriptPublicKey []byte } -// Clone returns a clone of DomainTransactionOutput -func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput { - if output == nil { - return nil +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = DomainTransactionOutput{0, []byte{}} + +// Equal returns whether output equals to other +func (output *DomainTransactionOutput) Equal(other *DomainTransactionOutput) bool { + if output == nil || other == nil { + return output == other } + if output.Value != other.Value { + return false + } + + if !bytes.Equal(output.ScriptPublicKey, other.ScriptPublicKey) { + return false + } + + return true +} + +// Clone returns a clone of DomainTransactionOutput +func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput { scriptPublicKeyClone := make([]byte, len(output.ScriptPublicKey)) copy(scriptPublicKeyClone, output.ScriptPublicKey) @@ -144,10 +270,19 @@ func (id DomainTransactionID) String() string { // Clone returns a clone of DomainTransactionID func (id *DomainTransactionID) Clone() *DomainTransactionID { - if id == nil { - return nil - } - idClone := *id return &idClone } + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ DomainTransactionID = [DomainHashSize]byte{} + +// Equal returns whether id equals to other +func (id *DomainTransactionID) Equal(other *DomainTransactionID) bool { + if id == nil || other == nil { + return id == other + } + + return *id == *other +} diff --git a/domain/consensus/model/externalapi/transaction_equal_clone_test.go b/domain/consensus/model/externalapi/transaction_equal_clone_test.go new file mode 100644 index 000000000..9a6c6e7b8 --- /dev/null +++ b/domain/consensus/model/externalapi/transaction_equal_clone_test.go @@ -0,0 +1,1133 @@ +package externalapi_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "reflect" + "testing" +) + +// Changed fields of a test struct compared to a base test struct marked as "changed" and +// pointing in some cases name changed struct field + +type transactionToCompare struct { + tx *externalapi.DomainTransaction + expectedResult bool + expectsPanic bool +} + +type testDomainTransactionStruct struct { + baseTx *externalapi.DomainTransaction + transactionToCompareTo []*transactionToCompare +} + +type transactionInputToCompare struct { + tx *externalapi.DomainTransactionInput + expectedResult bool +} + +type testDomainTransactionInputStruct struct { + baseTx *externalapi.DomainTransactionInput + transactionInputToCompareTo []*transactionInputToCompare +} + +type transactionOutputToCompare struct { + tx *externalapi.DomainTransactionOutput + expectedResult bool +} + +type testDomainTransactionOutputStruct struct { + baseTx *externalapi.DomainTransactionOutput + transactionOutputToCompareTo []*transactionOutputToCompare +} + +type domainOutpointToCompare struct { + domainOutpoint *externalapi.DomainOutpoint + expectedResult bool +} + +type testDomainOutpointStruct struct { + baseDomainOutpoint *externalapi.DomainOutpoint + domainOutpointToCompareTo []*domainOutpointToCompare +} + +type domainTransactionIDToCompare struct { + domainTransactionID *externalapi.DomainTransactionID + expectedResult bool +} + +type testDomainTransactionIDStruct struct { + baseDomainTransactionID *externalapi.DomainTransactionID + domainTransactionIDToCompareTo []*domainTransactionIDToCompare +} + +func initTestBaseTransaction() *externalapi.DomainTransaction { + + testTx := &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + } + return testTx +} + +func initTestTransactionToCompare() []*transactionToCompare { + + testTx := []*transactionToCompare{{ + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, //Changed + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 3}}, //Changed + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01, 0x02}, //Changed + 1, + externalapi.DomainHash{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01, 0x02}, //Changed + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: true, + }, + { + // ID changed + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + }, + expectsPanic: true, + }, + { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 1000000000, //Changed + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 2, //Changed + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, //6 + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 2, //Changed + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + }, //7 + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 2, //Changed + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + {externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}, {uint64(0xFFFFF), + []byte{1, 2, 3}}}, //changed Outputs + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + nil, //changed + }, + expectedResult: true, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3, 4}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, + } + return testTx +} + +func initTestDomainTransactionForClone() []*externalapi.DomainTransaction { + + tests := []*externalapi.DomainTransaction{ + { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{ + {externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + }, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + Payload: []byte{0x01}, + Fee: 5555555555, + Mass: 1, + ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, { + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{}, + Outputs: []*externalapi.DomainTransactionOutput{}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: &externalapi.DomainTransactionID{}, + }, + } + return tests +} + +func initTestDomainTransactionForEqual() []testDomainTransactionStruct { + + tests := []testDomainTransactionStruct{ + { + baseTx: initTestBaseTransaction(), + transactionToCompareTo: initTestTransactionToCompare(), + }, + { + baseTx: nil, + transactionToCompareTo: []*transactionToCompare{{ + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{}, + []*externalapi.DomainTransactionOutput{}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + expectedResult: false, + }, { + tx: nil, + expectedResult: true}}, + }, { + baseTx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{}, + []*externalapi.DomainTransactionOutput{}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + }, + transactionToCompareTo: []*transactionToCompare{{ + tx: nil, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{}, + []*externalapi.DomainTransactionOutput{}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 0, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + nil, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{}, + []*externalapi.DomainTransactionOutput{}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{0x01}, + 0, + 1, + nil, + }, + expectedResult: true, + }}, + }, + } + return tests +} + +func initTestBaseDomainTransactionInput() *externalapi.DomainTransactionInput { + basetxInput := &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + } + return basetxInput +} + +func initTestDomainTxInputToCompare() []*transactionInputToCompare { + txInput := []*transactionInputToCompare{{ + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }, + expectedResult: true, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, false, 2), // Changed + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFF0), // Changed + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3, 4}, // Changed + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01, 0x02}, 0xFFFF}, // Changed + []byte{1, 2, 3}, + uint64(0xFFFFFFF0), // Changed + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01, 0x02}, 0xFFFF}, // Changed + []byte{1, 2, 3}, + uint64(0xFFFFFFF0), // Changed + utxo.NewUTXOEntry(2 /* Changed */, []byte{0, 1, 2, 3}, true, 2), // Changed + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01, 0x02}, 0xFFFF}, // Changed + []byte{1, 2, 3}, + uint64(0xFFFFFFF0), // Changed + utxo.NewUTXOEntry(3 /* Changed */, []byte{0, 1, 2, 3}, true, 3), // Changed + }, + expectedResult: false, + }, { + tx: nil, + expectedResult: false, + }} + return txInput + +} + +func initTestDomainTransactionInputForClone() []*externalapi.DomainTransactionInput { + txInput := []*externalapi.DomainTransactionInput{ + { + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }, { + + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }, { + + externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFF0), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + }} + return txInput +} + +func initTestBaseDomainTransactionOutput() *externalapi.DomainTransactionOutput { + basetxOutput := &externalapi.DomainTransactionOutput{ + 0xFFFFFFFF, + []byte{0xFF, 0xFF}, + } + return basetxOutput +} + +func initTestDomainTransactionOutputForClone() []*externalapi.DomainTransactionOutput { + txInput := []*externalapi.DomainTransactionOutput{ + { + 0xFFFFFFFF, + []byte{0xF0, 0xFF}, + }, { + 0xFFFFFFF1, + []byte{0xFF, 0xFF}, + }} + return txInput +} + +func initTestDomainTransactionOutputForEqual() []testDomainTransactionOutputStruct { + tests := []testDomainTransactionOutputStruct{ + { + baseTx: initTestBaseDomainTransactionOutput(), + transactionOutputToCompareTo: []*transactionOutputToCompare{{ + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFFF, + []byte{0xFF, 0xFF}}, + expectedResult: true, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFFF, + []byte{0xF0, 0xFF}, // Changed + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFF0, // Changed + []byte{0xFF, 0xFF}, + }, + expectedResult: false, + }, { + tx: nil, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFF0, // Changed + []byte{0xFF, 0xFF, 0x01}, // Changed + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFF0, // Changed + []byte{}, // Changed + }, + expectedResult: false, + }}, + }, + { + baseTx: nil, + transactionOutputToCompareTo: []*transactionOutputToCompare{{ + tx: nil, + expectedResult: true, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFFF, + []byte{0xFF, 0xFF}}, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFFF, + []byte{0xF0, 0xFF}, // Changed + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFF0, // Changed + []byte{0xFF, 0xFF}, + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFF0, + []byte{0xFF, 0xFF, 0x01}, // Changed + }, + expectedResult: false, + }, { + tx: &externalapi.DomainTransactionOutput{ + 0xFFFFFFF0, + []byte{}, // Changed + }, + expectedResult: false, + }}, + }, + } + return tests +} + +func initTestDomainTransactionInputForEqual() []testDomainTransactionInputStruct { + + tests := []testDomainTransactionInputStruct{ + { + baseTx: initTestBaseDomainTransactionInput(), + transactionInputToCompareTo: initTestDomainTxInputToCompare(), + }, + } + return tests +} + +func TestDomainTransaction_Equal(t *testing.T) { + + txTests := initTestDomainTransactionForEqual() + for i, test := range txTests { + for j, subTest := range test.transactionToCompareTo { + func() { + defer func() { + r := recover() + panicked := r != nil + if panicked != subTest.expectsPanic { + t.Fatalf("panicked expected to be %t but got %t", subTest.expectsPanic, panicked) + } + }() + result1 := test.baseTx.Equal(subTest.tx) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + }() + func() { + defer func() { + r := recover() + panicked := r != nil + if panicked != subTest.expectsPanic { + t.Fatalf("panicked expected to be %t but got %t", subTest.expectsPanic, panicked) + } + }() + result2 := subTest.tx.Equal(test.baseTx) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + }() + } + } +} + +func TestDomainTransaction_Clone(t *testing.T) { + + txs := initTestDomainTransactionForClone() + for i, tx := range txs { + txClone := tx.Clone() + if !txClone.Equal(tx) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(tx, txClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} + +func TestDomainTransactionInput_Equal(t *testing.T) { + + txTests := initTestDomainTransactionInputForEqual() + for i, test := range txTests { + for j, subTest := range test.transactionInputToCompareTo { + result1 := test.baseTx.Equal(subTest.tx) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.tx.Equal(test.baseTx) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainTransactionInput_Clone(t *testing.T) { + + txInputs := initTestDomainTransactionInputForClone() + for i, txInput := range txInputs { + txInputClone := txInput.Clone() + if !txInputClone.Equal(txInput) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(txInput, txInputClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} + +func TestDomainTransactionOutput_Equal(t *testing.T) { + + txTests := initTestDomainTransactionOutputForEqual() + for i, test := range txTests { + for j, subTest := range test.transactionOutputToCompareTo { + result1 := test.baseTx.Equal(subTest.tx) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.tx.Equal(test.baseTx) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainTransactionOutput_Clone(t *testing.T) { + + txInputs := initTestDomainTransactionOutputForClone() + for i, txOutput := range txInputs { + txOutputClone := txOutput.Clone() + if !txOutputClone.Equal(txOutput) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(txOutput, txOutputClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} + +func initTestDomainOutpointForClone() []*externalapi.DomainOutpoint { + outpoint := []*externalapi.DomainOutpoint{{ + externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 1}, + } + return outpoint +} + +func initTestDomainOutpointForEqual() []testDomainOutpointStruct { + + var outpoint = []*domainOutpointToCompare{{ + domainOutpoint: &externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 1}, + expectedResult: true, + }, { + domainOutpoint: &externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 1}, + expectedResult: false, + }, { + domainOutpoint: &externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0}, + 2}, + expectedResult: false, + }} + tests := []testDomainOutpointStruct{ + { + baseDomainOutpoint: &externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 1}, + domainOutpointToCompareTo: outpoint, + }, {baseDomainOutpoint: &externalapi.DomainOutpoint{ + externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 1}, + domainOutpointToCompareTo: []*domainOutpointToCompare{{domainOutpoint: nil, expectedResult: false}}, + }, {baseDomainOutpoint: nil, + domainOutpointToCompareTo: []*domainOutpointToCompare{{domainOutpoint: nil, expectedResult: true}}, + }, + } + return tests +} + +func TestDomainOutpoint_Equal(t *testing.T) { + + domainOutpoints := initTestDomainOutpointForEqual() + for i, test := range domainOutpoints { + for j, subTest := range test.domainOutpointToCompareTo { + result1 := test.baseDomainOutpoint.Equal(subTest.domainOutpoint) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.domainOutpoint.Equal(test.baseDomainOutpoint) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainOutpoint_Clone(t *testing.T) { + + domainOutpoints := initTestDomainOutpointForClone() + for i, outpoint := range domainOutpoints { + outpointClone := outpoint.Clone() + if !outpointClone.Equal(outpoint) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(outpoint, outpointClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} + +func initTestDomainTransactionIDForClone() []*externalapi.DomainTransactionID { + outpoint := []*externalapi.DomainTransactionID{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + } + + return outpoint +} + +func initTestDomainTransactionIDForEqual() []testDomainTransactionIDStruct { + + var outpoint = []*domainTransactionIDToCompare{{ + domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + expectedResult: true, + }, { + domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + expectedResult: false, + }, { + domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0}, + expectedResult: false, + }} + tests := []testDomainTransactionIDStruct{ + { + baseDomainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + domainTransactionIDToCompareTo: outpoint, + }, { + baseDomainTransactionID: nil, + domainTransactionIDToCompareTo: []*domainTransactionIDToCompare{{ + domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + expectedResult: false, + }}, + }, + } + return tests +} + +func TestDomainTransactionID_Equal(t *testing.T) { + + domainDomainTransactionIDs := initTestDomainTransactionIDForEqual() + for i, test := range domainDomainTransactionIDs { + for j, subTest := range test.domainTransactionIDToCompareTo { + result1 := test.baseDomainTransactionID.Equal(subTest.domainTransactionID) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.domainTransactionID.Equal(test.baseDomainTransactionID) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestDomainTransactionID_Clone(t *testing.T) { + + domainDomainTransactionIDs := initTestDomainTransactionIDForClone() + for i, domainTransactionID := range domainDomainTransactionIDs { + domainTransactionIDClone := domainTransactionID.Clone() + if !domainTransactionIDClone.Equal(domainTransactionID) { + t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) + } + if !reflect.DeepEqual(domainTransactionID, domainTransactionIDClone) { + t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/model/externalapi/utxoentry.go b/domain/consensus/model/externalapi/utxoentry.go index 22f9498b8..efc803809 100644 --- a/domain/consensus/model/externalapi/utxoentry.go +++ b/domain/consensus/model/externalapi/utxoentry.go @@ -9,4 +9,5 @@ type UTXOEntry interface { ScriptPublicKey() []byte // The public key script for the output. BlockBlueScore() uint64 // Blue score of the block accepting the tx. IsCoinbase() bool + Equal(other UTXOEntry) bool } diff --git a/domain/consensus/model/reachabilitydata.go b/domain/consensus/model/reachabilitydata.go index 93ffd3b20..f90c42e5a 100644 --- a/domain/consensus/model/reachabilitydata.go +++ b/domain/consensus/model/reachabilitydata.go @@ -12,15 +12,32 @@ type ReachabilityData struct { FutureCoveringSet FutureCoveringTreeNodeSet } -// Clone returns a clone of ReachabilityData -func (rd *ReachabilityData) Clone() *ReachabilityData { - if rd == nil { - return nil +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &ReachabilityData{&ReachabilityTreeNode{}, FutureCoveringTreeNodeSet{}} + +// Equal returns whether rd equals to other +func (rd *ReachabilityData) Equal(other *ReachabilityData) bool { + if rd == nil || other == nil { + return rd == other } + if !rd.TreeNode.Equal(other.TreeNode) { + return false + } + + if !rd.FutureCoveringSet.Equal(other.FutureCoveringSet) { + return false + } + + return true +} + +// Clone returns a clone of ReachabilityData +func (rd *ReachabilityData) Clone() *ReachabilityData { return &ReachabilityData{ TreeNode: rd.TreeNode.Clone(), - FutureCoveringSet: externalapi.CloneHashes(rd.FutureCoveringSet), + FutureCoveringSet: rd.FutureCoveringSet.Clone(), } } @@ -48,15 +65,43 @@ type ReachabilityTreeNode struct { Interval *ReachabilityInterval } +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &ReachabilityTreeNode{[]*externalapi.DomainHash{}, &externalapi.DomainHash{}, + &ReachabilityInterval{}} + +// Equal returns whether rtn equals to other +func (rtn *ReachabilityTreeNode) Equal(other *ReachabilityTreeNode) bool { + if rtn == nil || other == nil { + return rtn == other + } + + if !externalapi.HashesEqual(rtn.Children, other.Children) { + return false + } + + if !rtn.Parent.Equal(other.Parent) { + return false + } + + if !rtn.Interval.Equal(other.Interval) { + return false + } + + return true +} + // Clone returns a clone of ReachabilityTreeNode func (rtn *ReachabilityTreeNode) Clone() *ReachabilityTreeNode { - if rtn == nil { - return nil + + var parentClone *externalapi.DomainHash + if rtn.Parent != nil { + parentClone = rtn.Parent.Clone() } return &ReachabilityTreeNode{ Children: externalapi.CloneHashes(rtn.Children), - Parent: rtn.Parent.Clone(), + Parent: parentClone, Interval: rtn.Interval.Clone(), } } @@ -69,12 +114,29 @@ type ReachabilityInterval struct { End uint64 } -// Clone returns a clone of ReachabilityInterval -func (ri *ReachabilityInterval) Clone() *ReachabilityInterval { - if ri == nil { - return nil +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &ReachabilityInterval{0, 0} + +// Equal returns whether ri equals to other +func (ri *ReachabilityInterval) Equal(other *ReachabilityInterval) bool { + if ri == nil || other == nil { + return ri == other } + if ri.Start != other.Start { + return false + } + + if ri.End != other.End { + return false + } + + return true +} + +// Clone returns a clone of ReachabilityInterval +func (ri *ReachabilityInterval) Clone() *ReachabilityInterval { return &ReachabilityInterval{ Start: ri.Start, End: ri.End, @@ -98,3 +160,17 @@ func (ri *ReachabilityInterval) String() string { // // See insertNode, hasAncestorOf, and isInPast for further details. type FutureCoveringTreeNodeSet []*externalapi.DomainHash + +// Clone returns a clone of FutureCoveringTreeNodeSet +func (fctns FutureCoveringTreeNodeSet) Clone() FutureCoveringTreeNodeSet { + return externalapi.CloneHashes(fctns) +} + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ FutureCoveringTreeNodeSet = []*externalapi.DomainHash{} + +// Equal returns whether fctns equals to other +func (fctns FutureCoveringTreeNodeSet) Equal(other FutureCoveringTreeNodeSet) bool { + return externalapi.HashesEqual(fctns, other) +} diff --git a/domain/consensus/model/reachabilitydata_equal_clone_test.go b/domain/consensus/model/reachabilitydata_equal_clone_test.go new file mode 100644 index 000000000..408981ec9 --- /dev/null +++ b/domain/consensus/model/reachabilitydata_equal_clone_test.go @@ -0,0 +1,296 @@ +package model + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "reflect" + "testing" +) + +func TestReachabilityData_Equal(t *testing.T) { + type dataToCompare struct { + data *ReachabilityData + expectedResult bool + } + tests := []struct { + baseData *ReachabilityData + dataToCompareTo []dataToCompare + }{ + // Test nil data + { + baseData: nil, + dataToCompareTo: nil, + }, + // Test empty data + { + baseData: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{}, + }, + dataToCompareTo: []dataToCompare{ + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{}, + }, + expectedResult: true, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}}, // Changed + &externalapi.DomainHash{}, + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{1}, // Changed + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &ReachabilityInterval{100, 0}, // Changed start + }, + FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &ReachabilityInterval{0, 100}, // Changed end + }, + FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, // Changed + }, + expectedResult: false, + }, + }, + }, + // Test filled data + { + baseData: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}, {3}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + dataToCompareTo: []dataToCompare{ + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}, {3}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: true, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}, {3}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{}, // Changed + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}, {3}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{200, 200}, // Changed start + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}, {3}}, + &externalapi.DomainHash{1}, + nil, //Changed + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}, {3}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 100}, // Changed end + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, // Changed + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}}, + &externalapi.DomainHash{}, // Changed + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{}, // Changed + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{}, // Changed + }, + expectedResult: false, + }, + { + data: &ReachabilityData{ + nil, + FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: nil, + expectedResult: false, + }, + }, + }, + } + + for i, test := range tests { + for j, subTest := range test.dataToCompareTo { + result1 := test.baseData.Equal(subTest.data) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + + result2 := subTest.data.Equal(test.baseData) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestReachabilityData_Clone(t *testing.T) { + testData := []*ReachabilityData{ + { + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{}, + }, + { + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + { + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + { + &ReachabilityTreeNode{ + []*externalapi.DomainHash{{1}, {2}}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + { + &ReachabilityTreeNode{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{1}, + &ReachabilityInterval{100, 200}, + }, + FutureCoveringTreeNodeSet{{1}, {2}}, + }, + } + + for i, data := range testData { + clone := data.Clone() + if !clone.Equal(data) { + t.Fatalf("Test #%d: clone should be equal to the original", i) + } + + if !reflect.DeepEqual(data, clone) { + t.Fatalf("Test #%d: clone should be equal to the original", i) + } + } +} diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 10ed66614..049388553 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -74,7 +74,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, } var oldHeadersSelectedTip *externalapi.DomainHash - isGenesis := *blockHash == *bp.genesisHash + isGenesis := blockHash.Equal(bp.genesisHash) if !isGenesis { var err error oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext) @@ -156,7 +156,7 @@ func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *e return err } - if *headersSelectedTip == *oldHeadersSelectedTip { + if headersSelectedTip.Equal(oldHeadersSelectedTip) { return nil } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go index c2e60cc01..826b6632b 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go @@ -17,7 +17,7 @@ func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externa newPruningPointHash := consensushashing.BlockHash(newPruningPoint) - if *expectedNewPruningPointHash != *newPruningPointHash { + if !expectedNewPruningPointHash.Equal(newPruningPointHash) { return errors.Wrapf(ruleerrors.ErrUnexpectedPruningPoint, "expected pruning point %s but got %s", expectedNewPruningPointHash, newPruningPointHash) } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 5b9367cf1..4daa95b9f 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -143,7 +143,7 @@ func (v *blockValidator) checkTransactionsInIsolation(block *externalapi.DomainB func (v *blockValidator) checkBlockHashMerkleRoot(block *externalapi.DomainBlock) error { calculatedHashMerkleRoot := merkle.CalculateHashMerkleRoot(block.Transactions) - if block.Header.HashMerkleRoot != *calculatedHashMerkleRoot { + if !block.Header.HashMerkleRoot.Equal(calculatedHashMerkleRoot) { return errors.Wrapf(ruleerrors.ErrBadMerkleRoot, "block hash merkle root is invalid - block "+ "header indicates %s, but calculated value is %s", block.Header.HashMerkleRoot, calculatedHashMerkleRoot) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 19f92a2a1..63976e8bf 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -86,7 +86,7 @@ func (v *blockValidator) hasValidatedHeader(blockHash *externalapi.DomainHash) ( func (v *blockValidator) checkParentsIncest(header *externalapi.DomainBlockHeader) error { for _, parentA := range header.ParentHashes { for _, parentB := range header.ParentHashes { - if *parentA == *parentB { + if parentA.Equal(parentB) { continue } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index c6402e6f9..31ca02e4c 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -35,7 +35,7 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader) error { hash := consensushashing.HeaderHash(header) - if len(header.ParentHashes) == 0 && *hash != *v.genesisHash { + if len(header.ParentHashes) == 0 && !hash.Equal(v.genesisHash) { return errors.Wrapf(ruleerrors.ErrNoParents, "block has no parents") } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index aab8210ae..01df31a28 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -68,7 +68,7 @@ func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(block log.Tracef("isCandidateToBeNextVirtualSelectedParent start for block %s", blockHash) defer log.Tracef("isCandidateToBeNextVirtualSelectedParent end for block %s", blockHash) - if *blockHash == *csm.genesisHash { + if blockHash.Equal(csm.genesisHash) { log.Tracef("Block %s is the genesis block, therefore it is "+ "the selected parent by definition", blockHash) return true, nil @@ -87,7 +87,7 @@ func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(block } log.Tracef("The next selected parent is: %s", nextVirtualSelectedParent) - return *blockHash == *nextVirtualSelectedParent, nil + return blockHash.Equal(nextVirtualSelectedParent), nil } func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (newTips []*externalapi.DomainHash, err error) { @@ -111,7 +111,7 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai log.Tracef("calculateNewTips start for new tip %s", newTipHash) defer log.Tracef("calculateNewTips end for new tip %s", newTipHash) - if *newTipHash == *csm.genesisHash { + if newTipHash.Equal(csm.genesisHash) { log.Tracef("The new tip is the genesis block, therefore it is the only tip by definition") return []*externalapi.DomainHash{newTipHash}, nil } @@ -133,7 +133,7 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai for _, currentTip := range currentTips { isCurrentTipInNewTipParents := false for _, newTipParent := range newTipParents { - if *currentTip == *newTipParent { + if currentTip.Equal(newTipParent) { isCurrentTipInNewTipParents = true break } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 42d214bbf..3b6c3c419 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -18,7 +18,7 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) - if *blockHash == *csm.genesisHash { + if blockHash.Equal(csm.genesisHash) { log.Tracef("Block %s is the genesis. By definition, "+ "it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash) return utxo.NewUTXODiff(), externalapi.AcceptanceData{}, multiset.New(), nil diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index a608340e7..ed38040db 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -154,7 +154,7 @@ func TestPastUTXOMultiset(t *testing.T) { secondMultisetHash := secondMultiset.Hash() // Make sure the multiset hasn't changed - if *firstMultisetHash != *secondMultisetHash { + if !firstMultisetHash.Equal(secondMultisetHash) { t.Fatalf("TestPastUTXOMultiSet: selectedParentMultiset appears to have changed!") } }) diff --git a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go index 9774276fe..4451c5cee 100644 --- a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go +++ b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go @@ -8,7 +8,7 @@ func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.Dom log.Tracef("isViolatingFinality start for block %s", blockHash) defer log.Tracef("isViolatingFinality end for block %s", blockHash) - if *blockHash == *csm.genesisHash { + if blockHash.Equal(csm.genesisHash) { log.Tracef("Block %s is the genesis block, "+ "and does not violate finality by definition", blockHash) return false, false, nil diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go index 965354283..d27b92e4c 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go @@ -51,7 +51,7 @@ func (csm *consensusStateManager) calculateSelectedParentChainChanges( // Walk down from the toBlockHash to the common ancestor var added []*externalapi.DomainHash current = toBlockHash - for *current != *commonAncestor { + for !current.Equal(commonAncestor) { added = append(added, current) currentGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, current) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go index f2306e142..c90ef0680 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go @@ -35,7 +35,7 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { 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 { + if !blockASelectedParentChainChanges.Added[0].Equal(blockAHash) { t.Fatalf("The `added` slice contains an unexpected hash. Want: %s, got: %s", blockAHash, blockASelectedParentChainChanges.Added[0]) } @@ -53,7 +53,7 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { } virtualSelectedParent := virtualGHOSTDAGData.SelectedParent() notVirtualSelectedParent := blockAHash - if *virtualSelectedParent == *blockAHash { + if virtualSelectedParent.Equal(blockAHash) { notVirtualSelectedParent = blockBHash } @@ -71,7 +71,7 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { 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 { + if !blockCSelectedParentChainChanges.Removed[0].Equal(virtualSelectedParent) { t.Fatalf("The `removed` slice contains an unexpected hash. "+ "Want: %s, got: %s", virtualSelectedParent, blockCSelectedParentChainChanges.Removed[0]) } @@ -82,11 +82,11 @@ func TestCalculateSelectedParentChainChanges(t *testing.T) { 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 { + if !blockCSelectedParentChainChanges.Added[0].Equal(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 { + if !blockCSelectedParentChainChanges.Added[1].Equal(blockCHash) { t.Fatalf("The `added` slice contains an unexpected hash as the second item. "+ "Want: %s, got: %s", blockCHash, blockCSelectedParentChainChanges.Added[1]) } diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 103da8975..3746f2422 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -109,7 +109,7 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( // remove virtual from parentChildren if it's there for i, parentChild := range parentChildren { - if *parentChild == *model.VirtualBlockHash { + if parentChild.Equal(model.VirtualBlockHash) { parentChildren = append(parentChildren[:i], parentChildren[i+1:]...) break } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 6f28d7312..8123aa690 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -70,7 +70,7 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e defer log.Tracef("findSelectedParentStatus end") lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1] - if *lastUnverifiedBlock == *csm.genesisHash { + if lastUnverifiedBlock.Equal(csm.genesisHash) { log.Tracef("the most recent unverified block is the genesis block, "+ "which by definition has status: %s", externalapi.StatusUTXOValid) return externalapi.StatusUTXOValid, nil @@ -173,7 +173,7 @@ func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssign log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild start for block %s", blockHash) defer log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild end for block %s", blockHash) - if *blockHash == *csm.genesisHash { + if blockHash.Equal(csm.genesisHash) { log.Tracef("Genesis block doesn't have ancestors to remove from the virtual diff parents") return nil } @@ -184,7 +184,7 @@ func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssign } for _, virtualDiffParent := range virtualDiffParents { - if *virtualDiffParent == *blockHash { + if virtualDiffParent.Equal(blockHash) { log.Tracef("Skipping updating virtual diff parent %s "+ "because it was updated before.", virtualDiffParent) continue diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 52dc97612..77f038e27 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -56,7 +56,7 @@ func TestDoubleSpends(t *testing.T) { spendingTransaction2.Outputs[0].Value-- // tweak the value to create a different ID spendingTransaction1ID := consensushashing.TransactionID(spendingTransaction1) spendingTransaction2ID := consensushashing.TransactionID(spendingTransaction2) - if *spendingTransaction1ID == *spendingTransaction2ID { + if spendingTransaction1ID.Equal(spendingTransaction2ID) { t.Fatalf("spendingTransaction1 and spendingTransaction2 ids are equal") } diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index 87847d699..a01c05672 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -63,7 +63,7 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap log.Debugf("The UTXO commitment of the pruning point: %s", newPruningPointHeader.UTXOCommitment) - if newPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() { + if !newPruningPointHeader.UTXOCommitment.Equal(utxoSetMultiSet.Hash()) { return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+ "point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash()) } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 1d80d2458..9d50dc8e5 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -13,7 +13,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain log.Tracef("Saving a reference to the GHOSTDAG data of the old virtual") var oldVirtualSelectedParent *externalapi.DomainHash - if *newBlockHash != *csm.genesisHash { + if !newBlockHash.Equal(csm.genesisHash) { oldVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err @@ -65,7 +65,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain log.Tracef("Calculating selected parent chain changes") var selectedParentChainChanges *externalapi.SelectedParentChainChanges - if *newBlockHash != *csm.genesisHash { + if !newBlockHash.Equal(csm.genesisHash) { newVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) if err != nil { return nil, err diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go index 564ca9fa2..4ba8d5325 100644 --- a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go +++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go @@ -29,7 +29,7 @@ func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi defer log.Tracef("addToVirtualDiffParents end for block %s", blockHash) var oldVirtualDiffParents []*externalapi.DomainHash - if *blockHash != *csm.genesisHash { + if !blockHash.Equal(csm.genesisHash) { var err error oldVirtualDiffParents, err = csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { @@ -39,7 +39,7 @@ func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi isInVirtualDiffParents := false for _, diffParent := range oldVirtualDiffParents { - if *diffParent == *blockHash { + if diffParent.Equal(blockHash) { isInVirtualDiffParents = true break } @@ -67,7 +67,7 @@ func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *extern newVirtualDiffParents := make([]*externalapi.DomainHash, 0, len(oldVirtualDiffParents)-1) for _, diffParent := range oldVirtualDiffParents { - if *diffParent != *blockHash { + if !diffParent.Equal(blockHash) { newVirtualDiffParents = append(newVirtualDiffParents, diffParent) } } diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index c5a0eef2c..b4ecd098e 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -103,7 +103,7 @@ func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalap defer log.Tracef("validateAcceptedIDMerkleRoot end for block %s", blockHash) calculatedAcceptedIDMerkleRoot := calculateAcceptedIDMerkleRoot(acceptanceData) - if block.Header.AcceptedIDMerkleRoot != *calculatedAcceptedIDMerkleRoot { + if !block.Header.AcceptedIDMerkleRoot.Equal(calculatedAcceptedIDMerkleRoot) { return errors.Wrapf(ruleerrors.ErrBadMerkleRoot, "block %s accepted ID merkle root is invalid - block "+ "header indicates %s, but calculated value is %s", blockHash, &block.Header.UTXOCommitment, calculatedAcceptedIDMerkleRoot) @@ -119,7 +119,7 @@ func (csm *consensusStateManager) validateUTXOCommitment( defer log.Tracef("validateUTXOCommitment end for block %s", blockHash) multisetHash := multiset.Hash() - if block.Header.UTXOCommitment != *multisetHash { + if !block.Header.UTXOCommitment.Equal(multisetHash) { return errors.Wrapf(ruleerrors.ErrBadUTXOCommitment, "block %s UTXO commitment is invalid - block "+ "header indicates %s, but calculated value is %s", blockHash, &block.Header.UTXOCommitment, multisetHash) } @@ -173,7 +173,7 @@ func (csm *consensusStateManager) validateCoinbaseTransaction(blockHash *externa log.Tracef("given coinbase hash: %s, expected coinbase hash: %s", coinbaseTransactionHash, expectedCoinbaseTransactionHash) - if *coinbaseTransactionHash != *expectedCoinbaseTransactionHash { + if !coinbaseTransactionHash.Equal(expectedCoinbaseTransactionHash) { return errors.Wrap(ruleerrors.ErrBadCoinbaseTransaction, "coinbase transaction is not built as expected") } diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index 245fbfb13..e5c69cd6c 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -99,7 +99,7 @@ func (dtm *dagTopologyManager) IsInSelectedParentChainOf(blockHashA *externalapi func isHashInSlice(hash *externalapi.DomainHash, hashes []*externalapi.DomainHash) bool { for _, h := range hashes { - if *h == *hash { + if h.Equal(hash) { return true } } @@ -128,7 +128,7 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par return err } for i, parentChild := range parentRelations.Children { - if *parentChild == *blockHash { + if parentChild.Equal(blockHash) { parentRelations.Children = append(parentRelations.Children[:i], parentRelations.Children[i+1:]...) dtm.blockRelationStore.StageBlockRelation(currentParent, parentRelations) break @@ -145,7 +145,7 @@ func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, par } isBlockAlreadyInChildren := false for _, parentChild := range parentRelations.Children { - if *parentChild == *blockHash { + if parentChild.Equal(blockHash) { isBlockAlreadyInChildren = true break } @@ -180,7 +180,7 @@ func (dtm *dagTopologyManager) ChildInSelectedParentChainOf( selectedParent := ghostdagData.SelectedParent() // In case where `blockHash` is an immediate parent of `highHash` - if *blockHash == *selectedParent { + if blockHash.Equal(selectedParent) { return highHash, nil } highHash = selectedParent diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index cdce9fd6a..9db1f12b3 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -20,7 +20,7 @@ func (s *selectedChildIterator) Next() bool { } for _, child := range children { - if *child == *model.VirtualBlockHash { + if child.Equal(model.VirtualBlockHash) { continue } diff --git a/domain/consensus/processes/finalitymanager/finality_manager.go b/domain/consensus/processes/finalitymanager/finality_manager.go index b5fb1ba29..67cf5b811 100644 --- a/domain/consensus/processes/finalitymanager/finality_manager.go +++ b/domain/consensus/processes/finalitymanager/finality_manager.go @@ -51,7 +51,7 @@ func (fm *finalityManager) VirtualFinalityPoint() (*externalapi.DomainHash, erro func (fm *finalityManager) FinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { log.Tracef("FinalityPoint start") defer log.Tracef("FinalityPoint end") - if *blockHash == *model.VirtualBlockHash { + if blockHash.Equal(model.VirtualBlockHash) { return fm.VirtualFinalityPoint() } finalityPoint, err := fm.finalityStore.FinalityPoint(fm.databaseContext, blockHash) @@ -88,7 +88,7 @@ func (fm *finalityManager) calculateFinalityPoint(blockHash *externalapi.DomainH } selectedParent := ghostdagData.SelectedParent() - if *selectedParent == *fm.genesisHash { + if selectedParent.Equal(fm.genesisHash) { return fm.genesisHash, nil } diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index 6a84f7b70..ec2ad1ef1 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -92,7 +92,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error } for _, mergeSetBlock := range mergeSetArr { - if *mergeSetBlock == *selectedParent { + if mergeSetBlock.Equal(selectedParent) { if !contains(selectedParent, mergeSetBlues) { mergeSetBlues = append(mergeSetBlues, selectedParent) blueSet = append(blueSet, selectedParent) @@ -252,7 +252,7 @@ func (gh *ghostdagHelper) validateKCluster(chain *externalapi.DomainHash, checke /*----------------contains-------------------------- */ func contains(item *externalapi.DomainHash, items []*externalapi.DomainHash) bool { for _, r := range items { - if *r == *item { + if r.Equal(item) { return true } } @@ -294,7 +294,7 @@ func (gh *ghostdagHelper) findMergeSet(parents []*externalapi.DomainHash, select for len(blockQueue) > 0 { block := blockQueue[0] blockQueue = blockQueue[1:] - if *selectedParent == *block { + if selectedParent.Equal(block) { if !contains(block, allMergeSet) { allMergeSet = append(allMergeSet, block) } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index a2d248cd1..08f64b32c 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -137,7 +137,7 @@ func TestGHOSTDAG(t *testing.T) { factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore()) } - if *StringToByte(testBlockData.SelectedParent) != *ghostdagData.SelectedParent() { + if !StringToByte(testBlockData.SelectedParent).Equal(ghostdagData.SelectedParent()) { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, string(ghostdagData.SelectedParent()[:])) } @@ -267,7 +267,7 @@ func (dt *DAGTopologyManagerImpl) IsAncestorOf(hashBlockA *externalapi.DomainHas } for _, parentOfB := range blockBParents { - if *parentOfB == *hashBlockA { + if parentOfB.Equal(hashBlockA) { return true, nil } } diff --git a/domain/consensus/processes/ghostdagmanager/mergeset.go b/domain/consensus/processes/ghostdagmanager/mergeset.go index ead66812f..4668eb127 100644 --- a/domain/consensus/processes/ghostdagmanager/mergeset.go +++ b/domain/consensus/processes/ghostdagmanager/mergeset.go @@ -14,7 +14,7 @@ func (gm *ghostdagManager) mergeSetWithoutSelectedParent(selecteParent *external queue := []*externalapi.DomainHash{} // Queueing all parents (other than the selected parent itself) for processing. for _, parent := range blockParents { - if *parent == *selecteParent { + if parent.Equal(selecteParent) { continue } mergeSetMap[*parent] = struct{}{} diff --git a/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go b/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go index 4ff750563..f4bb6f16b 100644 --- a/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go +++ b/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go @@ -46,7 +46,7 @@ func (h *headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error { return err } - if *newHeadersSelectedTip != *headersSelectedTip { + if !newHeadersSelectedTip.Equal(headersSelectedTip) { h.headersSelectedTipStore.Stage(newHeadersSelectedTip) } } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 11a0e7431..1c87d7a81 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -124,7 +124,7 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { return err } - if *newPruningPoint != *currentP { + if !newPruningPoint.Equal(currentP) { err = pm.savePruningPoint(newPruningPoint) if err != nil { return err diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index 8d2674955..01f0aaac6 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -26,7 +26,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t t.Fatalf("ReachabilityReindexRoot: %s", err) } - if *reindexRoot != *params.GenesisHash { + if !reindexRoot.Equal(params.GenesisHash) { t.Fatalf("reindex root is expected to initially be genesis") } @@ -52,7 +52,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t t.Fatalf("ReachabilityReindexRoot: %s", err) } - if *newReindexRoot == *reindexRoot { + if newReindexRoot.Equal(reindexRoot) { t.Fatalf("reindex root is expected to change") } @@ -114,7 +114,7 @@ func TestUpdateReindexRoot(t *testing.T) { t.Fatalf("ReachabilityReindexRoot: %s", err) } - if *reindexRoot != *params.GenesisHash { + if !reindexRoot.Equal(params.GenesisHash) { t.Fatalf("reindex root unexpectedly moved") } } @@ -131,7 +131,7 @@ func TestUpdateReindexRoot(t *testing.T) { t.Fatalf("ReachabilityReindexRoot: %s", err) } - if *reindexRoot != *chain1RootBlock { + if !reindexRoot.Equal(chain1RootBlock) { t.Fatalf("chain1RootBlock is not the reindex root after reindex") } @@ -207,7 +207,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { t.Fatalf("ReachabilityReindexRoot: %s", err) } - if *reindexRoot != *centerBlock { + if !reindexRoot.Equal(centerBlock) { t.Fatalf("centerBlock is not the reindex root after reindex") } diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go index 448ebb031..0e7f36af7 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go @@ -950,7 +950,7 @@ func BenchmarkReindexInterval(b *testing.B) { currentTreeNode = childTreeNode } - originalRemainingInterval := *helper.remainingIntervalAfter(root) + originalRemainingInterval := helper.remainingIntervalAfter(root).Clone() // After we added subTreeSize nodes, adding the next // node should lead to a reindex from root. fullReindexTriggeringNode := helper.newNode() @@ -961,7 +961,7 @@ func BenchmarkReindexInterval(b *testing.B) { b.Fatalf("addChild: %s", err) } - if *helper.remainingIntervalAfter(root) == originalRemainingInterval { + if helper.remainingIntervalAfter(root).Equal(originalRemainingInterval) { b.Fatal("Expected a reindex from root, but it didn't happen") } } diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 054b3836e..2e2f3398c 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -317,7 +317,7 @@ func (rt *reachabilityManager) countSubtrees(node *externalapi.DomainHash, subTr // We reached a leaf or a pre-calculated subtree. // Push information up - for *current != *node { + for !current.Equal(node) { current, err = rt.parent(current) if err != nil { return err @@ -461,7 +461,7 @@ func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAnces return err } - if currentHasSlackIntervalBefore || *current == *reindexRoot { + if currentHasSlackIntervalBefore || current.Equal(reindexRoot) { break } @@ -471,7 +471,7 @@ func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAnces } } - if *current == *reindexRoot { + if current.Equal(reindexRoot) { // "Deallocate" an interval of slackReachabilityIntervalForReclaiming // from this node. This is the interval that we'll use for the new // node. @@ -505,7 +505,7 @@ func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAnces // current node with an interval that is smaller by // slackReachabilityIntervalForReclaiming. This is to make room // for the new node. - for *current != *commonAncestor { + for !current.Equal(commonAncestor) { currentInterval, err := rt.interval(current) if err != nil { return err @@ -583,7 +583,7 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces return err } - if currentHasSlackIntervalAfter || *current == *reindexRoot { + if currentHasSlackIntervalAfter || current.Equal(reindexRoot) { break } @@ -593,7 +593,7 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces } } - if *current == *reindexRoot { + if current.Equal(reindexRoot) { // "Deallocate" an interval of slackReachabilityIntervalForReclaiming // from this node. This is the interval that we'll use for the new // node. @@ -627,7 +627,7 @@ func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAnces // current node with an interval that is smaller by // slackReachabilityIntervalForReclaiming. This is to make room // for the new node. - for *current != *commonAncestor { + for !current.Equal(commonAncestor) { currentInterval, err := rt.interval(current) if err != nil { return err @@ -883,7 +883,7 @@ func (rt *reachabilityManager) splitChildrenAroundChild(node, child *externalapi } for i, candidateChild := range nodeChildren { - if *candidateChild == *child { + if candidateChild.Equal(child) { return nodeChildren[:i], nodeChildren[i+1:], nil } } diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 90a5009d8..f62c10a96 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -36,7 +36,7 @@ func (sm *syncManager) isAwaitingUTXOSet() (isAwaitingUTXOSet bool, ibdRootUTXOB // 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 { + if !pruningPoint.Equal(pruningPointByHeaders) { return true, pruningPointByHeaders, nil } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index eee4d8168..9d0ecb65e 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -128,7 +128,7 @@ func (v *transactionValidator) checkCoinbaseLength(tx *externalapi.DomainTransac func (v *transactionValidator) checkTransactionPayloadHash(tx *externalapi.DomainTransaction) error { if tx.SubnetworkID != subnetworks.SubnetworkIDNative { payloadHash := hashes.PayloadHash(tx.Payload) - if tx.PayloadHash != *payloadHash { + if !tx.PayloadHash.Equal(payloadHash) { return errors.Wrapf(ruleerrors.ErrInvalidPayloadHash, "invalid payload hash") } } else if tx.PayloadHash != (externalapi.DomainHash{}) { @@ -177,7 +177,7 @@ func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.Domain // If we are a partial node, only transactions on built in subnetworks // or our own subnetwork may have a payload isLocalNodeFull := localNodeSubnetworkID == nil - shouldTxBeFull := subnetworks.IsBuiltIn(tx.SubnetworkID) || subnetworks.IsEqual(&tx.SubnetworkID, localNodeSubnetworkID) + shouldTxBeFull := subnetworks.IsBuiltIn(tx.SubnetworkID) || tx.SubnetworkID.Equal(localNodeSubnetworkID) if !isLocalNodeFull && !shouldTxBeFull && len(tx.Payload) > 0 { return errors.Wrapf(ruleerrors.ErrInvalidPayload, "transaction that was expected to be partial has a payload "+ diff --git a/domain/consensus/utils/hashes/to_big.go b/domain/consensus/utils/hashes/to_big.go index 510181660..25077c69a 100644 --- a/domain/consensus/utils/hashes/to_big.go +++ b/domain/consensus/utils/hashes/to_big.go @@ -10,7 +10,7 @@ import ( func ToBig(hash *externalapi.DomainHash) *big.Int { // A Hash is in little-endian, but the big package wants the bytes in // big-endian, so reverse them. - buf := *hash + buf := hash.Clone() blen := len(buf) for i := 0; i < blen/2; i++ { buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] diff --git a/domain/consensus/utils/subnetworks/compare.go b/domain/consensus/utils/subnetworks/compare.go index af1a06358..12cda20da 100644 --- a/domain/consensus/utils/subnetworks/compare.go +++ b/domain/consensus/utils/subnetworks/compare.go @@ -21,14 +21,3 @@ func cmp(a, b externalapi.DomainSubnetworkID) int { func Less(a, b externalapi.DomainSubnetworkID) bool { return cmp(a, b) < 0 } - -// IsEqual returns true if a and b are equal or both nil -func IsEqual(a, b *externalapi.DomainSubnetworkID) bool { - if a == nil && b == nil { - return true - } - if a == nil || b == nil { - return false - } - return *a == *b -} diff --git a/domain/consensus/utils/utxo/utxo_entry.go b/domain/consensus/utils/utxo/utxo_entry.go index 68b63793e..b6cae4bab 100644 --- a/domain/consensus/utils/utxo/utxo_entry.go +++ b/domain/consensus/utils/utxo/utxo_entry.go @@ -1,6 +1,9 @@ package utxo -import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +import ( + "bytes" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) type utxoEntry struct { amount uint64 @@ -38,3 +41,36 @@ func (u *utxoEntry) BlockBlueScore() uint64 { func (u *utxoEntry) IsCoinbase() bool { return u.isCoinbase } + +// Equal returns whether entry equals to other +func (u *utxoEntry) Equal(other externalapi.UTXOEntry) bool { + if u == nil || other == nil { + return u == other + } + + // If only the underlying value of other is nil it'll + // make `other == nil` return false, so we check it + // explicitly. + downcastedOther := other.(*utxoEntry) + if u == nil || downcastedOther == nil { + return u == downcastedOther + } + + if u.Amount() != other.Amount() { + return false + } + + if !bytes.Equal(u.ScriptPublicKey(), other.ScriptPublicKey()) { + return false + } + + if u.BlockBlueScore() != other.BlockBlueScore() { + return false + } + + if u.IsCoinbase() != other.IsCoinbase() { + return false + } + + return true +} diff --git a/domain/consensus/utils/utxo/utxo_entry_test.go b/domain/consensus/utils/utxo/utxo_entry_test.go new file mode 100644 index 000000000..69b90277b --- /dev/null +++ b/domain/consensus/utils/utxo/utxo_entry_test.go @@ -0,0 +1,113 @@ +package utxo + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "testing" +) + +func TestUTXOEntry_Equal(t *testing.T) { + type testUTXOEntryToCompare struct { + utxoEntry *utxoEntry + expectedResult bool + } + + tests := []struct { + baseUTXOEntry *utxoEntry + UTXOEntryToCompareTo []testUTXOEntryToCompare + }{ + { + baseUTXOEntry: nil, + UTXOEntryToCompareTo: []testUTXOEntryToCompare{ + { + utxoEntry: nil, + expectedResult: true, + }, + { + utxoEntry: &utxoEntry{ + 0xFFFF, + []byte{0xA1, 0xA2, 0xA3}, + 0xFFFF, + false, + }, + expectedResult: false, + }, + }, + }, { + baseUTXOEntry: &utxoEntry{ + 0xFFFF, + []byte{0xA1, 0xA2, 0xA3}, + 0xFFFF, + true, + }, + UTXOEntryToCompareTo: []testUTXOEntryToCompare{ + { + utxoEntry: &utxoEntry{ + 0xFFFF, + []byte{0xA1, 0xA2, 0xA3}, + 0xFFFF, + true, + }, + expectedResult: true, + }, + { + utxoEntry: nil, + expectedResult: false, + }, + { + utxoEntry: &utxoEntry{ + 0xFFFF, + []byte{0xA1, 0xA0, 0xA3}, // Changed + 0xFFFF, + true, + }, + expectedResult: false, + }, + { + utxoEntry: &utxoEntry{ + 0xFFFF, + []byte{0xA1, 0xA2, 0xA3}, + 0xFFFF, + false, // Changed + }, + expectedResult: false, + }, + { + utxoEntry: &utxoEntry{ + 0xFFFF, + []byte{0xA1, 0xA2, 0xA3}, + 0xFFF0, // Changed + true, + }, + expectedResult: false, + }, + { + utxoEntry: nil, + expectedResult: false, + }, + { + utxoEntry: &utxoEntry{ + 0xFFF0, // Changed + []byte{0xA1, 0xA2, 0xA3}, + 0xFFFF, + true, + }, + expectedResult: false, + }, + }, + }, + } + + for i, test := range tests { + for j, subTest := range test.UTXOEntryToCompareTo { + var base externalapi.UTXOEntry = test.baseUTXOEntry + result1 := base.Equal(subTest.utxoEntry) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + result2 := subTest.utxoEntry.Equal(base) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} diff --git a/domain/dagconfig/genesis_test.go b/domain/dagconfig/genesis_test.go index dd6892757..580773546 100644 --- a/domain/dagconfig/genesis_test.go +++ b/domain/dagconfig/genesis_test.go @@ -15,7 +15,7 @@ import ( func TestGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. hash := consensushashing.BlockHash(MainnetParams.GenesisBlock) - if *MainnetParams.GenesisHash != *hash { + if !MainnetParams.GenesisHash.Equal(hash) { t.Fatalf("TestGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, MainnetParams.GenesisHash) } @@ -26,7 +26,7 @@ func TestGenesisBlock(t *testing.T) { func TestTestnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. hash := consensushashing.BlockHash(TestnetParams.GenesisBlock) - if *TestnetParams.GenesisHash != *hash { + if !TestnetParams.GenesisHash.Equal(hash) { t.Fatalf("TestTestnetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, TestnetParams.GenesisHash) @@ -38,7 +38,7 @@ func TestTestnetGenesisBlock(t *testing.T) { func TestSimnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. hash := consensushashing.BlockHash(SimnetParams.GenesisBlock) - if *SimnetParams.GenesisHash != *hash { + if !SimnetParams.GenesisHash.Equal(hash) { t.Fatalf("TestSimnetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, SimnetParams.GenesisHash) @@ -50,7 +50,7 @@ func TestSimnetGenesisBlock(t *testing.T) { func TestDevnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. hash := consensushashing.BlockHash(DevnetParams.GenesisBlock) - if *DevnetParams.GenesisHash != *hash { + if !DevnetParams.GenesisHash.Equal(hash) { t.Fatalf("TestDevnetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", hash, DevnetParams.GenesisHash) diff --git a/domain/dagconfig/params_test.go b/domain/dagconfig/params_test.go index ceb1219b8..3790ed75c 100644 --- a/domain/dagconfig/params_test.go +++ b/domain/dagconfig/params_test.go @@ -35,7 +35,7 @@ func TestNewHashFromStr(t *testing.T) { result := newHashFromStr(test.hexStr) - if *result != *test.expectedHash { + if !result.Equal(test.expectedHash) { t.Errorf("%s: Expected hash: %s, but got %s", test.hexStr, test.expectedHash, result) } }() diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 0cba5cb1b..40dab8a9d 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -467,10 +467,10 @@ func (mp *mempool) removeChainTransaction(tx *consensusexternalapi.DomainTransac // // This function MUST be called with the mempool lock held (for writes). func (mp *mempool) removeDoubleSpends(tx *consensusexternalapi.DomainTransaction) error { - txID := *consensushashing.TransactionID(tx) + txID := consensushashing.TransactionID(tx) for _, txIn := range tx.Inputs { if txRedeemer, ok := mp.mempoolUTXOSet.poolTransactionBySpendingOutpoint(txIn.PreviousOutpoint); ok { - if !(*consensushashing.TransactionID(txRedeemer) == txID) { + if !consensushashing.TransactionID(txRedeemer).Equal(txID) { err := mp.removeTransactionAndItsChainedTransactions(txRedeemer) if err != nil { return err diff --git a/domain/utxoindex/store.go b/domain/utxoindex/store.go index e09a4b1be..67d985038 100644 --- a/domain/utxoindex/store.go +++ b/domain/utxoindex/store.go @@ -25,7 +25,7 @@ func newUTXOIndexStore(database database.Database) *utxoIndexStore { } } -func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint, utxoEntry *externalapi.UTXOEntry) error { +func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error { key := ConvertScriptPublicKeyToString(scriptPublicKey) log.Tracef("Adding outpoint %s:%d to scriptPublicKey %s", outpoint.TransactionID, outpoint.Index, key) @@ -52,7 +52,7 @@ func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.Dom return errors.Errorf("cannot add outpoint %s because it's being added already", outpoint) } - toAddPairsOfKey[*outpoint] = *utxoEntry + toAddPairsOfKey[*outpoint] = utxoEntry log.Tracef("Added outpoint %s:%d to scriptPublicKey %s", outpoint.TransactionID, outpoint.Index, key) diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go index 8e2666fe5..defa4a6bb 100644 --- a/domain/utxoindex/utxoindex.go +++ b/domain/utxoindex/utxoindex.go @@ -126,7 +126,7 @@ func (ui *UTXOIndex) addTransaction(transaction *externalapi.DomainTransaction, log.Tracef("Adding outpoint %s:%d to UTXO index", transactionID, index) outpoint := externalapi.NewDomainOutpoint(transactionID, uint32(index)) utxoEntry := utxo.NewUTXOEntry(transactionOutput.Value, transactionOutput.ScriptPublicKey, isCoinbase, blockBlueScore) - err := ui.store.add(transactionOutput.ScriptPublicKey, outpoint, &utxoEntry) + err := ui.store.add(transactionOutput.ScriptPublicKey, outpoint, utxoEntry) if err != nil { return err } @@ -148,7 +148,7 @@ func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransactio for _, transactionInput := range transaction.Inputs { log.Tracef("Adding outpoint %s:%d to UTXO index", transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) - err := ui.store.add(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint, &transactionInput.UTXOEntry) + err := ui.store.add(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint, transactionInput.UTXOEntry) if err != nil { return err } diff --git a/testing/integration/basic_sync_test.go b/testing/integration/basic_sync_test.go index 0050ebd8c..60eaecfe6 100644 --- a/testing/integration/basic_sync_test.go +++ b/testing/integration/basic_sync_test.go @@ -38,7 +38,7 @@ func TestIntegrationBasicSync(t *testing.T) { } blockHash := consensushashing.BlockHash(block) - if *header.BlockHash() != *blockHash { + if !header.BlockHash().Equal(blockHash) { t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash()) } @@ -49,7 +49,7 @@ func TestIntegrationBasicSync(t *testing.T) { } blockHash = consensushashing.BlockHash(block) - if *header.BlockHash() != *blockHash { + if !header.BlockHash().Equal(blockHash) { t.Errorf("Expected block with hash '%s', but got '%s'", blockHash, header.BlockHash()) } } From 90d4dbcba18b50098d54c31ce5cb2f763b09ef5a Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 23 Dec 2020 09:41:48 +0200 Subject: [PATCH 149/351] Implement a simple CLI wallet (#1261) * Copy over the CLI wallet from Kasparov. * Fix trivial compilation errors. * Reimplement the balance command. * Extract isUTXOSpendable to a separate function. * Reimplement the send command. * Fix bad transaction ID parsing. * Add a missing newline in a log. * Don't use msgTx in send(). * Fix isUTXOSpendable not checking whether a UTXO is of a coinbase transaction. * Add --devnet, --testnet, etc. to command line flags. * In `create`, only print the public key of the active network. * Use coinbase maturity in isUTXOSpendable. * Add a readme. * Fix formatting in readme. --- cmd/wallet/README.md | 19 ++++ cmd/wallet/balance.go | 40 +++++++++ cmd/wallet/common.go | 20 +++++ cmd/wallet/config.go | 85 ++++++++++++++++++ cmd/wallet/create.go | 37 ++++++++ cmd/wallet/main.go | 25 ++++++ cmd/wallet/send.go | 201 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 427 insertions(+) create mode 100644 cmd/wallet/README.md create mode 100644 cmd/wallet/balance.go create mode 100644 cmd/wallet/common.go create mode 100644 cmd/wallet/config.go create mode 100644 cmd/wallet/create.go create mode 100644 cmd/wallet/main.go create mode 100644 cmd/wallet/send.go diff --git a/cmd/wallet/README.md b/cmd/wallet/README.md new file mode 100644 index 000000000..46fb1d98e --- /dev/null +++ b/cmd/wallet/README.md @@ -0,0 +1,19 @@ +WALLET +====== + +## IMPORTANT: + +### This software is for TESTING ONLY. Do NOT use it for handling real money. + +`wallet` is a simple, no-frills wallet software operated via the command line.\ +It is capable of generating wallet key-pairs, printing a wallet's current balance, and sending simple transactions. + + +Usage +----- + +* Create a new wallet key-pair: `wallet create --testnet` +* Print a wallet's current balance: + `wallet balance --testnet --address=kaspatest:000000000000000000000000000000000000000000` +* Send funds to another wallet: + `wallet send --testnet --private-key=0000000000000000000000000000000000000000000000000000000000000000 --send-amount=50 --to-address=kaspatest:000000000000000000000000000000000000000000` \ No newline at end of file diff --git a/cmd/wallet/balance.go b/cmd/wallet/balance.go new file mode 100644 index 000000000..8c0d152fb --- /dev/null +++ b/cmd/wallet/balance.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "github.com/kaspanet/kaspad/infrastructure/network/rpcclient" + + "github.com/kaspanet/kaspad/util" +) + +func balance(conf *balanceConfig) error { + client, err := rpcclient.NewRPCClient(conf.RPCServer) + if err != nil { + return err + } + getUTXOsByAddressesResponse, err := client.GetUTXOsByAddresses([]string{conf.Address}) + if err != nil { + return err + } + virtualSelectedParentBlueScoreResponse, err := client.GetVirtualSelectedParentBlueScore() + if err != nil { + return err + } + virtualSelectedParentBlueScore := virtualSelectedParentBlueScoreResponse.BlueScore + + var availableBalance, pendingBalance uint64 + for _, entry := range getUTXOsByAddressesResponse.Entries { + if isUTXOSpendable(entry, virtualSelectedParentBlueScore, conf.ActiveNetParams.BlockCoinbaseMaturity) { + availableBalance += entry.UTXOEntry.Amount + } else { + pendingBalance += entry.UTXOEntry.Amount + } + } + + fmt.Printf("Balance:\t\tKAS %f\n", float64(availableBalance)/util.SompiPerKaspa) + if pendingBalance > 0 { + fmt.Printf("Pending balance:\tKAS %f\n", float64(pendingBalance)/util.SompiPerKaspa) + } + + return nil +} diff --git a/cmd/wallet/common.go b/cmd/wallet/common.go new file mode 100644 index 000000000..df98f193f --- /dev/null +++ b/cmd/wallet/common.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + "github.com/kaspanet/kaspad/app/appmessage" + "os" +) + +func isUTXOSpendable(entry *appmessage.UTXOsByAddressesEntry, virtualSelectedParentBlueScore uint64, coinbaseMaturity uint64) bool { + if !entry.UTXOEntry.IsCoinbase { + return true + } + blockBlueScore := entry.UTXOEntry.BlockBlueScore + return blockBlueScore+coinbaseMaturity < virtualSelectedParentBlueScore +} + +func printErrorAndExit(err error) { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) +} diff --git a/cmd/wallet/config.go b/cmd/wallet/config.go new file mode 100644 index 000000000..4571ee623 --- /dev/null +++ b/cmd/wallet/config.go @@ -0,0 +1,85 @@ +package main + +import ( + "github.com/kaspanet/kaspad/infrastructure/config" + "github.com/pkg/errors" + "os" + + "github.com/jessevdk/go-flags" +) + +const ( + createSubCmd = "create" + balanceSubCmd = "balance" + sendSubCmd = "send" +) + +type createConfig struct { + config.NetworkFlags +} + +type balanceConfig struct { + RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"` + Address string `long:"address" short:"d" description:"The public address to check the balance of" required:"true"` + config.NetworkFlags +} + +type sendConfig struct { + RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"` + PrivateKey string `long:"private-key" short:"k" description:"The private key of the sender (encoded in hex)" required:"true"` + ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"` + SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"` + config.NetworkFlags +} + +func parseCommandLine() (subCommand string, config interface{}) { + cfg := &struct{}{} + parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag) + + createConf := &createConfig{} + parser.AddCommand(createSubCmd, "Creates a new wallet", + "Creates a private key and 3 public addresses, one for each of MainNet, TestNet and DevNet", createConf) + + balanceConf := &balanceConfig{} + parser.AddCommand(balanceSubCmd, "Shows the balance of a public address", + "Shows the balance for a public address in Kaspa", balanceConf) + + sendConf := &sendConfig{} + parser.AddCommand(sendSubCmd, "Sends a Kaspa transaction to a public address", + "Sends a Kaspa transaction to a public address", sendConf) + + _, err := parser.Parse() + + if err != nil { + var flagsErr *flags.Error + if ok := errors.As(err, &flagsErr); ok && flagsErr.Type == flags.ErrHelp { + os.Exit(0) + } else { + os.Exit(1) + } + return "", nil + } + + switch parser.Command.Active.Name { + case createSubCmd: + err := createConf.ResolveNetwork(parser) + if err != nil { + printErrorAndExit(err) + } + config = createConf + case balanceSubCmd: + err := balanceConf.ResolveNetwork(parser) + if err != nil { + printErrorAndExit(err) + } + config = balanceConf + case sendSubCmd: + err := sendConf.ResolveNetwork(parser) + if err != nil { + printErrorAndExit(err) + } + config = sendConf + } + + return parser.Command.Active.Name, config +} diff --git a/cmd/wallet/create.go b/cmd/wallet/create.go new file mode 100644 index 000000000..99edebd30 --- /dev/null +++ b/cmd/wallet/create.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/util" + "github.com/pkg/errors" +) + +func create(conf *createConfig) error { + privateKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + return errors.Wrap(err, "Failed to generate private key") + } + + fmt.Println("This is your private key, granting access to all wallet funds. Keep it safe. Use it only when sending Kaspa.") + fmt.Printf("Private key (hex):\t%s\n\n", privateKey.SerializePrivateKey()) + + fmt.Println("This is your public address, where money is to be sent.") + publicKey, err := privateKey.SchnorrPublicKey() + if err != nil { + return errors.Wrap(err, "Failed to generate public key") + } + publicKeySerialized, err := publicKey.Serialize() + if err != nil { + return errors.Wrap(err, "Failed to serialize public key") + } + + addr, err := util.NewAddressPubKeyHashFromPublicKey(publicKeySerialized[:], conf.ActiveNetParams.Prefix) + if err != nil { + return errors.Wrap(err, "Failed to generate p2pkh address") + } + fmt.Printf("Address (%s):\t%s\n", conf.ActiveNetParams.Name, addr) + + return nil +} diff --git a/cmd/wallet/main.go b/cmd/wallet/main.go new file mode 100644 index 000000000..b84eec163 --- /dev/null +++ b/cmd/wallet/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "github.com/pkg/errors" +) + +func main() { + subCmd, config := parseCommandLine() + + var err error + switch subCmd { + case createSubCmd: + err = create(config.(*createConfig)) + case balanceSubCmd: + err = balance(config.(*balanceConfig)) + case sendSubCmd: + err = send(config.(*sendConfig)) + default: + err = errors.Errorf("Unknown sub-command '%s'\n", subCmd) + } + + if err != nil { + printErrorAndExit(err) + } +} diff --git a/cmd/wallet/send.go b/cmd/wallet/send.go new file mode 100644 index 000000000..b757cbaf2 --- /dev/null +++ b/cmd/wallet/send.go @@ -0,0 +1,201 @@ +package main + +import ( + "encoding/hex" + "fmt" + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/infrastructure/network/rpcclient" + "github.com/kaspanet/kaspad/util" + "github.com/pkg/errors" +) + +const feeSompis uint64 = 1000 + +func send(conf *sendConfig) error { + toAddress, err := util.DecodeAddress(conf.ToAddress, conf.ActiveNetParams.Prefix) + if err != nil { + return err + } + + keyPair, publicKey, err := parsePrivateKey(conf.PrivateKey) + if err != nil { + return err + } + + serializedPublicKey, err := publicKey.Serialize() + if err != nil { + return err + } + fromAddress, err := util.NewAddressPubKeyHashFromPublicKey(serializedPublicKey[:], conf.ActiveNetParams.Prefix) + if err != nil { + return err + } + + client, err := rpcclient.NewRPCClient(conf.RPCServer) + if err != nil { + return err + } + utxos, err := fetchSpendableUTXOs(conf, client, fromAddress.String()) + if err != nil { + return err + } + + sendAmountSompi := uint64(conf.SendAmount * util.SompiPerKaspa) + totalToSend := sendAmountSompi + feeSompis + + selectedUTXOs, changeSompi, err := selectUTXOs(utxos, totalToSend) + if err != nil { + return err + } + + rpcTransaction, err := generateTransaction(keyPair, selectedUTXOs, sendAmountSompi, changeSompi, toAddress, fromAddress) + if err != nil { + return err + } + + transactionID, err := sendTransaction(client, rpcTransaction) + if err != nil { + return err + } + + fmt.Println("Transaction was sent successfully") + fmt.Printf("Transaction ID: \t%s\n", transactionID) + + return nil +} + +func parsePrivateKey(privateKeyHex string) (*secp256k1.SchnorrKeyPair, *secp256k1.SchnorrPublicKey, error) { + privateKeyBytes, err := hex.DecodeString(privateKeyHex) + if err != nil { + return nil, nil, errors.Wrap(err, "Error parsing private key hex") + } + keyPair, err := secp256k1.DeserializePrivateKeyFromSlice(privateKeyBytes) + if err != nil { + return nil, nil, errors.Wrap(err, "Error deserializing private key") + } + publicKey, err := keyPair.SchnorrPublicKey() + if err != nil { + return nil, nil, errors.Wrap(err, "Error generating public key") + } + return keyPair, publicKey, nil +} + +func fetchSpendableUTXOs(conf *sendConfig, client *rpcclient.RPCClient, address string) ([]*appmessage.UTXOsByAddressesEntry, error) { + getUTXOsByAddressesResponse, err := client.GetUTXOsByAddresses([]string{address}) + if err != nil { + return nil, err + } + virtualSelectedParentBlueScoreResponse, err := client.GetVirtualSelectedParentBlueScore() + if err != nil { + return nil, err + } + virtualSelectedParentBlueScore := virtualSelectedParentBlueScoreResponse.BlueScore + + spendableUTXOs := make([]*appmessage.UTXOsByAddressesEntry, 0) + for _, entry := range getUTXOsByAddressesResponse.Entries { + if !isUTXOSpendable(entry, virtualSelectedParentBlueScore, conf.ActiveNetParams.BlockCoinbaseMaturity) { + continue + } + spendableUTXOs = append(spendableUTXOs, entry) + } + return spendableUTXOs, nil +} + +func selectUTXOs(utxos []*appmessage.UTXOsByAddressesEntry, totalToSpend uint64) ( + selectedUTXOs []*appmessage.UTXOsByAddressesEntry, changeSompi uint64, err error) { + + selectedUTXOs = []*appmessage.UTXOsByAddressesEntry{} + totalValue := uint64(0) + + for _, utxo := range utxos { + selectedUTXOs = append(selectedUTXOs, utxo) + totalValue += utxo.UTXOEntry.Amount + + if totalValue >= totalToSpend { + break + } + } + + if totalValue < totalToSpend { + return nil, 0, errors.Errorf("Insufficient funds for send: %f required, while only %f available", + float64(totalToSpend)/util.SompiPerKaspa, float64(totalValue)/util.SompiPerKaspa) + } + + return selectedUTXOs, totalValue - totalToSpend, nil +} + +func generateTransaction(keyPair *secp256k1.SchnorrKeyPair, selectedUTXOs []*appmessage.UTXOsByAddressesEntry, + sompisToSend uint64, change uint64, toAddress util.Address, + fromAddress util.Address) (*appmessage.RPCTransaction, error) { + + inputs := make([]*externalapi.DomainTransactionInput, len(selectedUTXOs)) + for i, utxo := range selectedUTXOs { + outpointTransactionIDBytes, err := hex.DecodeString(utxo.Outpoint.TransactionID) + if err != nil { + return nil, err + } + outpointTransactionID, err := transactionid.FromBytes(outpointTransactionIDBytes) + if err != nil { + return nil, err + } + outpoint := externalapi.DomainOutpoint{ + TransactionID: *outpointTransactionID, + Index: utxo.Outpoint.Index, + } + inputs[i] = &externalapi.DomainTransactionInput{PreviousOutpoint: outpoint} + } + + toScript, err := txscript.PayToAddrScript(toAddress) + if err != nil { + return nil, err + } + mainOutput := &externalapi.DomainTransactionOutput{ + Value: sompisToSend, + ScriptPublicKey: toScript, + } + fromScript, err := txscript.PayToAddrScript(fromAddress) + if err != nil { + return nil, err + } + changeOutput := &externalapi.DomainTransactionOutput{ + Value: change, + ScriptPublicKey: fromScript, + } + outputs := []*externalapi.DomainTransactionOutput{mainOutput, changeOutput} + + domainTransaction := &externalapi.DomainTransaction{ + Version: constants.TransactionVersion, + Inputs: inputs, + Outputs: outputs, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + Gas: 0, + Payload: nil, + PayloadHash: externalapi.DomainHash{}, + } + + for i, input := range domainTransaction.Inputs { + signatureScript, err := txscript.SignatureScript(domainTransaction, i, fromScript, txscript.SigHashAll, keyPair) + if err != nil { + return nil, err + } + input.SignatureScript = signatureScript + } + + rpcTransaction := appmessage.DomainTransactionToRPCTransaction(domainTransaction) + return rpcTransaction, nil +} + +func sendTransaction(client *rpcclient.RPCClient, rpcTransaction *appmessage.RPCTransaction) (string, error) { + submitTransactionResponse, err := client.SubmitTransaction(rpcTransaction) + if err != nil { + return "", errors.Wrapf(err, "error submitting transaction") + } + return submitTransactionResponse.TransactionID, nil +} From 43c00f5e7f0a661a1e6dc4a3549818ba5902cbc6 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 23 Dec 2020 10:00:14 +0200 Subject: [PATCH 150/351] Remove the sorting requirement from BlueWindow (#1266) * Remove the requirement for sorting in BlueWindow * Sort the BlueWindow in window_test --- .../processes/dagtraversalmanager/window.go | 9 +-------- .../dagtraversalmanager/window_test.go | 17 +++++++++++++++++ .../processes/difficultymanager/blockwindow.go | 15 ++++++++++++--- .../difficultymanager/difficultymanager.go | 6 +++--- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/domain/consensus/processes/dagtraversalmanager/window.go b/domain/consensus/processes/dagtraversalmanager/window.go index 05e8fa10b..b2c6439c9 100644 --- a/domain/consensus/processes/dagtraversalmanager/window.go +++ b/domain/consensus/processes/dagtraversalmanager/window.go @@ -1,13 +1,11 @@ package dagtraversalmanager import ( - "sort" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) // blueBlockWindow returns a blockWindow of the given size that contains the -// blues in the past of startindNode, sorted by GHOSTDAG order. +// blues in the past of startindNode, the sorting is unspecified. // If the number of blues in the past of startingNode is less then windowSize, // the window will be padded by genesis blocks to achieve a size of windowSize. func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) { @@ -63,11 +61,6 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash } } - // a heap is not a sorted list, and the interface promises to be sorted so we now need to sort this - sort.Slice(windowHeap.impl.slice, func(i, j int) bool { - return windowHeap.impl.slice[j].less(windowHeap.impl.slice[i], dtm.ghostdagManager) - }) - window := make([]*externalapi.DomainHash, 0, windowSize) for _, b := range windowHeap.impl.slice { window = append(window, b.hash) diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 1f5922ccc..dca6a4d1b 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -1,7 +1,9 @@ package dagtraversalmanager_test import ( + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "reflect" + "sort" "testing" "github.com/kaspanet/kaspad/domain/consensus" @@ -343,6 +345,7 @@ func TestBlueBlockWindow(t *testing.T) { if err != nil { t.Fatalf("BlueWindow: %s", err) } + sortWindow(t, tc, window) if err := checkWindowIDs(window, blockData.expectedWindowWithGenesisPadding, idByBlockMap); err != nil { t.Errorf("Unexpected values for window for block %s: %s", blockData.id, err) } @@ -350,6 +353,20 @@ func TestBlueBlockWindow(t *testing.T) { }) } +func sortWindow(t *testing.T, tc testapi.TestConsensus, window []*externalapi.DomainHash) { + sort.Slice(window, func(i, j int) bool { + ghostdagDataI, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), window[i]) + if err != nil { + t.Fatalf("Failed getting ghostdag data for %s", err) + } + ghostdagDataJ, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), window[j]) + if err != nil { + t.Fatalf("Failed getting ghostdag data for %s", err) + } + return !tc.GHOSTDAGManager().Less(window[i], ghostdagDataI, window[j], ghostdagDataJ) + }) +} + func checkWindowIDs(window []*externalapi.DomainHash, expectedIDs []string, idByBlockMap map[externalapi.DomainHash]string) error { ids := make([]string, len(window)) for i, node := range window { diff --git a/domain/consensus/processes/difficultymanager/blockwindow.go b/domain/consensus/processes/difficultymanager/blockwindow.go index 4d25cab01..2fd458258 100644 --- a/domain/consensus/processes/difficultymanager/blockwindow.go +++ b/domain/consensus/processes/difficultymanager/blockwindow.go @@ -29,7 +29,7 @@ func (dm *difficultyManager) getDifficultyBlock(blockHash *externalapi.DomainHas } // blueBlockWindow returns a blockWindow of the given size that contains the -// blues in the past of startindNode, sorted by GHOSTDAG order. +// blues in the past of startindNode, the sorting is unspecified. // If the number of blues in the past of startingNode is less then windowSize, // the window will be padded by genesis blocks to achieve a size of windowSize. func (dm *difficultyManager) blueBlockWindow(startingNode *externalapi.DomainHash, windowSize int) (blockWindow, error) { @@ -49,20 +49,29 @@ func (dm *difficultyManager) blueBlockWindow(startingNode *externalapi.DomainHas return window, nil } -func (window blockWindow) minMaxTimestamps() (min, max int64) { +func (window blockWindow) minMaxTimestamps() (min, max int64, minIndex, maxIndex int) { min = math.MaxInt64 + minIndex = math.MaxInt64 max = 0 - for _, block := range window { + maxIndex = 0 + for i, block := range window { if block.timeInMilliseconds < min { min = block.timeInMilliseconds + minIndex = i } if block.timeInMilliseconds > max { max = block.timeInMilliseconds + maxIndex = i } } return } +func (window *blockWindow) remove(n int) { + (*window)[n] = (*window)[len(*window)-1] + *window = (*window)[:len(*window)-1] +} + func (window blockWindow) averageTarget(averageTarget *big.Int) { averageTarget.SetInt64(0) diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index c1e028562..3d75318c0 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -100,14 +100,14 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas } // Fetch window of dag.difficultyAdjustmentWindowSize + 1 so we can have dag.difficultyAdjustmentWindowSize block intervals - timestampsWindow, err := dm.blueBlockWindow(bluestParent, dm.difficultyAdjustmentWindowSize+1) + targetsWindow, err := dm.blueBlockWindow(bluestParent, dm.difficultyAdjustmentWindowSize+1) if err != nil { return 0, err } - windowMinTimestamp, windowMaxTimeStamp := timestampsWindow.minMaxTimestamps() + windowMinTimestamp, windowMaxTimeStamp, windowsMinIndex, _ := targetsWindow.minMaxTimestamps() // Remove the last block from the window so to calculate the average target of dag.difficultyAdjustmentWindowSize blocks - targetsWindow := timestampsWindow[:dm.difficultyAdjustmentWindowSize] + targetsWindow.remove(windowsMinIndex) // Calculate new target difficulty as: // averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize)) From 729e3db145282575803fa1b76a53613719475802 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 23 Dec 2020 11:37:39 +0200 Subject: [PATCH 151/351] Pruning calculation changes (#1250) * 1) Calculate pruning point incrementally 2) Add IsValidPruningPoint to pruning manager and consensus 3) Use reachability children for selected child iterator * Add request IBD root hash flow * Fix UpdatePruningPointByVirtual and IsValidPruningPoint * Regenerate messages.pb.go * Make the pruning point the earliest chain block with finality interval higher than the previous pruning point * Fix merge errors --- app/appmessage/message.go | 4 + app/appmessage/p2p_ibdrootnotfound.go | 4 +- app/appmessage/p2p_msgibdroothash.go | 26 + app/appmessage/p2p_requestibdroothash.go | 22 + .../handle_ibd_root_hash_requests.go | 49 + app/protocol/flows/blockrelay/ibd.go | 97 +- app/protocol/protocol.go | 9 +- domain/consensus/consensus.go | 11 + .../pruningstore/pruningstore.go | 73 +- domain/consensus/factory.go | 1 + .../consensus/model/externalapi/consensus.go | 2 + domain/consensus/model/externalapi/sync.go | 22 +- .../externalapi/sync_equal_clone_test.go | 27 - .../interface_datastructures_pruningstore.go | 5 +- .../interface_processes_pruningmanager.go | 2 +- .../validateandinsertpruningpoint.go | 11 +- .../update_pruning_utxo_set.go | 5 +- .../dagtraversalmanager.go | 17 +- .../selected_child_iterator.go | 23 +- .../processes/pruningmanager/pruning_test.go | 30 +- .../pruningmanager/pruningmanager.go | 156 +- .../testdata/chain-for-test-pruning.json | 9000 +++++++++++++++++ .../processes/syncmanager/syncinfo.go | 33 +- domain/consensus/ruleerrors/rule_error.go | 2 + .../grpcserver/protowire/messages.pb.go | 3578 +++---- .../grpcserver/protowire/messages.proto | 13 + .../grpcserver/protowire/p2p_ibd_root_hash.go | 19 + .../protowire/p2p_request_ibd_root_hash.go | 11 + .../server/grpcserver/protowire/wire.go | 16 + 29 files changed, 11387 insertions(+), 1881 deletions(-) create mode 100644 app/appmessage/p2p_msgibdroothash.go create mode 100644 app/appmessage/p2p_requestibdroothash.go create mode 100644 app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 45b2a9918..117762f02 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -55,6 +55,8 @@ const ( CmdIBDRootUTXOSetAndBlock CmdRequestIBDBlocks CmdIBDRootNotFound + CmdRequestIBDRootHash + CmdIBDRootHash // rpc CmdGetCurrentNetworkRequestMessage @@ -145,6 +147,8 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdIBDRootUTXOSetAndBlock: "IBDRootUTXOSetAndBlock", CmdRequestIBDBlocks: "RequestIBDBlocks", CmdIBDRootNotFound: "IBDRootNotFound", + CmdRequestIBDRootHash: "IBDRequestIBDRootHash", + CmdIBDRootHash: "IBDIBDRootHash", } // RPCMessageCommandToString maps all MessageCommands to their string representation diff --git a/app/appmessage/p2p_ibdrootnotfound.go b/app/appmessage/p2p_ibdrootnotfound.go index 8a57e5ad6..2e7adf8dc 100644 --- a/app/appmessage/p2p_ibdrootnotfound.go +++ b/app/appmessage/p2p_ibdrootnotfound.go @@ -17,6 +17,6 @@ func (msg *MsgIBDRootNotFound) Command() MessageCommand { // NewMsgIBDRootNotFound returns a new kaspa IBDRootNotFound message that conforms to the // Message interface. -func NewMsgIBDRootNotFound() *MsgDoneHeaders { - return &MsgDoneHeaders{} +func NewMsgIBDRootNotFound() *MsgIBDRootNotFound { + return &MsgIBDRootNotFound{} } diff --git a/app/appmessage/p2p_msgibdroothash.go b/app/appmessage/p2p_msgibdroothash.go new file mode 100644 index 000000000..1b21ac65d --- /dev/null +++ b/app/appmessage/p2p_msgibdroothash.go @@ -0,0 +1,26 @@ +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgIBDRootHash implements the Message interface and represents a kaspa +// IBDRootHash message. It is used as a reply to IBD root hash requests. +type MsgIBDRootHash struct { + baseMessage + Hash *externalapi.DomainHash +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgIBDRootHash) Command() MessageCommand { + return CmdIBDRootHash +} + +// NewMsgIBDRootHash returns a new kaspa IBDRootHash message that conforms to +// the Message interface. See MsgIBDRootHash for details. +func NewMsgIBDRootHash(hash *externalapi.DomainHash) *MsgIBDRootHash { + return &MsgIBDRootHash{ + Hash: hash, + } +} diff --git a/app/appmessage/p2p_requestibdroothash.go b/app/appmessage/p2p_requestibdroothash.go new file mode 100644 index 000000000..0c8139568 --- /dev/null +++ b/app/appmessage/p2p_requestibdroothash.go @@ -0,0 +1,22 @@ +package appmessage + +// MsgRequestIBDRootHash implements the Message interface and represents a kaspa +// MsgRequestIBDRootHash message. It is used to request the IBD root hash +// from a peer during IBD. +// +// This message has no payload. +type MsgRequestIBDRootHash struct { + baseMessage +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgRequestIBDRootHash) Command() MessageCommand { + return CmdRequestIBDRootHash +} + +// NewMsgRequestIBDRootHash returns a new kaspa RequestIBDRootHash message that conforms to the +// Message interface. +func NewMsgRequestIBDRootHash() *MsgRequestIBDRootHash { + return &MsgRequestIBDRootHash{} +} diff --git a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go new file mode 100644 index 000000000..1a63d0403 --- /dev/null +++ b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go @@ -0,0 +1,49 @@ +package blockrelay + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleIBDRootHashRequestsFlowContext is the interface for the context needed for the handleIBDRootHashRequestsFlow flow. +type HandleIBDRootHashRequestsFlowContext interface { + Domain() domain.Domain +} + +type handleIBDRootHashRequestsFlow struct { + HandleIBDRootHashRequestsFlowContext + incomingRoute, outgoingRoute *router.Route +} + +// HandleIBDRootHashRequests listens to appmessage.MsgRequestIBDRootHash messages and sends +// the IBD root hash as response. +func HandleIBDRootHashRequests(context HandleIBDRootHashRequestsFlowContext, incomingRoute, + outgoingRoute *router.Route) error { + flow := &handleIBDRootHashRequestsFlow{ + HandleIBDRootHashRequestsFlowContext: context, + incomingRoute: incomingRoute, + outgoingRoute: outgoingRoute, + } + + return flow.start() +} + +func (flow *handleIBDRootHashRequestsFlow) start() error { + for { + _, err := flow.incomingRoute.Dequeue() + if err != nil { + return err + } + + pruningPoint, err := flow.Domain().Consensus().PruningPoint() + if err != nil { + return err + } + + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootHash(pruningPoint)) + if err != nil { + return err + } + } +} diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index a43c2e379..b697a8af4 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -30,22 +30,55 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain log.Debugf("Finished downloading headers up to %s", highHash) // Fetch the UTXO set if we don't already have it - log.Debugf("Downloading the IBD root UTXO set under highHash %s", highHash) - syncInfo, err := flow.Domain().Consensus().GetSyncInfo() + log.Debugf("Checking if there's a new pruning point under %s", highHash) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHash()) if err != nil { return err } - if syncInfo.IsAwaitingUTXOSet { - found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash) + + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return err + } + + msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHash) + if !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) + } + + blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgIBDRootHash.Hash) + if err != nil { + return err + } + + if blockInfo.BlockStatus == externalapi.StatusHeaderOnly { + isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) if err != nil { return err } - if !found { - log.Infof("Cannot download the IBD root UTXO set under highHash %s", highHash) + + if !isValid { + log.Infof("The suggested pruning point is incompatible to this node DAG, so stopping IBD with this" + + " peer") return nil } + + log.Info("Fetching the pruning point UTXO set") + succeed, err := flow.fetchMissingUTXOSet(msgIBDRootHash.Hash) + if err != nil { + return err + } + + if !succeed { + log.Infof("Couldn't successfully fetch the pruning point UTXO set. Stopping IBD.") + return nil + } + + log.Info("Fetched the new pruning point UTXO set") + } else { + log.Debugf("Already has the block data of the new suggested pruning point %s", msgIBDRootHash.Hash) } - log.Debugf("Finished downloading the IBD root UTXO set under highHash %s", highHash) // Fetch the block bodies log.Debugf("Downloading block bodies up to %s", highHash) @@ -58,6 +91,40 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain return nil } +func (flow *handleRelayInvsFlow) fetchUTXOSetIfMissing() (bool, error) { + err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHash()) + if err != nil { + return false, err + } + + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return false, err + } + + msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHash) + if !ok { + return false, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) + } + + isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) + if err != nil { + return false, err + } + + if !isValid { + return false, nil + } + + found, err := flow.fetchMissingUTXOSet(msgIBDRootHash.Hash) + if err != nil { + return false, err + } + + return found, nil +} + func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) error { log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) @@ -207,21 +274,13 @@ func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.Do err = flow.Domain().Consensus().ValidateAndInsertPruningPoint(block, utxoSet) if err != nil { + // TODO: Find a better way to deal with finality conflicts. + if errors.Is(err, ruleerrors.ErrSuggestedPruningViolatesFinality) { + return false, 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 } diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 6d7527744..1e00f961e 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -136,7 +136,7 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, - appmessage.CmdHeader}, isStopping, errChan, + appmessage.CmdHeader, appmessage.CmdIBDRootHash}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) @@ -176,6 +176,13 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * return blockrelay.HandleIBDBlockRequests(m.context, incomingRoute, outgoingRoute) }, ), + + m.registerFlow("HandleIBDRootHashRequests", router, + []appmessage.MessageCommand{appmessage.CmdRequestIBDRootHash}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.HandleIBDRootHashRequests(m.context, incomingRoute, outgoingRoute) + }, + ), } } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index d4b01df9a..644594313 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -184,6 +184,13 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi return serializedUTXOSet, nil } +func (s *consensus) PruningPoint() (*externalapi.DomainHash, error) { + s.lock.Lock() + defer s.lock.Unlock() + + return s.pruningStore.PruningPoint(s.databaseContext) +} + func (s *consensus) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { s.lock.Lock() defer s.lock.Unlock() @@ -259,6 +266,10 @@ func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { return s.syncManager.GetSyncInfo() } +func (s *consensus) IsValidPruningPoint(block *externalapi.DomainHash) (bool, error) { + return s.pruningManager.IsValidPruningPoint(block) +} + func (s *consensus) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { s.lock.Lock() defer s.lock.Unlock() diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index 646f6bbac..ba69a749a 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -9,13 +9,54 @@ import ( ) var pruningBlockHashKey = dbkeys.MakeBucket().Key([]byte("pruning-block-hash")) -var pruningSerializedUTXOSetkey = dbkeys.MakeBucket().Key([]byte("pruning-utxo-set")) +var candidatePruningPointHashKey = dbkeys.MakeBucket().Key([]byte("candidate-pruning-point-hash")) +var pruningSerializedUTXOSetKey = dbkeys.MakeBucket().Key([]byte("pruning-utxo-set")) // pruningStore represents a store for the current pruning state type pruningStore struct { - pruningPointStaging *externalapi.DomainHash - serializedUTXOSetStaging []byte - pruningPointCache *externalapi.DomainHash + pruningPointStaging *externalapi.DomainHash + pruningPointCandidateStaging *externalapi.DomainHash + serializedUTXOSetStaging []byte + pruningPointCandidateCache *externalapi.DomainHash + pruningPointCache *externalapi.DomainHash +} + +func (ps *pruningStore) StagePruningPointCandidate(candidate *externalapi.DomainHash) { + ps.pruningPointCandidateStaging = candidate.Clone() +} + +func (ps *pruningStore) PruningPointCandidate(dbContext model.DBReader) (*externalapi.DomainHash, error) { + if ps.pruningPointCandidateStaging != nil { + return ps.pruningPointCandidateStaging, nil + } + + if ps.pruningPointCandidateCache != nil { + return ps.pruningPointCandidateCache, nil + } + + candidateBytes, err := dbContext.Get(pruningBlockHashKey) + if err != nil { + return nil, err + } + + candidate, err := ps.deserializePruningPoint(candidateBytes) + if err != nil { + return nil, err + } + ps.pruningPointCandidateCache = candidate + return candidate, nil +} + +func (ps *pruningStore) HasPruningPointCandidate(dbContext model.DBReader) (bool, error) { + if ps.pruningPointCandidateStaging != nil { + return true, nil + } + + if ps.pruningPointCandidateCache != nil { + return true, nil + } + + return dbContext.Has(candidatePruningPointHashKey) } // New instantiates a new PruningStore @@ -24,7 +65,7 @@ func New() model.PruningStore { } // Stage stages the pruning state -func (ps *pruningStore) Stage(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) { +func (ps *pruningStore) StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) { ps.pruningPointStaging = pruningPointBlockHash.Clone() ps.serializedUTXOSetStaging = pruningPointUTXOSetBytes } @@ -40,7 +81,7 @@ func (ps *pruningStore) Discard() { func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { if ps.pruningPointStaging != nil { - pruningPointBytes, err := ps.serializePruningPoint(ps.pruningPointStaging) + pruningPointBytes, err := ps.serializeHash(ps.pruningPointStaging) if err != nil { return err } @@ -51,12 +92,24 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { ps.pruningPointCache = ps.pruningPointStaging } + if ps.pruningPointCandidateStaging != nil { + candidateBytes, err := ps.serializeHash(ps.pruningPointCandidateStaging) + if err != nil { + return err + } + err = dbTx.Put(candidatePruningPointHashKey, candidateBytes) + if err != nil { + return err + } + ps.pruningPointCandidateCache = ps.pruningPointCandidateStaging + } + if ps.serializedUTXOSetStaging != nil { utxoSetBytes, err := ps.serializeUTXOSetBytes(ps.serializedUTXOSetStaging) if err != nil { return err } - err = dbTx.Put(pruningSerializedUTXOSetkey, utxoSetBytes) + err = dbTx.Put(pruningSerializedUTXOSetKey, utxoSetBytes) if err != nil { return err } @@ -95,7 +148,7 @@ func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader) return ps.serializedUTXOSetStaging, nil } - dbPruningPointUTXOSetBytes, err := dbContext.Get(pruningSerializedUTXOSetkey) + dbPruningPointUTXOSetBytes, err := dbContext.Get(pruningSerializedUTXOSetKey) if err != nil { return nil, err } @@ -107,8 +160,8 @@ func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader) return pruningPointUTXOSet, nil } -func (ps *pruningStore) serializePruningPoint(pruningPoint *externalapi.DomainHash) ([]byte, error) { - return proto.Marshal(serialization.DomainHashToDbHash(pruningPoint)) +func (ps *pruningStore) serializeHash(hash *externalapi.DomainHash) ([]byte, error) { + return proto.Marshal(serialization.DomainHashToDbHash(hash)) } func (ps *pruningStore) deserializePruningPoint(pruningPointBytes []byte) (*externalapi.DomainHash, error) { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 21e8bcd8a..934a060e2 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -105,6 +105,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager, dagTopologyManager, ghostdagDataStore, + reachabilityDataStore, ghostdagManager) pastMedianTimeManager := pastmediantimemanager.New( dagParams.TimestampDeviationTolerance, diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 8cebe6634..0806fb2dd 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -14,6 +14,7 @@ type Consensus interface { GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error) GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error) + PruningPoint() (*DomainHash, error) ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error GetVirtualSelectedParent() (*DomainBlock, error) CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) @@ -21,5 +22,6 @@ type Consensus interface { GetSyncInfo() (*SyncInfo, error) Tips() ([]*DomainHash, error) GetVirtualInfo() (*VirtualInfo, error) + IsValidPruningPoint(block *DomainHash) (bool, error) GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) } diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index d1b717857..797401e9d 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -2,25 +2,21 @@ package externalapi // SyncInfo holds info about the current sync state of the consensus type SyncInfo struct { - IsAwaitingUTXOSet bool - IBDRootUTXOBlockHash *DomainHash - HeaderCount uint64 - BlockCount uint64 + HeaderCount uint64 + BlockCount uint64 } // Clone returns a clone of SyncInfo func (si *SyncInfo) Clone() *SyncInfo { return &SyncInfo{ - IsAwaitingUTXOSet: si.IsAwaitingUTXOSet, - IBDRootUTXOBlockHash: si.IBDRootUTXOBlockHash.Clone(), - HeaderCount: si.HeaderCount, - BlockCount: si.BlockCount, + HeaderCount: si.HeaderCount, + BlockCount: si.BlockCount, } } // If this doesn't compile, it means the type definition has been changed, so it's // an indication to update Equal and Clone accordingly. -var _ = SyncInfo{false, &DomainHash{}, 0, 0} +var _ = SyncInfo{0, 0} // Equal returns whether si equals to other func (si *SyncInfo) Equal(other *SyncInfo) bool { @@ -28,14 +24,6 @@ func (si *SyncInfo) Equal(other *SyncInfo) bool { return si == other } - if si.IsAwaitingUTXOSet != other.IsAwaitingUTXOSet { - return false - } - - if !si.IBDRootUTXOBlockHash.Equal(other.IBDRootUTXOBlockHash) { - return false - } - if si.HeaderCount != other.HeaderCount { return false } diff --git a/domain/consensus/model/externalapi/sync_equal_clone_test.go b/domain/consensus/model/externalapi/sync_equal_clone_test.go index 4a216c564..d4959aca9 100644 --- a/domain/consensus/model/externalapi/sync_equal_clone_test.go +++ b/domain/consensus/model/externalapi/sync_equal_clone_test.go @@ -8,8 +8,6 @@ import ( func initTestSyncInfoForClone() []*SyncInfo { tests := []*SyncInfo{{ - false, - &DomainHash{1, 2}, 0xF, 0xF}} return tests @@ -32,8 +30,6 @@ func initTestSyncInfoForEqual() []*testSyncInfoStruct { syncInfoToCompareTo: []testSyncInfoToCompare{ { syncInfo: &SyncInfo{ - false, - &DomainHash{1, 2}, 0xF, 0xF}, expectedResult: false, @@ -43,38 +39,17 @@ func initTestSyncInfoForEqual() []*testSyncInfoStruct { }, }}, { baseSyncInfo: &SyncInfo{ - false, - &DomainHash{1, 2}, 0xF, 0xF}, syncInfoToCompareTo: []testSyncInfoToCompare{ { syncInfo: &SyncInfo{ - false, - &DomainHash{1, 2}, 0xF, 0xF}, expectedResult: true, - }, { - syncInfo: &SyncInfo{ - true, - &DomainHash{1, 2}, - 0xF, - 0xF}, - expectedResult: false, }, { syncInfo: &SyncInfo{ - false, - &DomainHash{1, 3}, - 0xF, - 0xF}, - expectedResult: false, - }, - { - syncInfo: &SyncInfo{ - false, - &DomainHash{1, 2}, 0xF1, 0xF}, expectedResult: false, @@ -83,8 +58,6 @@ func initTestSyncInfoForEqual() []*testSyncInfoStruct { expectedResult: false, }, { syncInfo: &SyncInfo{ - false, - &DomainHash{1, 2}, 0xF, 0xF1}, expectedResult: false}, diff --git a/domain/consensus/model/interface_datastructures_pruningstore.go b/domain/consensus/model/interface_datastructures_pruningstore.go index ca9bdab25..da8c47fdf 100644 --- a/domain/consensus/model/interface_datastructures_pruningstore.go +++ b/domain/consensus/model/interface_datastructures_pruningstore.go @@ -5,8 +5,11 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // PruningStore represents a store for the current pruning state type PruningStore interface { Store - Stage(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) + StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) + StagePruningPointCandidate(candidate *externalapi.DomainHash) IsStaged() bool + PruningPointCandidate(dbContext DBReader) (*externalapi.DomainHash, error) + HasPruningPointCandidate(dbContext DBReader) (bool, error) PruningPoint(dbContext DBReader) (*externalapi.DomainHash, error) HasPruningPoint(dbContext DBReader) (bool, error) PruningPointSerializedUTXOSet(dbContext DBReader) ([]byte, error) diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index 6df77895b..72c4d76dc 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -5,5 +5,5 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // PruningManager resolves and manages the current pruning point type PruningManager interface { UpdatePruningPointByVirtual() error - CalculatePruningPointByHeaderSelectedTip() (*externalapi.DomainHash, error) + IsValidPruningPoint(block *externalapi.DomainHash) (bool, error) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go index 826b6632b..db0144053 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go @@ -10,16 +10,15 @@ import ( 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() + newPruningPointHash := consensushashing.BlockHash(newPruningPoint) + isValidPruningPoint, err := bp.pruningManager.IsValidPruningPoint(newPruningPointHash) if err != nil { return err } - newPruningPointHash := consensushashing.BlockHash(newPruningPoint) - - if !expectedNewPruningPointHash.Equal(newPruningPointHash) { - return errors.Wrapf(ruleerrors.ErrUnexpectedPruningPoint, "expected pruning point %s but got %s", - expectedNewPruningPointHash, newPruningPointHash) + if !isValidPruningPoint { + return errors.Wrapf(ruleerrors.ErrUnexpectedPruningPoint, "%s is not a valid pruning point", + newPruningPointHash) } // We have to validate the pruning point block before we set the new pruning point in consensusStateManager. diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index a01c05672..f0a0d195b 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -41,7 +41,8 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap if isViolatingFinality { log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash) - return nil + return errors.Wrapf(ruleerrors.ErrSuggestedPruningViolatesFinality, "%s cannot be a pruning point because "+ + "it violates finality", newPruningPointHash) } protoUTXOSet := &utxoserialization.ProtoUTXOSet{} @@ -102,7 +103,7 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap } log.Debugf("Staging the new pruning point and its UTXO set") - csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet) + csm.pruningStore.StagePruningPoint(newPruningPointHash, serializedUTXOSet) // Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid // against the provided UTXO set. diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 762580ee4..3c4662bb3 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -12,9 +12,10 @@ import ( type dagTraversalManager struct { databaseContext model.DBReader - dagTopologyManager model.DAGTopologyManager - ghostdagDataStore model.GHOSTDAGDataStore - ghostdagManager model.GHOSTDAGManager + dagTopologyManager model.DAGTopologyManager + ghostdagDataStore model.GHOSTDAGDataStore + reachabilityDataStore model.ReachabilityDataStore + ghostdagManager model.GHOSTDAGManager } // selectedParentIterator implements the `model.BlockIterator` API @@ -45,12 +46,14 @@ func New( databaseContext model.DBReader, dagTopologyManager model.DAGTopologyManager, ghostdagDataStore model.GHOSTDAGDataStore, + reachabilityDataStore model.ReachabilityDataStore, ghostdagManager model.GHOSTDAGManager) model.DAGTraversalManager { return &dagTraversalManager{ - databaseContext: databaseContext, - dagTopologyManager: dagTopologyManager, - ghostdagDataStore: ghostdagDataStore, - ghostdagManager: ghostdagManager, + databaseContext: databaseContext, + dagTopologyManager: dagTopologyManager, + ghostdagDataStore: ghostdagDataStore, + reachabilityDataStore: reachabilityDataStore, + ghostdagManager: ghostdagManager, } } diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index 9db1f12b3..21e9646ef 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -9,21 +9,19 @@ import ( type selectedChildIterator struct { databaseContext model.DBReader dagTopologyManager model.DAGTopologyManager - highHash *externalapi.DomainHash - current *externalapi.DomainHash + + reachabilityDataStore model.ReachabilityDataStore + highHash *externalapi.DomainHash + current *externalapi.DomainHash } func (s *selectedChildIterator) Next() bool { - children, err := s.dagTopologyManager.Children(s.current) + data, err := s.reachabilityDataStore.ReachabilityData(s.databaseContext, s.current) if err != nil { panic(err) } - for _, child := range children { - if child.Equal(model.VirtualBlockHash) { - continue - } - + for _, child := range data.TreeNode.Children { isChildInSelectedParentChainOfHighHash, err := s.dagTopologyManager.IsInSelectedParentChainOf(child, s.highHash) if err != nil { panic(err) @@ -51,9 +49,10 @@ func (dtm *dagTraversalManager) SelectedChildIterator(highHash, lowHash *externa return nil, errors.Errorf("%s is not in the selected parent chain of %s", highHash, lowHash) } return &selectedChildIterator{ - databaseContext: dtm.databaseContext, - dagTopologyManager: dtm.dagTopologyManager, - highHash: highHash, - current: lowHash, + databaseContext: dtm.databaseContext, + dagTopologyManager: dtm.dagTopologyManager, + reachabilityDataStore: dtm.reachabilityDataStore, + highHash: highHash, + current: lowHash, }, nil } diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index d2b150809..16c83ace2 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -26,10 +26,10 @@ type testJSON struct { func TestPruning(t *testing.T) { expectedPruningPointByNet := map[string]map[string]string{ "chain-for-test-pruning.json": { - "kaspa-mainnet": "84", - "kaspa-simnet": "84", - "kaspa-devnet": "84", - "kaspa-testnet": "84", + "kaspa-mainnet": "1582", + "kaspa-simnet": "1582", + "kaspa-devnet": "1582", + "kaspa-testnet": "1582", }, "dag-for-test-pruning.json": { "kaspa-mainnet": "503", @@ -100,9 +100,29 @@ func TestPruning(t *testing.T) { blockIDToHash[dagBlock.ID] = blockHash blockHashToID[*blockHash] = dagBlock.ID + + pruningPoint, err := tc.PruningPoint() + if err != nil { + return err + } + + pruningPointCandidate, err := tc.PruningStore().PruningPointCandidate(tc.DatabaseContext()) + if err != nil { + return err + } + + isValidPruningPoint, err := tc.IsValidPruningPoint(pruningPointCandidate) + if err != nil { + return err + } + + shouldBeValid := *pruningPoint == *pruningPointCandidate + if isValidPruningPoint != shouldBeValid { + t.Fatalf("isValidPruningPoint is %t while expected %t", isValidPruningPoint, shouldBeValid) + } } - pruningPoint, err := tc.PruningStore().PruningPoint(tc.DatabaseContext()) + pruningPoint, err := tc.PruningPoint() if err != nil { t.Fatalf("PruningPoint: %+v", err) } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 1c87d7a81..305255ceb 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -88,7 +88,12 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { } } - currentP, err := pm.pruningStore.PruningPoint(pm.databaseContext) + currentCandidate, err := pm.pruningPointCandidate() + if err != nil { + return err + } + + currentCandidateGHOSTDAGData, err := pm.ghostdagDataStore.Get(pm.databaseContext, currentCandidate) if err != nil { return err } @@ -103,28 +108,71 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { 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 virtualSelectedParent.BlueScore() <= currentPBlueScore+pm.finalityInterval { - return nil - } - - // This means the pruning point is still genesis. - if virtualSelectedParent.BlueScore() <= pm.pruningDepth+pm.finalityInterval { - return nil - } - - // get Virtual(pruningDepth) - newPruningPoint, err := pm.calculatePruningPointFromBlock(model.VirtualBlockHash) + currentPruningPoint, err := pm.pruningStore.PruningPoint(pm.databaseContext) if err != nil { return err } - if !newPruningPoint.Equal(currentP) { + currentPruningPointGHOSTDAGData, err := pm.ghostdagDataStore.Get(pm.databaseContext, currentPruningPoint) + if err != nil { + return err + } + + iterator, err := pm.dagTraversalManager.SelectedChildIterator(virtual.SelectedParent(), currentCandidate) + if err != nil { + return err + } + + // Finding the next pruning point candidate: look for the latest + // selected child of the current candidate that is in depth of at + // least pm.pruningDepth blocks from the virtual selected parent. + // + // Note: Sometimes the current candidate is less than pm.pruningDepth + // from the virtual. This can happen only if the virtual blue score + // got smaller, because virtual blue score is not guaranteed to always + // increase (because sometimes a block with higher blue work can have + // lower blue score). + // In such cases we still keep the same candidate because it's guaranteed + // that a block that was once in depth of pm.pruningDepth cannot be + // reorged without causing a finality conflict first. + newCandidate := currentCandidate + newCandidateGHOSTDAGData := currentCandidateGHOSTDAGData + + newPruningPoint := currentPruningPoint + newPruningPointGHOSTDAGData := currentPruningPointGHOSTDAGData + for iterator.Next() { + selectedChild := iterator.Get() + selectedChildGHOSTDAGData, err := pm.ghostdagDataStore.Get(pm.databaseContext, selectedChild) + if err != nil { + return err + } + + if virtualSelectedParent.BlueScore()-selectedChildGHOSTDAGData.BlueScore() < pm.pruningDepth { + break + } + + newCandidate = selectedChild + newCandidateGHOSTDAGData = selectedChildGHOSTDAGData + + // We move the pruning point every time the candidate's finality score is + // bigger than the current pruning point finality score. + if pm.finalityScore(newCandidateGHOSTDAGData.BlueScore()) > pm.finalityScore(newPruningPointGHOSTDAGData.BlueScore()) { + newPruningPoint = newCandidate + newPruningPointGHOSTDAGData = newCandidateGHOSTDAGData + } + } + + if !newCandidate.Equal(currentCandidate) { + pm.pruningStore.StagePruningPointCandidate(newCandidate) + } + + // We move the pruning point every time the candidate's finality score is + // bigger than the current pruning point finality score. + if pm.finalityScore(newCandidateGHOSTDAGData.BlueScore()) <= pm.finalityScore(currentPruningPointGHOSTDAGData.BlueScore()) { + return nil + } + + if !newPruningPoint.Equal(currentPruningPoint) { err = pm.savePruningPoint(newPruningPoint) if err != nil { return err @@ -214,7 +262,7 @@ func (pm *pruningManager) savePruningPoint(blockHash *externalapi.DomainHash) er if err != nil { return err } - pm.pruningStore.Stage(blockHash, serializedUtxo) + pm.pruningStore.StagePruningPoint(blockHash, serializedUtxo) return nil } @@ -237,28 +285,68 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread return false, nil } -func (pm *pruningManager) CalculatePruningPointByHeaderSelectedTip() (*externalapi.DomainHash, error) { +func (pm *pruningManager) IsValidPruningPoint(block *externalapi.DomainHash) (bool, error) { + if *pm.genesisHash == *block { + return true, nil + } + headersSelectedTip, err := pm.headerSelectedTipStore.HeadersSelectedTip(pm.databaseContext) if err != nil { - return nil, err + return false, err } - return pm.calculatePruningPointFromBlock(headersSelectedTip) + // A pruning point has to be in the selected chain of the headers selected tip. + headersSelectedTipGHOSTDAGData, err := pm.ghostdagDataStore.Get(pm.databaseContext, headersSelectedTip) + if err != nil { + return false, err + } + + isInSelectedParentChainOfHeadersSelectedTip, err := pm.dagTopologyManager.IsInSelectedParentChainOf(block, + headersSelectedTip) + if err != nil { + return false, err + } + + if !isInSelectedParentChainOfHeadersSelectedTip { + return false, nil + } + + ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, block) + if err != nil { + return false, err + } + + // A pruning point has to be at depth of at least pm.pruningDepth + if headersSelectedTipGHOSTDAGData.BlueScore()-ghostdagData.BlueScore() < pm.pruningDepth { + return false, nil + } + + selectedParentGHOSTDAGData, err := pm.ghostdagDataStore.Get(pm.databaseContext, ghostdagData.SelectedParent()) + if err != nil { + return false, err + } + + // A pruning point has to be the lowest chain block with a certain finality score, so + // if the block selected parent has the same finality score it means it cannot be a + // pruning point. + if pm.finalityScore(ghostdagData.BlueScore()) == pm.finalityScore(selectedParentGHOSTDAGData.BlueScore()) { + return false, nil + } + + return true, nil } -func (pm *pruningManager) calculatePruningPointFromBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, blockHash) +func (pm *pruningManager) pruningPointCandidate() (*externalapi.DomainHash, error) { + hasPruningPointCandidate, err := pm.pruningStore.HasPruningPointCandidate(pm.databaseContext) 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 + if !hasPruningPointCandidate { + return pm.genesisHash, nil } - return pm.dagTraversalManager.LowestChainBlockAboveOrEqualToBlueScore(blockHash, targetBlueScore) + + return pm.pruningStore.PruningPointCandidate(pm.databaseContext) } func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error) { @@ -268,3 +356,9 @@ func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error } return proto.Marshal(serializedUtxo) } + +// finalityScore is the number of finality intervals passed since +// the given block. +func (pm *pruningManager) finalityScore(blueScore uint64) uint64 { + return blueScore / pm.finalityInterval +} diff --git a/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json b/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json index 3689af435..9fe696188 100644 --- a/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json +++ b/domain/consensus/processes/pruningmanager/testdata/chain-for-test-pruning.json @@ -2999,6 +2999,9006 @@ "parents": [ "498" ] + }, + { + "id": "500", + "parents": [ + "499" + ] + }, + { + "id": "501", + "parents": [ + "500" + ] + }, + { + "id": "502", + "parents": [ + "501" + ] + }, + { + "id": "503", + "parents": [ + "502" + ] + }, + { + "id": "504", + "parents": [ + "503" + ] + }, + { + "id": "505", + "parents": [ + "504" + ] + }, + { + "id": "506", + "parents": [ + "505" + ] + }, + { + "id": "507", + "parents": [ + "506" + ] + }, + { + "id": "508", + "parents": [ + "507" + ] + }, + { + "id": "509", + "parents": [ + "508" + ] + }, + { + "id": "510", + "parents": [ + "509" + ] + }, + { + "id": "511", + "parents": [ + "510" + ] + }, + { + "id": "512", + "parents": [ + "511" + ] + }, + { + "id": "513", + "parents": [ + "512" + ] + }, + { + "id": "514", + "parents": [ + "513" + ] + }, + { + "id": "515", + "parents": [ + "514" + ] + }, + { + "id": "516", + "parents": [ + "515" + ] + }, + { + "id": "517", + "parents": [ + "516" + ] + }, + { + "id": "518", + "parents": [ + "517" + ] + }, + { + "id": "519", + "parents": [ + "518" + ] + }, + { + "id": "520", + "parents": [ + "519" + ] + }, + { + "id": "521", + "parents": [ + "520" + ] + }, + { + "id": "522", + "parents": [ + "521" + ] + }, + { + "id": "523", + "parents": [ + "522" + ] + }, + { + "id": "524", + "parents": [ + "523" + ] + }, + { + "id": "525", + "parents": [ + "524" + ] + }, + { + "id": "526", + "parents": [ + "525" + ] + }, + { + "id": "527", + "parents": [ + "526" + ] + }, + { + "id": "528", + "parents": [ + "527" + ] + }, + { + "id": "529", + "parents": [ + "528" + ] + }, + { + "id": "530", + "parents": [ + "529" + ] + }, + { + "id": "531", + "parents": [ + "530" + ] + }, + { + "id": "532", + "parents": [ + "531" + ] + }, + { + "id": "533", + "parents": [ + "532" + ] + }, + { + "id": "534", + "parents": [ + "533" + ] + }, + { + "id": "535", + "parents": [ + "534" + ] + }, + { + "id": "536", + "parents": [ + "535" + ] + }, + { + "id": "537", + "parents": [ + "536" + ] + }, + { + "id": "538", + "parents": [ + "537" + ] + }, + { + "id": "539", + "parents": [ + "538" + ] + }, + { + "id": "540", + "parents": [ + "539" + ] + }, + { + "id": "541", + "parents": [ + "540" + ] + }, + { + "id": "542", + "parents": [ + "541" + ] + }, + { + "id": "543", + "parents": [ + "542" + ] + }, + { + "id": "544", + "parents": [ + "543" + ] + }, + { + "id": "545", + "parents": [ + "544" + ] + }, + { + "id": "546", + "parents": [ + "545" + ] + }, + { + "id": "547", + "parents": [ + "546" + ] + }, + { + "id": "548", + "parents": [ + "547" + ] + }, + { + "id": "549", + "parents": [ + "548" + ] + }, + { + "id": "550", + "parents": [ + "549" + ] + }, + { + "id": "551", + "parents": [ + "550" + ] + }, + { + "id": "552", + "parents": [ + "551" + ] + }, + { + "id": "553", + "parents": [ + "552" + ] + }, + { + "id": "554", + "parents": [ + "553" + ] + }, + { + "id": "555", + "parents": [ + "554" + ] + }, + { + "id": "556", + "parents": [ + "555" + ] + }, + { + "id": "557", + "parents": [ + "556" + ] + }, + { + "id": "558", + "parents": [ + "557" + ] + }, + { + "id": "559", + "parents": [ + "558" + ] + }, + { + "id": "560", + "parents": [ + "559" + ] + }, + { + "id": "561", + "parents": [ + "560" + ] + }, + { + "id": "562", + "parents": [ + "561" + ] + }, + { + "id": "563", + "parents": [ + "562" + ] + }, + { + "id": "564", + "parents": [ + "563" + ] + }, + { + "id": "565", + "parents": [ + "564" + ] + }, + { + "id": "566", + "parents": [ + "565" + ] + }, + { + "id": "567", + "parents": [ + "566" + ] + }, + { + "id": "568", + "parents": [ + "567" + ] + }, + { + "id": "569", + "parents": [ + "568" + ] + }, + { + "id": "570", + "parents": [ + "569" + ] + }, + { + "id": "571", + "parents": [ + "570" + ] + }, + { + "id": "572", + "parents": [ + "571" + ] + }, + { + "id": "573", + "parents": [ + "572" + ] + }, + { + "id": "574", + "parents": [ + "573" + ] + }, + { + "id": "575", + "parents": [ + "574" + ] + }, + { + "id": "576", + "parents": [ + "575" + ] + }, + { + "id": "577", + "parents": [ + "576" + ] + }, + { + "id": "578", + "parents": [ + "577" + ] + }, + { + "id": "579", + "parents": [ + "578" + ] + }, + { + "id": "580", + "parents": [ + "579" + ] + }, + { + "id": "581", + "parents": [ + "580" + ] + }, + { + "id": "582", + "parents": [ + "581" + ] + }, + { + "id": "583", + "parents": [ + "582" + ] + }, + { + "id": "584", + "parents": [ + "583" + ] + }, + { + "id": "585", + "parents": [ + "584" + ] + }, + { + "id": "586", + "parents": [ + "585" + ] + }, + { + "id": "587", + "parents": [ + "586" + ] + }, + { + "id": "588", + "parents": [ + "587" + ] + }, + { + "id": "589", + "parents": [ + "588" + ] + }, + { + "id": "590", + "parents": [ + "589" + ] + }, + { + "id": "591", + "parents": [ + "590" + ] + }, + { + "id": "592", + "parents": [ + "591" + ] + }, + { + "id": "593", + "parents": [ + "592" + ] + }, + { + "id": "594", + "parents": [ + "593" + ] + }, + { + "id": "595", + "parents": [ + "594" + ] + }, + { + "id": "596", + "parents": [ + "595" + ] + }, + { + "id": "597", + "parents": [ + "596" + ] + }, + { + "id": "598", + "parents": [ + "597" + ] + }, + { + "id": "599", + "parents": [ + "598" + ] + }, + { + "id": "600", + "parents": [ + "599" + ] + }, + { + "id": "601", + "parents": [ + "600" + ] + }, + { + "id": "602", + "parents": [ + "601" + ] + }, + { + "id": "603", + "parents": [ + "602" + ] + }, + { + "id": "604", + "parents": [ + "603" + ] + }, + { + "id": "605", + "parents": [ + "604" + ] + }, + { + "id": "606", + "parents": [ + "605" + ] + }, + { + "id": "607", + "parents": [ + "606" + ] + }, + { + "id": "608", + "parents": [ + "607" + ] + }, + { + "id": "609", + "parents": [ + "608" + ] + }, + { + "id": "610", + "parents": [ + "609" + ] + }, + { + "id": "611", + "parents": [ + "610" + ] + }, + { + "id": "612", + "parents": [ + "611" + ] + }, + { + "id": "613", + "parents": [ + "612" + ] + }, + { + "id": "614", + "parents": [ + "613" + ] + }, + { + "id": "615", + "parents": [ + "614" + ] + }, + { + "id": "616", + "parents": [ + "615" + ] + }, + { + "id": "617", + "parents": [ + "616" + ] + }, + { + "id": "618", + "parents": [ + "617" + ] + }, + { + "id": "619", + "parents": [ + "618" + ] + }, + { + "id": "620", + "parents": [ + "619" + ] + }, + { + "id": "621", + "parents": [ + "620" + ] + }, + { + "id": "622", + "parents": [ + "621" + ] + }, + { + "id": "623", + "parents": [ + "622" + ] + }, + { + "id": "624", + "parents": [ + "623" + ] + }, + { + "id": "625", + "parents": [ + "624" + ] + }, + { + "id": "626", + "parents": [ + "625" + ] + }, + { + "id": "627", + "parents": [ + "626" + ] + }, + { + "id": "628", + "parents": [ + "627" + ] + }, + { + "id": "629", + "parents": [ + "628" + ] + }, + { + "id": "630", + "parents": [ + "629" + ] + }, + { + "id": "631", + "parents": [ + "630" + ] + }, + { + "id": "632", + "parents": [ + "631" + ] + }, + { + "id": "633", + "parents": [ + "632" + ] + }, + { + "id": "634", + "parents": [ + "633" + ] + }, + { + "id": "635", + "parents": [ + "634" + ] + }, + { + "id": "636", + "parents": [ + "635" + ] + }, + { + "id": "637", + "parents": [ + "636" + ] + }, + { + "id": "638", + "parents": [ + "637" + ] + }, + { + "id": "639", + "parents": [ + "638" + ] + }, + { + "id": "640", + "parents": [ + "639" + ] + }, + { + "id": "641", + "parents": [ + "640" + ] + }, + { + "id": "642", + "parents": [ + "641" + ] + }, + { + "id": "643", + "parents": [ + "642" + ] + }, + { + "id": "644", + "parents": [ + "643" + ] + }, + { + "id": "645", + "parents": [ + "644" + ] + }, + { + "id": "646", + "parents": [ + "645" + ] + }, + { + "id": "647", + "parents": [ + "646" + ] + }, + { + "id": "648", + "parents": [ + "647" + ] + }, + { + "id": "649", + "parents": [ + "648" + ] + }, + { + "id": "650", + "parents": [ + "649" + ] + }, + { + "id": "651", + "parents": [ + "650" + ] + }, + { + "id": "652", + "parents": [ + "651" + ] + }, + { + "id": "653", + "parents": [ + "652" + ] + }, + { + "id": "654", + "parents": [ + "653" + ] + }, + { + "id": "655", + "parents": [ + "654" + ] + }, + { + "id": "656", + "parents": [ + "655" + ] + }, + { + "id": "657", + "parents": [ + "656" + ] + }, + { + "id": "658", + "parents": [ + "657" + ] + }, + { + "id": "659", + "parents": [ + "658" + ] + }, + { + "id": "660", + "parents": [ + "659" + ] + }, + { + "id": "661", + "parents": [ + "660" + ] + }, + { + "id": "662", + "parents": [ + "661" + ] + }, + { + "id": "663", + "parents": [ + "662" + ] + }, + { + "id": "664", + "parents": [ + "663" + ] + }, + { + "id": "665", + "parents": [ + "664" + ] + }, + { + "id": "666", + "parents": [ + "665" + ] + }, + { + "id": "667", + "parents": [ + "666" + ] + }, + { + "id": "668", + "parents": [ + "667" + ] + }, + { + "id": "669", + "parents": [ + "668" + ] + }, + { + "id": "670", + "parents": [ + "669" + ] + }, + { + "id": "671", + "parents": [ + "670" + ] + }, + { + "id": "672", + "parents": [ + "671" + ] + }, + { + "id": "673", + "parents": [ + "672" + ] + }, + { + "id": "674", + "parents": [ + "673" + ] + }, + { + "id": "675", + "parents": [ + "674" + ] + }, + { + "id": "676", + "parents": [ + "675" + ] + }, + { + "id": "677", + "parents": [ + "676" + ] + }, + { + "id": "678", + "parents": [ + "677" + ] + }, + { + "id": "679", + "parents": [ + "678" + ] + }, + { + "id": "680", + "parents": [ + "679" + ] + }, + { + "id": "681", + "parents": [ + "680" + ] + }, + { + "id": "682", + "parents": [ + "681" + ] + }, + { + "id": "683", + "parents": [ + "682" + ] + }, + { + "id": "684", + "parents": [ + "683" + ] + }, + { + "id": "685", + "parents": [ + "684" + ] + }, + { + "id": "686", + "parents": [ + "685" + ] + }, + { + "id": "687", + "parents": [ + "686" + ] + }, + { + "id": "688", + "parents": [ + "687" + ] + }, + { + "id": "689", + "parents": [ + "688" + ] + }, + { + "id": "690", + "parents": [ + "689" + ] + }, + { + "id": "691", + "parents": [ + "690" + ] + }, + { + "id": "692", + "parents": [ + "691" + ] + }, + { + "id": "693", + "parents": [ + "692" + ] + }, + { + "id": "694", + "parents": [ + "693" + ] + }, + { + "id": "695", + "parents": [ + "694" + ] + }, + { + "id": "696", + "parents": [ + "695" + ] + }, + { + "id": "697", + "parents": [ + "696" + ] + }, + { + "id": "698", + "parents": [ + "697" + ] + }, + { + "id": "699", + "parents": [ + "698" + ] + }, + { + "id": "700", + "parents": [ + "699" + ] + }, + { + "id": "701", + "parents": [ + "700" + ] + }, + { + "id": "702", + "parents": [ + "701" + ] + }, + { + "id": "703", + "parents": [ + "702" + ] + }, + { + "id": "704", + "parents": [ + "703" + ] + }, + { + "id": "705", + "parents": [ + "704" + ] + }, + { + "id": "706", + "parents": [ + "705" + ] + }, + { + "id": "707", + "parents": [ + "706" + ] + }, + { + "id": "708", + "parents": [ + "707" + ] + }, + { + "id": "709", + "parents": [ + "708" + ] + }, + { + "id": "710", + "parents": [ + "709" + ] + }, + { + "id": "711", + "parents": [ + "710" + ] + }, + { + "id": "712", + "parents": [ + "711" + ] + }, + { + "id": "713", + "parents": [ + "712" + ] + }, + { + "id": "714", + "parents": [ + "713" + ] + }, + { + "id": "715", + "parents": [ + "714" + ] + }, + { + "id": "716", + "parents": [ + "715" + ] + }, + { + "id": "717", + "parents": [ + "716" + ] + }, + { + "id": "718", + "parents": [ + "717" + ] + }, + { + "id": "719", + "parents": [ + "718" + ] + }, + { + "id": "720", + "parents": [ + "719" + ] + }, + { + "id": "721", + "parents": [ + "720" + ] + }, + { + "id": "722", + "parents": [ + "721" + ] + }, + { + "id": "723", + "parents": [ + "722" + ] + }, + { + "id": "724", + "parents": [ + "723" + ] + }, + { + "id": "725", + "parents": [ + "724" + ] + }, + { + "id": "726", + "parents": [ + "725" + ] + }, + { + "id": "727", + "parents": [ + "726" + ] + }, + { + "id": "728", + "parents": [ + "727" + ] + }, + { + "id": "729", + "parents": [ + "728" + ] + }, + { + "id": "730", + "parents": [ + "729" + ] + }, + { + "id": "731", + "parents": [ + "730" + ] + }, + { + "id": "732", + "parents": [ + "731" + ] + }, + { + "id": "733", + "parents": [ + "732" + ] + }, + { + "id": "734", + "parents": [ + "733" + ] + }, + { + "id": "735", + "parents": [ + "734" + ] + }, + { + "id": "736", + "parents": [ + "735" + ] + }, + { + "id": "737", + "parents": [ + "736" + ] + }, + { + "id": "738", + "parents": [ + "737" + ] + }, + { + "id": "739", + "parents": [ + "738" + ] + }, + { + "id": "740", + "parents": [ + "739" + ] + }, + { + "id": "741", + "parents": [ + "740" + ] + }, + { + "id": "742", + "parents": [ + "741" + ] + }, + { + "id": "743", + "parents": [ + "742" + ] + }, + { + "id": "744", + "parents": [ + "743" + ] + }, + { + "id": "745", + "parents": [ + "744" + ] + }, + { + "id": "746", + "parents": [ + "745" + ] + }, + { + "id": "747", + "parents": [ + "746" + ] + }, + { + "id": "748", + "parents": [ + "747" + ] + }, + { + "id": "749", + "parents": [ + "748" + ] + }, + { + "id": "750", + "parents": [ + "749" + ] + }, + { + "id": "751", + "parents": [ + "750" + ] + }, + { + "id": "752", + "parents": [ + "751" + ] + }, + { + "id": "753", + "parents": [ + "752" + ] + }, + { + "id": "754", + "parents": [ + "753" + ] + }, + { + "id": "755", + "parents": [ + "754" + ] + }, + { + "id": "756", + "parents": [ + "755" + ] + }, + { + "id": "757", + "parents": [ + "756" + ] + }, + { + "id": "758", + "parents": [ + "757" + ] + }, + { + "id": "759", + "parents": [ + "758" + ] + }, + { + "id": "760", + "parents": [ + "759" + ] + }, + { + "id": "761", + "parents": [ + "760" + ] + }, + { + "id": "762", + "parents": [ + "761" + ] + }, + { + "id": "763", + "parents": [ + "762" + ] + }, + { + "id": "764", + "parents": [ + "763" + ] + }, + { + "id": "765", + "parents": [ + "764" + ] + }, + { + "id": "766", + "parents": [ + "765" + ] + }, + { + "id": "767", + "parents": [ + "766" + ] + }, + { + "id": "768", + "parents": [ + "767" + ] + }, + { + "id": "769", + "parents": [ + "768" + ] + }, + { + "id": "770", + "parents": [ + "769" + ] + }, + { + "id": "771", + "parents": [ + "770" + ] + }, + { + "id": "772", + "parents": [ + "771" + ] + }, + { + "id": "773", + "parents": [ + "772" + ] + }, + { + "id": "774", + "parents": [ + "773" + ] + }, + { + "id": "775", + "parents": [ + "774" + ] + }, + { + "id": "776", + "parents": [ + "775" + ] + }, + { + "id": "777", + "parents": [ + "776" + ] + }, + { + "id": "778", + "parents": [ + "777" + ] + }, + { + "id": "779", + "parents": [ + "778" + ] + }, + { + "id": "780", + "parents": [ + "779" + ] + }, + { + "id": "781", + "parents": [ + "780" + ] + }, + { + "id": "782", + "parents": [ + "781" + ] + }, + { + "id": "783", + "parents": [ + "782" + ] + }, + { + "id": "784", + "parents": [ + "783" + ] + }, + { + "id": "785", + "parents": [ + "784" + ] + }, + { + "id": "786", + "parents": [ + "785" + ] + }, + { + "id": "787", + "parents": [ + "786" + ] + }, + { + "id": "788", + "parents": [ + "787" + ] + }, + { + "id": "789", + "parents": [ + "788" + ] + }, + { + "id": "790", + "parents": [ + "789" + ] + }, + { + "id": "791", + "parents": [ + "790" + ] + }, + { + "id": "792", + "parents": [ + "791" + ] + }, + { + "id": "793", + "parents": [ + "792" + ] + }, + { + "id": "794", + "parents": [ + "793" + ] + }, + { + "id": "795", + "parents": [ + "794" + ] + }, + { + "id": "796", + "parents": [ + "795" + ] + }, + { + "id": "797", + "parents": [ + "796" + ] + }, + { + "id": "798", + "parents": [ + "797" + ] + }, + { + "id": "799", + "parents": [ + "798" + ] + }, + { + "id": "800", + "parents": [ + "799" + ] + }, + { + "id": "801", + "parents": [ + "800" + ] + }, + { + "id": "802", + "parents": [ + "801" + ] + }, + { + "id": "803", + "parents": [ + "802" + ] + }, + { + "id": "804", + "parents": [ + "803" + ] + }, + { + "id": "805", + "parents": [ + "804" + ] + }, + { + "id": "806", + "parents": [ + "805" + ] + }, + { + "id": "807", + "parents": [ + "806" + ] + }, + { + "id": "808", + "parents": [ + "807" + ] + }, + { + "id": "809", + "parents": [ + "808" + ] + }, + { + "id": "810", + "parents": [ + "809" + ] + }, + { + "id": "811", + "parents": [ + "810" + ] + }, + { + "id": "812", + "parents": [ + "811" + ] + }, + { + "id": "813", + "parents": [ + "812" + ] + }, + { + "id": "814", + "parents": [ + "813" + ] + }, + { + "id": "815", + "parents": [ + "814" + ] + }, + { + "id": "816", + "parents": [ + "815" + ] + }, + { + "id": "817", + "parents": [ + "816" + ] + }, + { + "id": "818", + "parents": [ + "817" + ] + }, + { + "id": "819", + "parents": [ + "818" + ] + }, + { + "id": "820", + "parents": [ + "819" + ] + }, + { + "id": "821", + "parents": [ + "820" + ] + }, + { + "id": "822", + "parents": [ + "821" + ] + }, + { + "id": "823", + "parents": [ + "822" + ] + }, + { + "id": "824", + "parents": [ + "823" + ] + }, + { + "id": "825", + "parents": [ + "824" + ] + }, + { + "id": "826", + "parents": [ + "825" + ] + }, + { + "id": "827", + "parents": [ + "826" + ] + }, + { + "id": "828", + "parents": [ + "827" + ] + }, + { + "id": "829", + "parents": [ + "828" + ] + }, + { + "id": "830", + "parents": [ + "829" + ] + }, + { + "id": "831", + "parents": [ + "830" + ] + }, + { + "id": "832", + "parents": [ + "831" + ] + }, + { + "id": "833", + "parents": [ + "832" + ] + }, + { + "id": "834", + "parents": [ + "833" + ] + }, + { + "id": "835", + "parents": [ + "834" + ] + }, + { + "id": "836", + "parents": [ + "835" + ] + }, + { + "id": "837", + "parents": [ + "836" + ] + }, + { + "id": "838", + "parents": [ + "837" + ] + }, + { + "id": "839", + "parents": [ + "838" + ] + }, + { + "id": "840", + "parents": [ + "839" + ] + }, + { + "id": "841", + "parents": [ + "840" + ] + }, + { + "id": "842", + "parents": [ + "841" + ] + }, + { + "id": "843", + "parents": [ + "842" + ] + }, + { + "id": "844", + "parents": [ + "843" + ] + }, + { + "id": "845", + "parents": [ + "844" + ] + }, + { + "id": "846", + "parents": [ + "845" + ] + }, + { + "id": "847", + "parents": [ + "846" + ] + }, + { + "id": "848", + "parents": [ + "847" + ] + }, + { + "id": "849", + "parents": [ + "848" + ] + }, + { + "id": "850", + "parents": [ + "849" + ] + }, + { + "id": "851", + "parents": [ + "850" + ] + }, + { + "id": "852", + "parents": [ + "851" + ] + }, + { + "id": "853", + "parents": [ + "852" + ] + }, + { + "id": "854", + "parents": [ + "853" + ] + }, + { + "id": "855", + "parents": [ + "854" + ] + }, + { + "id": "856", + "parents": [ + "855" + ] + }, + { + "id": "857", + "parents": [ + "856" + ] + }, + { + "id": "858", + "parents": [ + "857" + ] + }, + { + "id": "859", + "parents": [ + "858" + ] + }, + { + "id": "860", + "parents": [ + "859" + ] + }, + { + "id": "861", + "parents": [ + "860" + ] + }, + { + "id": "862", + "parents": [ + "861" + ] + }, + { + "id": "863", + "parents": [ + "862" + ] + }, + { + "id": "864", + "parents": [ + "863" + ] + }, + { + "id": "865", + "parents": [ + "864" + ] + }, + { + "id": "866", + "parents": [ + "865" + ] + }, + { + "id": "867", + "parents": [ + "866" + ] + }, + { + "id": "868", + "parents": [ + "867" + ] + }, + { + "id": "869", + "parents": [ + "868" + ] + }, + { + "id": "870", + "parents": [ + "869" + ] + }, + { + "id": "871", + "parents": [ + "870" + ] + }, + { + "id": "872", + "parents": [ + "871" + ] + }, + { + "id": "873", + "parents": [ + "872" + ] + }, + { + "id": "874", + "parents": [ + "873" + ] + }, + { + "id": "875", + "parents": [ + "874" + ] + }, + { + "id": "876", + "parents": [ + "875" + ] + }, + { + "id": "877", + "parents": [ + "876" + ] + }, + { + "id": "878", + "parents": [ + "877" + ] + }, + { + "id": "879", + "parents": [ + "878" + ] + }, + { + "id": "880", + "parents": [ + "879" + ] + }, + { + "id": "881", + "parents": [ + "880" + ] + }, + { + "id": "882", + "parents": [ + "881" + ] + }, + { + "id": "883", + "parents": [ + "882" + ] + }, + { + "id": "884", + "parents": [ + "883" + ] + }, + { + "id": "885", + "parents": [ + "884" + ] + }, + { + "id": "886", + "parents": [ + "885" + ] + }, + { + "id": "887", + "parents": [ + "886" + ] + }, + { + "id": "888", + "parents": [ + "887" + ] + }, + { + "id": "889", + "parents": [ + "888" + ] + }, + { + "id": "890", + "parents": [ + "889" + ] + }, + { + "id": "891", + "parents": [ + "890" + ] + }, + { + "id": "892", + "parents": [ + "891" + ] + }, + { + "id": "893", + "parents": [ + "892" + ] + }, + { + "id": "894", + "parents": [ + "893" + ] + }, + { + "id": "895", + "parents": [ + "894" + ] + }, + { + "id": "896", + "parents": [ + "895" + ] + }, + { + "id": "897", + "parents": [ + "896" + ] + }, + { + "id": "898", + "parents": [ + "897" + ] + }, + { + "id": "899", + "parents": [ + "898" + ] + }, + { + "id": "900", + "parents": [ + "899" + ] + }, + { + "id": "901", + "parents": [ + "900" + ] + }, + { + "id": "902", + "parents": [ + "901" + ] + }, + { + "id": "903", + "parents": [ + "902" + ] + }, + { + "id": "904", + "parents": [ + "903" + ] + }, + { + "id": "905", + "parents": [ + "904" + ] + }, + { + "id": "906", + "parents": [ + "905" + ] + }, + { + "id": "907", + "parents": [ + "906" + ] + }, + { + "id": "908", + "parents": [ + "907" + ] + }, + { + "id": "909", + "parents": [ + "908" + ] + }, + { + "id": "910", + "parents": [ + "909" + ] + }, + { + "id": "911", + "parents": [ + "910" + ] + }, + { + "id": "912", + "parents": [ + "911" + ] + }, + { + "id": "913", + "parents": [ + "912" + ] + }, + { + "id": "914", + "parents": [ + "913" + ] + }, + { + "id": "915", + "parents": [ + "914" + ] + }, + { + "id": "916", + "parents": [ + "915" + ] + }, + { + "id": "917", + "parents": [ + "916" + ] + }, + { + "id": "918", + "parents": [ + "917" + ] + }, + { + "id": "919", + "parents": [ + "918" + ] + }, + { + "id": "920", + "parents": [ + "919" + ] + }, + { + "id": "921", + "parents": [ + "920" + ] + }, + { + "id": "922", + "parents": [ + "921" + ] + }, + { + "id": "923", + "parents": [ + "922" + ] + }, + { + "id": "924", + "parents": [ + "923" + ] + }, + { + "id": "925", + "parents": [ + "924" + ] + }, + { + "id": "926", + "parents": [ + "925" + ] + }, + { + "id": "927", + "parents": [ + "926" + ] + }, + { + "id": "928", + "parents": [ + "927" + ] + }, + { + "id": "929", + "parents": [ + "928" + ] + }, + { + "id": "930", + "parents": [ + "929" + ] + }, + { + "id": "931", + "parents": [ + "930" + ] + }, + { + "id": "932", + "parents": [ + "931" + ] + }, + { + "id": "933", + "parents": [ + "932" + ] + }, + { + "id": "934", + "parents": [ + "933" + ] + }, + { + "id": "935", + "parents": [ + "934" + ] + }, + { + "id": "936", + "parents": [ + "935" + ] + }, + { + "id": "937", + "parents": [ + "936" + ] + }, + { + "id": "938", + "parents": [ + "937" + ] + }, + { + "id": "939", + "parents": [ + "938" + ] + }, + { + "id": "940", + "parents": [ + "939" + ] + }, + { + "id": "941", + "parents": [ + "940" + ] + }, + { + "id": "942", + "parents": [ + "941" + ] + }, + { + "id": "943", + "parents": [ + "942" + ] + }, + { + "id": "944", + "parents": [ + "943" + ] + }, + { + "id": "945", + "parents": [ + "944" + ] + }, + { + "id": "946", + "parents": [ + "945" + ] + }, + { + "id": "947", + "parents": [ + "946" + ] + }, + { + "id": "948", + "parents": [ + "947" + ] + }, + { + "id": "949", + "parents": [ + "948" + ] + }, + { + "id": "950", + "parents": [ + "949" + ] + }, + { + "id": "951", + "parents": [ + "950" + ] + }, + { + "id": "952", + "parents": [ + "951" + ] + }, + { + "id": "953", + "parents": [ + "952" + ] + }, + { + "id": "954", + "parents": [ + "953" + ] + }, + { + "id": "955", + "parents": [ + "954" + ] + }, + { + "id": "956", + "parents": [ + "955" + ] + }, + { + "id": "957", + "parents": [ + "956" + ] + }, + { + "id": "958", + "parents": [ + "957" + ] + }, + { + "id": "959", + "parents": [ + "958" + ] + }, + { + "id": "960", + "parents": [ + "959" + ] + }, + { + "id": "961", + "parents": [ + "960" + ] + }, + { + "id": "962", + "parents": [ + "961" + ] + }, + { + "id": "963", + "parents": [ + "962" + ] + }, + { + "id": "964", + "parents": [ + "963" + ] + }, + { + "id": "965", + "parents": [ + "964" + ] + }, + { + "id": "966", + "parents": [ + "965" + ] + }, + { + "id": "967", + "parents": [ + "966" + ] + }, + { + "id": "968", + "parents": [ + "967" + ] + }, + { + "id": "969", + "parents": [ + "968" + ] + }, + { + "id": "970", + "parents": [ + "969" + ] + }, + { + "id": "971", + "parents": [ + "970" + ] + }, + { + "id": "972", + "parents": [ + "971" + ] + }, + { + "id": "973", + "parents": [ + "972" + ] + }, + { + "id": "974", + "parents": [ + "973" + ] + }, + { + "id": "975", + "parents": [ + "974" + ] + }, + { + "id": "976", + "parents": [ + "975" + ] + }, + { + "id": "977", + "parents": [ + "976" + ] + }, + { + "id": "978", + "parents": [ + "977" + ] + }, + { + "id": "979", + "parents": [ + "978" + ] + }, + { + "id": "980", + "parents": [ + "979" + ] + }, + { + "id": "981", + "parents": [ + "980" + ] + }, + { + "id": "982", + "parents": [ + "981" + ] + }, + { + "id": "983", + "parents": [ + "982" + ] + }, + { + "id": "984", + "parents": [ + "983" + ] + }, + { + "id": "985", + "parents": [ + "984" + ] + }, + { + "id": "986", + "parents": [ + "985" + ] + }, + { + "id": "987", + "parents": [ + "986" + ] + }, + { + "id": "988", + "parents": [ + "987" + ] + }, + { + "id": "989", + "parents": [ + "988" + ] + }, + { + "id": "990", + "parents": [ + "989" + ] + }, + { + "id": "991", + "parents": [ + "990" + ] + }, + { + "id": "992", + "parents": [ + "991" + ] + }, + { + "id": "993", + "parents": [ + "992" + ] + }, + { + "id": "994", + "parents": [ + "993" + ] + }, + { + "id": "995", + "parents": [ + "994" + ] + }, + { + "id": "996", + "parents": [ + "995" + ] + }, + { + "id": "997", + "parents": [ + "996" + ] + }, + { + "id": "998", + "parents": [ + "997" + ] + }, + { + "id": "999", + "parents": [ + "998" + ] + }, + { + "id": "1000", + "parents": [ + "999" + ] + }, + { + "id": "1001", + "parents": [ + "1000" + ] + }, + { + "id": "1002", + "parents": [ + "1001" + ] + }, + { + "id": "1003", + "parents": [ + "1002" + ] + }, + { + "id": "1004", + "parents": [ + "1003" + ] + }, + { + "id": "1005", + "parents": [ + "1004" + ] + }, + { + "id": "1006", + "parents": [ + "1005" + ] + }, + { + "id": "1007", + "parents": [ + "1006" + ] + }, + { + "id": "1008", + "parents": [ + "1007" + ] + }, + { + "id": "1009", + "parents": [ + "1008" + ] + }, + { + "id": "1010", + "parents": [ + "1009" + ] + }, + { + "id": "1011", + "parents": [ + "1010" + ] + }, + { + "id": "1012", + "parents": [ + "1011" + ] + }, + { + "id": "1013", + "parents": [ + "1012" + ] + }, + { + "id": "1014", + "parents": [ + "1013" + ] + }, + { + "id": "1015", + "parents": [ + "1014" + ] + }, + { + "id": "1016", + "parents": [ + "1015" + ] + }, + { + "id": "1017", + "parents": [ + "1016" + ] + }, + { + "id": "1018", + "parents": [ + "1017" + ] + }, + { + "id": "1019", + "parents": [ + "1018" + ] + }, + { + "id": "1020", + "parents": [ + "1019" + ] + }, + { + "id": "1021", + "parents": [ + "1020" + ] + }, + { + "id": "1022", + "parents": [ + "1021" + ] + }, + { + "id": "1023", + "parents": [ + "1022" + ] + }, + { + "id": "1024", + "parents": [ + "1023" + ] + }, + { + "id": "1025", + "parents": [ + "1024" + ] + }, + { + "id": "1026", + "parents": [ + "1025" + ] + }, + { + "id": "1027", + "parents": [ + "1026" + ] + }, + { + "id": "1028", + "parents": [ + "1027" + ] + }, + { + "id": "1029", + "parents": [ + "1028" + ] + }, + { + "id": "1030", + "parents": [ + "1029" + ] + }, + { + "id": "1031", + "parents": [ + "1030" + ] + }, + { + "id": "1032", + "parents": [ + "1031" + ] + }, + { + "id": "1033", + "parents": [ + "1032" + ] + }, + { + "id": "1034", + "parents": [ + "1033" + ] + }, + { + "id": "1035", + "parents": [ + "1034" + ] + }, + { + "id": "1036", + "parents": [ + "1035" + ] + }, + { + "id": "1037", + "parents": [ + "1036" + ] + }, + { + "id": "1038", + "parents": [ + "1037" + ] + }, + { + "id": "1039", + "parents": [ + "1038" + ] + }, + { + "id": "1040", + "parents": [ + "1039" + ] + }, + { + "id": "1041", + "parents": [ + "1040" + ] + }, + { + "id": "1042", + "parents": [ + "1041" + ] + }, + { + "id": "1043", + "parents": [ + "1042" + ] + }, + { + "id": "1044", + "parents": [ + "1043" + ] + }, + { + "id": "1045", + "parents": [ + "1044" + ] + }, + { + "id": "1046", + "parents": [ + "1045" + ] + }, + { + "id": "1047", + "parents": [ + "1046" + ] + }, + { + "id": "1048", + "parents": [ + "1047" + ] + }, + { + "id": "1049", + "parents": [ + "1048" + ] + }, + { + "id": "1050", + "parents": [ + "1049" + ] + }, + { + "id": "1051", + "parents": [ + "1050" + ] + }, + { + "id": "1052", + "parents": [ + "1051" + ] + }, + { + "id": "1053", + "parents": [ + "1052" + ] + }, + { + "id": "1054", + "parents": [ + "1053" + ] + }, + { + "id": "1055", + "parents": [ + "1054" + ] + }, + { + "id": "1056", + "parents": [ + "1055" + ] + }, + { + "id": "1057", + "parents": [ + "1056" + ] + }, + { + "id": "1058", + "parents": [ + "1057" + ] + }, + { + "id": "1059", + "parents": [ + "1058" + ] + }, + { + "id": "1060", + "parents": [ + "1059" + ] + }, + { + "id": "1061", + "parents": [ + "1060" + ] + }, + { + "id": "1062", + "parents": [ + "1061" + ] + }, + { + "id": "1063", + "parents": [ + "1062" + ] + }, + { + "id": "1064", + "parents": [ + "1063" + ] + }, + { + "id": "1065", + "parents": [ + "1064" + ] + }, + { + "id": "1066", + "parents": [ + "1065" + ] + }, + { + "id": "1067", + "parents": [ + "1066" + ] + }, + { + "id": "1068", + "parents": [ + "1067" + ] + }, + { + "id": "1069", + "parents": [ + "1068" + ] + }, + { + "id": "1070", + "parents": [ + "1069" + ] + }, + { + "id": "1071", + "parents": [ + "1070" + ] + }, + { + "id": "1072", + "parents": [ + "1071" + ] + }, + { + "id": "1073", + "parents": [ + "1072" + ] + }, + { + "id": "1074", + "parents": [ + "1073" + ] + }, + { + "id": "1075", + "parents": [ + "1074" + ] + }, + { + "id": "1076", + "parents": [ + "1075" + ] + }, + { + "id": "1077", + "parents": [ + "1076" + ] + }, + { + "id": "1078", + "parents": [ + "1077" + ] + }, + { + "id": "1079", + "parents": [ + "1078" + ] + }, + { + "id": "1080", + "parents": [ + "1079" + ] + }, + { + "id": "1081", + "parents": [ + "1080" + ] + }, + { + "id": "1082", + "parents": [ + "1081" + ] + }, + { + "id": "1083", + "parents": [ + "1082" + ] + }, + { + "id": "1084", + "parents": [ + "1083" + ] + }, + { + "id": "1085", + "parents": [ + "1084" + ] + }, + { + "id": "1086", + "parents": [ + "1085" + ] + }, + { + "id": "1087", + "parents": [ + "1086" + ] + }, + { + "id": "1088", + "parents": [ + "1087" + ] + }, + { + "id": "1089", + "parents": [ + "1088" + ] + }, + { + "id": "1090", + "parents": [ + "1089" + ] + }, + { + "id": "1091", + "parents": [ + "1090" + ] + }, + { + "id": "1092", + "parents": [ + "1091" + ] + }, + { + "id": "1093", + "parents": [ + "1092" + ] + }, + { + "id": "1094", + "parents": [ + "1093" + ] + }, + { + "id": "1095", + "parents": [ + "1094" + ] + }, + { + "id": "1096", + "parents": [ + "1095" + ] + }, + { + "id": "1097", + "parents": [ + "1096" + ] + }, + { + "id": "1098", + "parents": [ + "1097" + ] + }, + { + "id": "1099", + "parents": [ + "1098" + ] + }, + { + "id": "1100", + "parents": [ + "1099" + ] + }, + { + "id": "1101", + "parents": [ + "1100" + ] + }, + { + "id": "1102", + "parents": [ + "1101" + ] + }, + { + "id": "1103", + "parents": [ + "1102" + ] + }, + { + "id": "1104", + "parents": [ + "1103" + ] + }, + { + "id": "1105", + "parents": [ + "1104" + ] + }, + { + "id": "1106", + "parents": [ + "1105" + ] + }, + { + "id": "1107", + "parents": [ + "1106" + ] + }, + { + "id": "1108", + "parents": [ + "1107" + ] + }, + { + "id": "1109", + "parents": [ + "1108" + ] + }, + { + "id": "1110", + "parents": [ + "1109" + ] + }, + { + "id": "1111", + "parents": [ + "1110" + ] + }, + { + "id": "1112", + "parents": [ + "1111" + ] + }, + { + "id": "1113", + "parents": [ + "1112" + ] + }, + { + "id": "1114", + "parents": [ + "1113" + ] + }, + { + "id": "1115", + "parents": [ + "1114" + ] + }, + { + "id": "1116", + "parents": [ + "1115" + ] + }, + { + "id": "1117", + "parents": [ + "1116" + ] + }, + { + "id": "1118", + "parents": [ + "1117" + ] + }, + { + "id": "1119", + "parents": [ + "1118" + ] + }, + { + "id": "1120", + "parents": [ + "1119" + ] + }, + { + "id": "1121", + "parents": [ + "1120" + ] + }, + { + "id": "1122", + "parents": [ + "1121" + ] + }, + { + "id": "1123", + "parents": [ + "1122" + ] + }, + { + "id": "1124", + "parents": [ + "1123" + ] + }, + { + "id": "1125", + "parents": [ + "1124" + ] + }, + { + "id": "1126", + "parents": [ + "1125" + ] + }, + { + "id": "1127", + "parents": [ + "1126" + ] + }, + { + "id": "1128", + "parents": [ + "1127" + ] + }, + { + "id": "1129", + "parents": [ + "1128" + ] + }, + { + "id": "1130", + "parents": [ + "1129" + ] + }, + { + "id": "1131", + "parents": [ + "1130" + ] + }, + { + "id": "1132", + "parents": [ + "1131" + ] + }, + { + "id": "1133", + "parents": [ + "1132" + ] + }, + { + "id": "1134", + "parents": [ + "1133" + ] + }, + { + "id": "1135", + "parents": [ + "1134" + ] + }, + { + "id": "1136", + "parents": [ + "1135" + ] + }, + { + "id": "1137", + "parents": [ + "1136" + ] + }, + { + "id": "1138", + "parents": [ + "1137" + ] + }, + { + "id": "1139", + "parents": [ + "1138" + ] + }, + { + "id": "1140", + "parents": [ + "1139" + ] + }, + { + "id": "1141", + "parents": [ + "1140" + ] + }, + { + "id": "1142", + "parents": [ + "1141" + ] + }, + { + "id": "1143", + "parents": [ + "1142" + ] + }, + { + "id": "1144", + "parents": [ + "1143" + ] + }, + { + "id": "1145", + "parents": [ + "1144" + ] + }, + { + "id": "1146", + "parents": [ + "1145" + ] + }, + { + "id": "1147", + "parents": [ + "1146" + ] + }, + { + "id": "1148", + "parents": [ + "1147" + ] + }, + { + "id": "1149", + "parents": [ + "1148" + ] + }, + { + "id": "1150", + "parents": [ + "1149" + ] + }, + { + "id": "1151", + "parents": [ + "1150" + ] + }, + { + "id": "1152", + "parents": [ + "1151" + ] + }, + { + "id": "1153", + "parents": [ + "1152" + ] + }, + { + "id": "1154", + "parents": [ + "1153" + ] + }, + { + "id": "1155", + "parents": [ + "1154" + ] + }, + { + "id": "1156", + "parents": [ + "1155" + ] + }, + { + "id": "1157", + "parents": [ + "1156" + ] + }, + { + "id": "1158", + "parents": [ + "1157" + ] + }, + { + "id": "1159", + "parents": [ + "1158" + ] + }, + { + "id": "1160", + "parents": [ + "1159" + ] + }, + { + "id": "1161", + "parents": [ + "1160" + ] + }, + { + "id": "1162", + "parents": [ + "1161" + ] + }, + { + "id": "1163", + "parents": [ + "1162" + ] + }, + { + "id": "1164", + "parents": [ + "1163" + ] + }, + { + "id": "1165", + "parents": [ + "1164" + ] + }, + { + "id": "1166", + "parents": [ + "1165" + ] + }, + { + "id": "1167", + "parents": [ + "1166" + ] + }, + { + "id": "1168", + "parents": [ + "1167" + ] + }, + { + "id": "1169", + "parents": [ + "1168" + ] + }, + { + "id": "1170", + "parents": [ + "1169" + ] + }, + { + "id": "1171", + "parents": [ + "1170" + ] + }, + { + "id": "1172", + "parents": [ + "1171" + ] + }, + { + "id": "1173", + "parents": [ + "1172" + ] + }, + { + "id": "1174", + "parents": [ + "1173" + ] + }, + { + "id": "1175", + "parents": [ + "1174" + ] + }, + { + "id": "1176", + "parents": [ + "1175" + ] + }, + { + "id": "1177", + "parents": [ + "1176" + ] + }, + { + "id": "1178", + "parents": [ + "1177" + ] + }, + { + "id": "1179", + "parents": [ + "1178" + ] + }, + { + "id": "1180", + "parents": [ + "1179" + ] + }, + { + "id": "1181", + "parents": [ + "1180" + ] + }, + { + "id": "1182", + "parents": [ + "1181" + ] + }, + { + "id": "1183", + "parents": [ + "1182" + ] + }, + { + "id": "1184", + "parents": [ + "1183" + ] + }, + { + "id": "1185", + "parents": [ + "1184" + ] + }, + { + "id": "1186", + "parents": [ + "1185" + ] + }, + { + "id": "1187", + "parents": [ + "1186" + ] + }, + { + "id": "1188", + "parents": [ + "1187" + ] + }, + { + "id": "1189", + "parents": [ + "1188" + ] + }, + { + "id": "1190", + "parents": [ + "1189" + ] + }, + { + "id": "1191", + "parents": [ + "1190" + ] + }, + { + "id": "1192", + "parents": [ + "1191" + ] + }, + { + "id": "1193", + "parents": [ + "1192" + ] + }, + { + "id": "1194", + "parents": [ + "1193" + ] + }, + { + "id": "1195", + "parents": [ + "1194" + ] + }, + { + "id": "1196", + "parents": [ + "1195" + ] + }, + { + "id": "1197", + "parents": [ + "1196" + ] + }, + { + "id": "1198", + "parents": [ + "1197" + ] + }, + { + "id": "1199", + "parents": [ + "1198" + ] + }, + { + "id": "1200", + "parents": [ + "1199" + ] + }, + { + "id": "1201", + "parents": [ + "1200" + ] + }, + { + "id": "1202", + "parents": [ + "1201" + ] + }, + { + "id": "1203", + "parents": [ + "1202" + ] + }, + { + "id": "1204", + "parents": [ + "1203" + ] + }, + { + "id": "1205", + "parents": [ + "1204" + ] + }, + { + "id": "1206", + "parents": [ + "1205" + ] + }, + { + "id": "1207", + "parents": [ + "1206" + ] + }, + { + "id": "1208", + "parents": [ + "1207" + ] + }, + { + "id": "1209", + "parents": [ + "1208" + ] + }, + { + "id": "1210", + "parents": [ + "1209" + ] + }, + { + "id": "1211", + "parents": [ + "1210" + ] + }, + { + "id": "1212", + "parents": [ + "1211" + ] + }, + { + "id": "1213", + "parents": [ + "1212" + ] + }, + { + "id": "1214", + "parents": [ + "1213" + ] + }, + { + "id": "1215", + "parents": [ + "1214" + ] + }, + { + "id": "1216", + "parents": [ + "1215" + ] + }, + { + "id": "1217", + "parents": [ + "1216" + ] + }, + { + "id": "1218", + "parents": [ + "1217" + ] + }, + { + "id": "1219", + "parents": [ + "1218" + ] + }, + { + "id": "1220", + "parents": [ + "1219" + ] + }, + { + "id": "1221", + "parents": [ + "1220" + ] + }, + { + "id": "1222", + "parents": [ + "1221" + ] + }, + { + "id": "1223", + "parents": [ + "1222" + ] + }, + { + "id": "1224", + "parents": [ + "1223" + ] + }, + { + "id": "1225", + "parents": [ + "1224" + ] + }, + { + "id": "1226", + "parents": [ + "1225" + ] + }, + { + "id": "1227", + "parents": [ + "1226" + ] + }, + { + "id": "1228", + "parents": [ + "1227" + ] + }, + { + "id": "1229", + "parents": [ + "1228" + ] + }, + { + "id": "1230", + "parents": [ + "1229" + ] + }, + { + "id": "1231", + "parents": [ + "1230" + ] + }, + { + "id": "1232", + "parents": [ + "1231" + ] + }, + { + "id": "1233", + "parents": [ + "1232" + ] + }, + { + "id": "1234", + "parents": [ + "1233" + ] + }, + { + "id": "1235", + "parents": [ + "1234" + ] + }, + { + "id": "1236", + "parents": [ + "1235" + ] + }, + { + "id": "1237", + "parents": [ + "1236" + ] + }, + { + "id": "1238", + "parents": [ + "1237" + ] + }, + { + "id": "1239", + "parents": [ + "1238" + ] + }, + { + "id": "1240", + "parents": [ + "1239" + ] + }, + { + "id": "1241", + "parents": [ + "1240" + ] + }, + { + "id": "1242", + "parents": [ + "1241" + ] + }, + { + "id": "1243", + "parents": [ + "1242" + ] + }, + { + "id": "1244", + "parents": [ + "1243" + ] + }, + { + "id": "1245", + "parents": [ + "1244" + ] + }, + { + "id": "1246", + "parents": [ + "1245" + ] + }, + { + "id": "1247", + "parents": [ + "1246" + ] + }, + { + "id": "1248", + "parents": [ + "1247" + ] + }, + { + "id": "1249", + "parents": [ + "1248" + ] + }, + { + "id": "1250", + "parents": [ + "1249" + ] + }, + { + "id": "1251", + "parents": [ + "1250" + ] + }, + { + "id": "1252", + "parents": [ + "1251" + ] + }, + { + "id": "1253", + "parents": [ + "1252" + ] + }, + { + "id": "1254", + "parents": [ + "1253" + ] + }, + { + "id": "1255", + "parents": [ + "1254" + ] + }, + { + "id": "1256", + "parents": [ + "1255" + ] + }, + { + "id": "1257", + "parents": [ + "1256" + ] + }, + { + "id": "1258", + "parents": [ + "1257" + ] + }, + { + "id": "1259", + "parents": [ + "1258" + ] + }, + { + "id": "1260", + "parents": [ + "1259" + ] + }, + { + "id": "1261", + "parents": [ + "1260" + ] + }, + { + "id": "1262", + "parents": [ + "1261" + ] + }, + { + "id": "1263", + "parents": [ + "1262" + ] + }, + { + "id": "1264", + "parents": [ + "1263" + ] + }, + { + "id": "1265", + "parents": [ + "1264" + ] + }, + { + "id": "1266", + "parents": [ + "1265" + ] + }, + { + "id": "1267", + "parents": [ + "1266" + ] + }, + { + "id": "1268", + "parents": [ + "1267" + ] + }, + { + "id": "1269", + "parents": [ + "1268" + ] + }, + { + "id": "1270", + "parents": [ + "1269" + ] + }, + { + "id": "1271", + "parents": [ + "1270" + ] + }, + { + "id": "1272", + "parents": [ + "1271" + ] + }, + { + "id": "1273", + "parents": [ + "1272" + ] + }, + { + "id": "1274", + "parents": [ + "1273" + ] + }, + { + "id": "1275", + "parents": [ + "1274" + ] + }, + { + "id": "1276", + "parents": [ + "1275" + ] + }, + { + "id": "1277", + "parents": [ + "1276" + ] + }, + { + "id": "1278", + "parents": [ + "1277" + ] + }, + { + "id": "1279", + "parents": [ + "1278" + ] + }, + { + "id": "1280", + "parents": [ + "1279" + ] + }, + { + "id": "1281", + "parents": [ + "1280" + ] + }, + { + "id": "1282", + "parents": [ + "1281" + ] + }, + { + "id": "1283", + "parents": [ + "1282" + ] + }, + { + "id": "1284", + "parents": [ + "1283" + ] + }, + { + "id": "1285", + "parents": [ + "1284" + ] + }, + { + "id": "1286", + "parents": [ + "1285" + ] + }, + { + "id": "1287", + "parents": [ + "1286" + ] + }, + { + "id": "1288", + "parents": [ + "1287" + ] + }, + { + "id": "1289", + "parents": [ + "1288" + ] + }, + { + "id": "1290", + "parents": [ + "1289" + ] + }, + { + "id": "1291", + "parents": [ + "1290" + ] + }, + { + "id": "1292", + "parents": [ + "1291" + ] + }, + { + "id": "1293", + "parents": [ + "1292" + ] + }, + { + "id": "1294", + "parents": [ + "1293" + ] + }, + { + "id": "1295", + "parents": [ + "1294" + ] + }, + { + "id": "1296", + "parents": [ + "1295" + ] + }, + { + "id": "1297", + "parents": [ + "1296" + ] + }, + { + "id": "1298", + "parents": [ + "1297" + ] + }, + { + "id": "1299", + "parents": [ + "1298" + ] + }, + { + "id": "1300", + "parents": [ + "1299" + ] + }, + { + "id": "1301", + "parents": [ + "1300" + ] + }, + { + "id": "1302", + "parents": [ + "1301" + ] + }, + { + "id": "1303", + "parents": [ + "1302" + ] + }, + { + "id": "1304", + "parents": [ + "1303" + ] + }, + { + "id": "1305", + "parents": [ + "1304" + ] + }, + { + "id": "1306", + "parents": [ + "1305" + ] + }, + { + "id": "1307", + "parents": [ + "1306" + ] + }, + { + "id": "1308", + "parents": [ + "1307" + ] + }, + { + "id": "1309", + "parents": [ + "1308" + ] + }, + { + "id": "1310", + "parents": [ + "1309" + ] + }, + { + "id": "1311", + "parents": [ + "1310" + ] + }, + { + "id": "1312", + "parents": [ + "1311" + ] + }, + { + "id": "1313", + "parents": [ + "1312" + ] + }, + { + "id": "1314", + "parents": [ + "1313" + ] + }, + { + "id": "1315", + "parents": [ + "1314" + ] + }, + { + "id": "1316", + "parents": [ + "1315" + ] + }, + { + "id": "1317", + "parents": [ + "1316" + ] + }, + { + "id": "1318", + "parents": [ + "1317" + ] + }, + { + "id": "1319", + "parents": [ + "1318" + ] + }, + { + "id": "1320", + "parents": [ + "1319" + ] + }, + { + "id": "1321", + "parents": [ + "1320" + ] + }, + { + "id": "1322", + "parents": [ + "1321" + ] + }, + { + "id": "1323", + "parents": [ + "1322" + ] + }, + { + "id": "1324", + "parents": [ + "1323" + ] + }, + { + "id": "1325", + "parents": [ + "1324" + ] + }, + { + "id": "1326", + "parents": [ + "1325" + ] + }, + { + "id": "1327", + "parents": [ + "1326" + ] + }, + { + "id": "1328", + "parents": [ + "1327" + ] + }, + { + "id": "1329", + "parents": [ + "1328" + ] + }, + { + "id": "1330", + "parents": [ + "1329" + ] + }, + { + "id": "1331", + "parents": [ + "1330" + ] + }, + { + "id": "1332", + "parents": [ + "1331" + ] + }, + { + "id": "1333", + "parents": [ + "1332" + ] + }, + { + "id": "1334", + "parents": [ + "1333" + ] + }, + { + "id": "1335", + "parents": [ + "1334" + ] + }, + { + "id": "1336", + "parents": [ + "1335" + ] + }, + { + "id": "1337", + "parents": [ + "1336" + ] + }, + { + "id": "1338", + "parents": [ + "1337" + ] + }, + { + "id": "1339", + "parents": [ + "1338" + ] + }, + { + "id": "1340", + "parents": [ + "1339" + ] + }, + { + "id": "1341", + "parents": [ + "1340" + ] + }, + { + "id": "1342", + "parents": [ + "1341" + ] + }, + { + "id": "1343", + "parents": [ + "1342" + ] + }, + { + "id": "1344", + "parents": [ + "1343" + ] + }, + { + "id": "1345", + "parents": [ + "1344" + ] + }, + { + "id": "1346", + "parents": [ + "1345" + ] + }, + { + "id": "1347", + "parents": [ + "1346" + ] + }, + { + "id": "1348", + "parents": [ + "1347" + ] + }, + { + "id": "1349", + "parents": [ + "1348" + ] + }, + { + "id": "1350", + "parents": [ + "1349" + ] + }, + { + "id": "1351", + "parents": [ + "1350" + ] + }, + { + "id": "1352", + "parents": [ + "1351" + ] + }, + { + "id": "1353", + "parents": [ + "1352" + ] + }, + { + "id": "1354", + "parents": [ + "1353" + ] + }, + { + "id": "1355", + "parents": [ + "1354" + ] + }, + { + "id": "1356", + "parents": [ + "1355" + ] + }, + { + "id": "1357", + "parents": [ + "1356" + ] + }, + { + "id": "1358", + "parents": [ + "1357" + ] + }, + { + "id": "1359", + "parents": [ + "1358" + ] + }, + { + "id": "1360", + "parents": [ + "1359" + ] + }, + { + "id": "1361", + "parents": [ + "1360" + ] + }, + { + "id": "1362", + "parents": [ + "1361" + ] + }, + { + "id": "1363", + "parents": [ + "1362" + ] + }, + { + "id": "1364", + "parents": [ + "1363" + ] + }, + { + "id": "1365", + "parents": [ + "1364" + ] + }, + { + "id": "1366", + "parents": [ + "1365" + ] + }, + { + "id": "1367", + "parents": [ + "1366" + ] + }, + { + "id": "1368", + "parents": [ + "1367" + ] + }, + { + "id": "1369", + "parents": [ + "1368" + ] + }, + { + "id": "1370", + "parents": [ + "1369" + ] + }, + { + "id": "1371", + "parents": [ + "1370" + ] + }, + { + "id": "1372", + "parents": [ + "1371" + ] + }, + { + "id": "1373", + "parents": [ + "1372" + ] + }, + { + "id": "1374", + "parents": [ + "1373" + ] + }, + { + "id": "1375", + "parents": [ + "1374" + ] + }, + { + "id": "1376", + "parents": [ + "1375" + ] + }, + { + "id": "1377", + "parents": [ + "1376" + ] + }, + { + "id": "1378", + "parents": [ + "1377" + ] + }, + { + "id": "1379", + "parents": [ + "1378" + ] + }, + { + "id": "1380", + "parents": [ + "1379" + ] + }, + { + "id": "1381", + "parents": [ + "1380" + ] + }, + { + "id": "1382", + "parents": [ + "1381" + ] + }, + { + "id": "1383", + "parents": [ + "1382" + ] + }, + { + "id": "1384", + "parents": [ + "1383" + ] + }, + { + "id": "1385", + "parents": [ + "1384" + ] + }, + { + "id": "1386", + "parents": [ + "1385" + ] + }, + { + "id": "1387", + "parents": [ + "1386" + ] + }, + { + "id": "1388", + "parents": [ + "1387" + ] + }, + { + "id": "1389", + "parents": [ + "1388" + ] + }, + { + "id": "1390", + "parents": [ + "1389" + ] + }, + { + "id": "1391", + "parents": [ + "1390" + ] + }, + { + "id": "1392", + "parents": [ + "1391" + ] + }, + { + "id": "1393", + "parents": [ + "1392" + ] + }, + { + "id": "1394", + "parents": [ + "1393" + ] + }, + { + "id": "1395", + "parents": [ + "1394" + ] + }, + { + "id": "1396", + "parents": [ + "1395" + ] + }, + { + "id": "1397", + "parents": [ + "1396" + ] + }, + { + "id": "1398", + "parents": [ + "1397" + ] + }, + { + "id": "1399", + "parents": [ + "1398" + ] + }, + { + "id": "1400", + "parents": [ + "1399" + ] + }, + { + "id": "1401", + "parents": [ + "1400" + ] + }, + { + "id": "1402", + "parents": [ + "1401" + ] + }, + { + "id": "1403", + "parents": [ + "1402" + ] + }, + { + "id": "1404", + "parents": [ + "1403" + ] + }, + { + "id": "1405", + "parents": [ + "1404" + ] + }, + { + "id": "1406", + "parents": [ + "1405" + ] + }, + { + "id": "1407", + "parents": [ + "1406" + ] + }, + { + "id": "1408", + "parents": [ + "1407" + ] + }, + { + "id": "1409", + "parents": [ + "1408" + ] + }, + { + "id": "1410", + "parents": [ + "1409" + ] + }, + { + "id": "1411", + "parents": [ + "1410" + ] + }, + { + "id": "1412", + "parents": [ + "1411" + ] + }, + { + "id": "1413", + "parents": [ + "1412" + ] + }, + { + "id": "1414", + "parents": [ + "1413" + ] + }, + { + "id": "1415", + "parents": [ + "1414" + ] + }, + { + "id": "1416", + "parents": [ + "1415" + ] + }, + { + "id": "1417", + "parents": [ + "1416" + ] + }, + { + "id": "1418", + "parents": [ + "1417" + ] + }, + { + "id": "1419", + "parents": [ + "1418" + ] + }, + { + "id": "1420", + "parents": [ + "1419" + ] + }, + { + "id": "1421", + "parents": [ + "1420" + ] + }, + { + "id": "1422", + "parents": [ + "1421" + ] + }, + { + "id": "1423", + "parents": [ + "1422" + ] + }, + { + "id": "1424", + "parents": [ + "1423" + ] + }, + { + "id": "1425", + "parents": [ + "1424" + ] + }, + { + "id": "1426", + "parents": [ + "1425" + ] + }, + { + "id": "1427", + "parents": [ + "1426" + ] + }, + { + "id": "1428", + "parents": [ + "1427" + ] + }, + { + "id": "1429", + "parents": [ + "1428" + ] + }, + { + "id": "1430", + "parents": [ + "1429" + ] + }, + { + "id": "1431", + "parents": [ + "1430" + ] + }, + { + "id": "1432", + "parents": [ + "1431" + ] + }, + { + "id": "1433", + "parents": [ + "1432" + ] + }, + { + "id": "1434", + "parents": [ + "1433" + ] + }, + { + "id": "1435", + "parents": [ + "1434" + ] + }, + { + "id": "1436", + "parents": [ + "1435" + ] + }, + { + "id": "1437", + "parents": [ + "1436" + ] + }, + { + "id": "1438", + "parents": [ + "1437" + ] + }, + { + "id": "1439", + "parents": [ + "1438" + ] + }, + { + "id": "1440", + "parents": [ + "1439" + ] + }, + { + "id": "1441", + "parents": [ + "1440" + ] + }, + { + "id": "1442", + "parents": [ + "1441" + ] + }, + { + "id": "1443", + "parents": [ + "1442" + ] + }, + { + "id": "1444", + "parents": [ + "1443" + ] + }, + { + "id": "1445", + "parents": [ + "1444" + ] + }, + { + "id": "1446", + "parents": [ + "1445" + ] + }, + { + "id": "1447", + "parents": [ + "1446" + ] + }, + { + "id": "1448", + "parents": [ + "1447" + ] + }, + { + "id": "1449", + "parents": [ + "1448" + ] + }, + { + "id": "1450", + "parents": [ + "1449" + ] + }, + { + "id": "1451", + "parents": [ + "1450" + ] + }, + { + "id": "1452", + "parents": [ + "1451" + ] + }, + { + "id": "1453", + "parents": [ + "1452" + ] + }, + { + "id": "1454", + "parents": [ + "1453" + ] + }, + { + "id": "1455", + "parents": [ + "1454" + ] + }, + { + "id": "1456", + "parents": [ + "1455" + ] + }, + { + "id": "1457", + "parents": [ + "1456" + ] + }, + { + "id": "1458", + "parents": [ + "1457" + ] + }, + { + "id": "1459", + "parents": [ + "1458" + ] + }, + { + "id": "1460", + "parents": [ + "1459" + ] + }, + { + "id": "1461", + "parents": [ + "1460" + ] + }, + { + "id": "1462", + "parents": [ + "1461" + ] + }, + { + "id": "1463", + "parents": [ + "1462" + ] + }, + { + "id": "1464", + "parents": [ + "1463" + ] + }, + { + "id": "1465", + "parents": [ + "1464" + ] + }, + { + "id": "1466", + "parents": [ + "1465" + ] + }, + { + "id": "1467", + "parents": [ + "1466" + ] + }, + { + "id": "1468", + "parents": [ + "1467" + ] + }, + { + "id": "1469", + "parents": [ + "1468" + ] + }, + { + "id": "1470", + "parents": [ + "1469" + ] + }, + { + "id": "1471", + "parents": [ + "1470" + ] + }, + { + "id": "1472", + "parents": [ + "1471" + ] + }, + { + "id": "1473", + "parents": [ + "1472" + ] + }, + { + "id": "1474", + "parents": [ + "1473" + ] + }, + { + "id": "1475", + "parents": [ + "1474" + ] + }, + { + "id": "1476", + "parents": [ + "1475" + ] + }, + { + "id": "1477", + "parents": [ + "1476" + ] + }, + { + "id": "1478", + "parents": [ + "1477" + ] + }, + { + "id": "1479", + "parents": [ + "1478" + ] + }, + { + "id": "1480", + "parents": [ + "1479" + ] + }, + { + "id": "1481", + "parents": [ + "1480" + ] + }, + { + "id": "1482", + "parents": [ + "1481" + ] + }, + { + "id": "1483", + "parents": [ + "1482" + ] + }, + { + "id": "1484", + "parents": [ + "1483" + ] + }, + { + "id": "1485", + "parents": [ + "1484" + ] + }, + { + "id": "1486", + "parents": [ + "1485" + ] + }, + { + "id": "1487", + "parents": [ + "1486" + ] + }, + { + "id": "1488", + "parents": [ + "1487" + ] + }, + { + "id": "1489", + "parents": [ + "1488" + ] + }, + { + "id": "1490", + "parents": [ + "1489" + ] + }, + { + "id": "1491", + "parents": [ + "1490" + ] + }, + { + "id": "1492", + "parents": [ + "1491" + ] + }, + { + "id": "1493", + "parents": [ + "1492" + ] + }, + { + "id": "1494", + "parents": [ + "1493" + ] + }, + { + "id": "1495", + "parents": [ + "1494" + ] + }, + { + "id": "1496", + "parents": [ + "1495" + ] + }, + { + "id": "1497", + "parents": [ + "1496" + ] + }, + { + "id": "1498", + "parents": [ + "1497" + ] + }, + { + "id": "1499", + "parents": [ + "1498" + ] + }, + { + "id": "1500", + "parents": [ + "1499" + ] + }, + { + "id": "1501", + "parents": [ + "1500" + ] + }, + { + "id": "1502", + "parents": [ + "1501" + ] + }, + { + "id": "1503", + "parents": [ + "1502" + ] + }, + { + "id": "1504", + "parents": [ + "1503" + ] + }, + { + "id": "1505", + "parents": [ + "1504" + ] + }, + { + "id": "1506", + "parents": [ + "1505" + ] + }, + { + "id": "1507", + "parents": [ + "1506" + ] + }, + { + "id": "1508", + "parents": [ + "1507" + ] + }, + { + "id": "1509", + "parents": [ + "1508" + ] + }, + { + "id": "1510", + "parents": [ + "1509" + ] + }, + { + "id": "1511", + "parents": [ + "1510" + ] + }, + { + "id": "1512", + "parents": [ + "1511" + ] + }, + { + "id": "1513", + "parents": [ + "1512" + ] + }, + { + "id": "1514", + "parents": [ + "1513" + ] + }, + { + "id": "1515", + "parents": [ + "1514" + ] + }, + { + "id": "1516", + "parents": [ + "1515" + ] + }, + { + "id": "1517", + "parents": [ + "1516" + ] + }, + { + "id": "1518", + "parents": [ + "1517" + ] + }, + { + "id": "1519", + "parents": [ + "1518" + ] + }, + { + "id": "1520", + "parents": [ + "1519" + ] + }, + { + "id": "1521", + "parents": [ + "1520" + ] + }, + { + "id": "1522", + "parents": [ + "1521" + ] + }, + { + "id": "1523", + "parents": [ + "1522" + ] + }, + { + "id": "1524", + "parents": [ + "1523" + ] + }, + { + "id": "1525", + "parents": [ + "1524" + ] + }, + { + "id": "1526", + "parents": [ + "1525" + ] + }, + { + "id": "1527", + "parents": [ + "1526" + ] + }, + { + "id": "1528", + "parents": [ + "1527" + ] + }, + { + "id": "1529", + "parents": [ + "1528" + ] + }, + { + "id": "1530", + "parents": [ + "1529" + ] + }, + { + "id": "1531", + "parents": [ + "1530" + ] + }, + { + "id": "1532", + "parents": [ + "1531" + ] + }, + { + "id": "1533", + "parents": [ + "1532" + ] + }, + { + "id": "1534", + "parents": [ + "1533" + ] + }, + { + "id": "1535", + "parents": [ + "1534" + ] + }, + { + "id": "1536", + "parents": [ + "1535" + ] + }, + { + "id": "1537", + "parents": [ + "1536" + ] + }, + { + "id": "1538", + "parents": [ + "1537" + ] + }, + { + "id": "1539", + "parents": [ + "1538" + ] + }, + { + "id": "1540", + "parents": [ + "1539" + ] + }, + { + "id": "1541", + "parents": [ + "1540" + ] + }, + { + "id": "1542", + "parents": [ + "1541" + ] + }, + { + "id": "1543", + "parents": [ + "1542" + ] + }, + { + "id": "1544", + "parents": [ + "1543" + ] + }, + { + "id": "1545", + "parents": [ + "1544" + ] + }, + { + "id": "1546", + "parents": [ + "1545" + ] + }, + { + "id": "1547", + "parents": [ + "1546" + ] + }, + { + "id": "1548", + "parents": [ + "1547" + ] + }, + { + "id": "1549", + "parents": [ + "1548" + ] + }, + { + "id": "1550", + "parents": [ + "1549" + ] + }, + { + "id": "1551", + "parents": [ + "1550" + ] + }, + { + "id": "1552", + "parents": [ + "1551" + ] + }, + { + "id": "1553", + "parents": [ + "1552" + ] + }, + { + "id": "1554", + "parents": [ + "1553" + ] + }, + { + "id": "1555", + "parents": [ + "1554" + ] + }, + { + "id": "1556", + "parents": [ + "1555" + ] + }, + { + "id": "1557", + "parents": [ + "1556" + ] + }, + { + "id": "1558", + "parents": [ + "1557" + ] + }, + { + "id": "1559", + "parents": [ + "1558" + ] + }, + { + "id": "1560", + "parents": [ + "1559" + ] + }, + { + "id": "1561", + "parents": [ + "1560" + ] + }, + { + "id": "1562", + "parents": [ + "1561" + ] + }, + { + "id": "1563", + "parents": [ + "1562" + ] + }, + { + "id": "1564", + "parents": [ + "1563" + ] + }, + { + "id": "1565", + "parents": [ + "1564" + ] + }, + { + "id": "1566", + "parents": [ + "1565" + ] + }, + { + "id": "1567", + "parents": [ + "1566" + ] + }, + { + "id": "1568", + "parents": [ + "1567" + ] + }, + { + "id": "1569", + "parents": [ + "1568" + ] + }, + { + "id": "1570", + "parents": [ + "1569" + ] + }, + { + "id": "1571", + "parents": [ + "1570" + ] + }, + { + "id": "1572", + "parents": [ + "1571" + ] + }, + { + "id": "1573", + "parents": [ + "1572" + ] + }, + { + "id": "1574", + "parents": [ + "1573" + ] + }, + { + "id": "1575", + "parents": [ + "1574" + ] + }, + { + "id": "1576", + "parents": [ + "1575" + ] + }, + { + "id": "1577", + "parents": [ + "1576" + ] + }, + { + "id": "1578", + "parents": [ + "1577" + ] + }, + { + "id": "1579", + "parents": [ + "1578" + ] + }, + { + "id": "1580", + "parents": [ + "1579" + ] + }, + { + "id": "1581", + "parents": [ + "1580" + ] + }, + { + "id": "1582", + "parents": [ + "1581" + ] + }, + { + "id": "1583", + "parents": [ + "1582" + ] + }, + { + "id": "1584", + "parents": [ + "1583" + ] + }, + { + "id": "1585", + "parents": [ + "1584" + ] + }, + { + "id": "1586", + "parents": [ + "1585" + ] + }, + { + "id": "1587", + "parents": [ + "1586" + ] + }, + { + "id": "1588", + "parents": [ + "1587" + ] + }, + { + "id": "1589", + "parents": [ + "1588" + ] + }, + { + "id": "1590", + "parents": [ + "1589" + ] + }, + { + "id": "1591", + "parents": [ + "1590" + ] + }, + { + "id": "1592", + "parents": [ + "1591" + ] + }, + { + "id": "1593", + "parents": [ + "1592" + ] + }, + { + "id": "1594", + "parents": [ + "1593" + ] + }, + { + "id": "1595", + "parents": [ + "1594" + ] + }, + { + "id": "1596", + "parents": [ + "1595" + ] + }, + { + "id": "1597", + "parents": [ + "1596" + ] + }, + { + "id": "1598", + "parents": [ + "1597" + ] + }, + { + "id": "1599", + "parents": [ + "1598" + ] + }, + { + "id": "1600", + "parents": [ + "1599" + ] + }, + { + "id": "1601", + "parents": [ + "1600" + ] + }, + { + "id": "1602", + "parents": [ + "1601" + ] + }, + { + "id": "1603", + "parents": [ + "1602" + ] + }, + { + "id": "1604", + "parents": [ + "1603" + ] + }, + { + "id": "1605", + "parents": [ + "1604" + ] + }, + { + "id": "1606", + "parents": [ + "1605" + ] + }, + { + "id": "1607", + "parents": [ + "1606" + ] + }, + { + "id": "1608", + "parents": [ + "1607" + ] + }, + { + "id": "1609", + "parents": [ + "1608" + ] + }, + { + "id": "1610", + "parents": [ + "1609" + ] + }, + { + "id": "1611", + "parents": [ + "1610" + ] + }, + { + "id": "1612", + "parents": [ + "1611" + ] + }, + { + "id": "1613", + "parents": [ + "1612" + ] + }, + { + "id": "1614", + "parents": [ + "1613" + ] + }, + { + "id": "1615", + "parents": [ + "1614" + ] + }, + { + "id": "1616", + "parents": [ + "1615" + ] + }, + { + "id": "1617", + "parents": [ + "1616" + ] + }, + { + "id": "1618", + "parents": [ + "1617" + ] + }, + { + "id": "1619", + "parents": [ + "1618" + ] + }, + { + "id": "1620", + "parents": [ + "1619" + ] + }, + { + "id": "1621", + "parents": [ + "1620" + ] + }, + { + "id": "1622", + "parents": [ + "1621" + ] + }, + { + "id": "1623", + "parents": [ + "1622" + ] + }, + { + "id": "1624", + "parents": [ + "1623" + ] + }, + { + "id": "1625", + "parents": [ + "1624" + ] + }, + { + "id": "1626", + "parents": [ + "1625" + ] + }, + { + "id": "1627", + "parents": [ + "1626" + ] + }, + { + "id": "1628", + "parents": [ + "1627" + ] + }, + { + "id": "1629", + "parents": [ + "1628" + ] + }, + { + "id": "1630", + "parents": [ + "1629" + ] + }, + { + "id": "1631", + "parents": [ + "1630" + ] + }, + { + "id": "1632", + "parents": [ + "1631" + ] + }, + { + "id": "1633", + "parents": [ + "1632" + ] + }, + { + "id": "1634", + "parents": [ + "1633" + ] + }, + { + "id": "1635", + "parents": [ + "1634" + ] + }, + { + "id": "1636", + "parents": [ + "1635" + ] + }, + { + "id": "1637", + "parents": [ + "1636" + ] + }, + { + "id": "1638", + "parents": [ + "1637" + ] + }, + { + "id": "1639", + "parents": [ + "1638" + ] + }, + { + "id": "1640", + "parents": [ + "1639" + ] + }, + { + "id": "1641", + "parents": [ + "1640" + ] + }, + { + "id": "1642", + "parents": [ + "1641" + ] + }, + { + "id": "1643", + "parents": [ + "1642" + ] + }, + { + "id": "1644", + "parents": [ + "1643" + ] + }, + { + "id": "1645", + "parents": [ + "1644" + ] + }, + { + "id": "1646", + "parents": [ + "1645" + ] + }, + { + "id": "1647", + "parents": [ + "1646" + ] + }, + { + "id": "1648", + "parents": [ + "1647" + ] + }, + { + "id": "1649", + "parents": [ + "1648" + ] + }, + { + "id": "1650", + "parents": [ + "1649" + ] + }, + { + "id": "1651", + "parents": [ + "1650" + ] + }, + { + "id": "1652", + "parents": [ + "1651" + ] + }, + { + "id": "1653", + "parents": [ + "1652" + ] + }, + { + "id": "1654", + "parents": [ + "1653" + ] + }, + { + "id": "1655", + "parents": [ + "1654" + ] + }, + { + "id": "1656", + "parents": [ + "1655" + ] + }, + { + "id": "1657", + "parents": [ + "1656" + ] + }, + { + "id": "1658", + "parents": [ + "1657" + ] + }, + { + "id": "1659", + "parents": [ + "1658" + ] + }, + { + "id": "1660", + "parents": [ + "1659" + ] + }, + { + "id": "1661", + "parents": [ + "1660" + ] + }, + { + "id": "1662", + "parents": [ + "1661" + ] + }, + { + "id": "1663", + "parents": [ + "1662" + ] + }, + { + "id": "1664", + "parents": [ + "1663" + ] + }, + { + "id": "1665", + "parents": [ + "1664" + ] + }, + { + "id": "1666", + "parents": [ + "1665" + ] + }, + { + "id": "1667", + "parents": [ + "1666" + ] + }, + { + "id": "1668", + "parents": [ + "1667" + ] + }, + { + "id": "1669", + "parents": [ + "1668" + ] + }, + { + "id": "1670", + "parents": [ + "1669" + ] + }, + { + "id": "1671", + "parents": [ + "1670" + ] + }, + { + "id": "1672", + "parents": [ + "1671" + ] + }, + { + "id": "1673", + "parents": [ + "1672" + ] + }, + { + "id": "1674", + "parents": [ + "1673" + ] + }, + { + "id": "1675", + "parents": [ + "1674" + ] + }, + { + "id": "1676", + "parents": [ + "1675" + ] + }, + { + "id": "1677", + "parents": [ + "1676" + ] + }, + { + "id": "1678", + "parents": [ + "1677" + ] + }, + { + "id": "1679", + "parents": [ + "1678" + ] + }, + { + "id": "1680", + "parents": [ + "1679" + ] + }, + { + "id": "1681", + "parents": [ + "1680" + ] + }, + { + "id": "1682", + "parents": [ + "1681" + ] + }, + { + "id": "1683", + "parents": [ + "1682" + ] + }, + { + "id": "1684", + "parents": [ + "1683" + ] + }, + { + "id": "1685", + "parents": [ + "1684" + ] + }, + { + "id": "1686", + "parents": [ + "1685" + ] + }, + { + "id": "1687", + "parents": [ + "1686" + ] + }, + { + "id": "1688", + "parents": [ + "1687" + ] + }, + { + "id": "1689", + "parents": [ + "1688" + ] + }, + { + "id": "1690", + "parents": [ + "1689" + ] + }, + { + "id": "1691", + "parents": [ + "1690" + ] + }, + { + "id": "1692", + "parents": [ + "1691" + ] + }, + { + "id": "1693", + "parents": [ + "1692" + ] + }, + { + "id": "1694", + "parents": [ + "1693" + ] + }, + { + "id": "1695", + "parents": [ + "1694" + ] + }, + { + "id": "1696", + "parents": [ + "1695" + ] + }, + { + "id": "1697", + "parents": [ + "1696" + ] + }, + { + "id": "1698", + "parents": [ + "1697" + ] + }, + { + "id": "1699", + "parents": [ + "1698" + ] + }, + { + "id": "1700", + "parents": [ + "1699" + ] + }, + { + "id": "1701", + "parents": [ + "1700" + ] + }, + { + "id": "1702", + "parents": [ + "1701" + ] + }, + { + "id": "1703", + "parents": [ + "1702" + ] + }, + { + "id": "1704", + "parents": [ + "1703" + ] + }, + { + "id": "1705", + "parents": [ + "1704" + ] + }, + { + "id": "1706", + "parents": [ + "1705" + ] + }, + { + "id": "1707", + "parents": [ + "1706" + ] + }, + { + "id": "1708", + "parents": [ + "1707" + ] + }, + { + "id": "1709", + "parents": [ + "1708" + ] + }, + { + "id": "1710", + "parents": [ + "1709" + ] + }, + { + "id": "1711", + "parents": [ + "1710" + ] + }, + { + "id": "1712", + "parents": [ + "1711" + ] + }, + { + "id": "1713", + "parents": [ + "1712" + ] + }, + { + "id": "1714", + "parents": [ + "1713" + ] + }, + { + "id": "1715", + "parents": [ + "1714" + ] + }, + { + "id": "1716", + "parents": [ + "1715" + ] + }, + { + "id": "1717", + "parents": [ + "1716" + ] + }, + { + "id": "1718", + "parents": [ + "1717" + ] + }, + { + "id": "1719", + "parents": [ + "1718" + ] + }, + { + "id": "1720", + "parents": [ + "1719" + ] + }, + { + "id": "1721", + "parents": [ + "1720" + ] + }, + { + "id": "1722", + "parents": [ + "1721" + ] + }, + { + "id": "1723", + "parents": [ + "1722" + ] + }, + { + "id": "1724", + "parents": [ + "1723" + ] + }, + { + "id": "1725", + "parents": [ + "1724" + ] + }, + { + "id": "1726", + "parents": [ + "1725" + ] + }, + { + "id": "1727", + "parents": [ + "1726" + ] + }, + { + "id": "1728", + "parents": [ + "1727" + ] + }, + { + "id": "1729", + "parents": [ + "1728" + ] + }, + { + "id": "1730", + "parents": [ + "1729" + ] + }, + { + "id": "1731", + "parents": [ + "1730" + ] + }, + { + "id": "1732", + "parents": [ + "1731" + ] + }, + { + "id": "1733", + "parents": [ + "1732" + ] + }, + { + "id": "1734", + "parents": [ + "1733" + ] + }, + { + "id": "1735", + "parents": [ + "1734" + ] + }, + { + "id": "1736", + "parents": [ + "1735" + ] + }, + { + "id": "1737", + "parents": [ + "1736" + ] + }, + { + "id": "1738", + "parents": [ + "1737" + ] + }, + { + "id": "1739", + "parents": [ + "1738" + ] + }, + { + "id": "1740", + "parents": [ + "1739" + ] + }, + { + "id": "1741", + "parents": [ + "1740" + ] + }, + { + "id": "1742", + "parents": [ + "1741" + ] + }, + { + "id": "1743", + "parents": [ + "1742" + ] + }, + { + "id": "1744", + "parents": [ + "1743" + ] + }, + { + "id": "1745", + "parents": [ + "1744" + ] + }, + { + "id": "1746", + "parents": [ + "1745" + ] + }, + { + "id": "1747", + "parents": [ + "1746" + ] + }, + { + "id": "1748", + "parents": [ + "1747" + ] + }, + { + "id": "1749", + "parents": [ + "1748" + ] + }, + { + "id": "1750", + "parents": [ + "1749" + ] + }, + { + "id": "1751", + "parents": [ + "1750" + ] + }, + { + "id": "1752", + "parents": [ + "1751" + ] + }, + { + "id": "1753", + "parents": [ + "1752" + ] + }, + { + "id": "1754", + "parents": [ + "1753" + ] + }, + { + "id": "1755", + "parents": [ + "1754" + ] + }, + { + "id": "1756", + "parents": [ + "1755" + ] + }, + { + "id": "1757", + "parents": [ + "1756" + ] + }, + { + "id": "1758", + "parents": [ + "1757" + ] + }, + { + "id": "1759", + "parents": [ + "1758" + ] + }, + { + "id": "1760", + "parents": [ + "1759" + ] + }, + { + "id": "1761", + "parents": [ + "1760" + ] + }, + { + "id": "1762", + "parents": [ + "1761" + ] + }, + { + "id": "1763", + "parents": [ + "1762" + ] + }, + { + "id": "1764", + "parents": [ + "1763" + ] + }, + { + "id": "1765", + "parents": [ + "1764" + ] + }, + { + "id": "1766", + "parents": [ + "1765" + ] + }, + { + "id": "1767", + "parents": [ + "1766" + ] + }, + { + "id": "1768", + "parents": [ + "1767" + ] + }, + { + "id": "1769", + "parents": [ + "1768" + ] + }, + { + "id": "1770", + "parents": [ + "1769" + ] + }, + { + "id": "1771", + "parents": [ + "1770" + ] + }, + { + "id": "1772", + "parents": [ + "1771" + ] + }, + { + "id": "1773", + "parents": [ + "1772" + ] + }, + { + "id": "1774", + "parents": [ + "1773" + ] + }, + { + "id": "1775", + "parents": [ + "1774" + ] + }, + { + "id": "1776", + "parents": [ + "1775" + ] + }, + { + "id": "1777", + "parents": [ + "1776" + ] + }, + { + "id": "1778", + "parents": [ + "1777" + ] + }, + { + "id": "1779", + "parents": [ + "1778" + ] + }, + { + "id": "1780", + "parents": [ + "1779" + ] + }, + { + "id": "1781", + "parents": [ + "1780" + ] + }, + { + "id": "1782", + "parents": [ + "1781" + ] + }, + { + "id": "1783", + "parents": [ + "1782" + ] + }, + { + "id": "1784", + "parents": [ + "1783" + ] + }, + { + "id": "1785", + "parents": [ + "1784" + ] + }, + { + "id": "1786", + "parents": [ + "1785" + ] + }, + { + "id": "1787", + "parents": [ + "1786" + ] + }, + { + "id": "1788", + "parents": [ + "1787" + ] + }, + { + "id": "1789", + "parents": [ + "1788" + ] + }, + { + "id": "1790", + "parents": [ + "1789" + ] + }, + { + "id": "1791", + "parents": [ + "1790" + ] + }, + { + "id": "1792", + "parents": [ + "1791" + ] + }, + { + "id": "1793", + "parents": [ + "1792" + ] + }, + { + "id": "1794", + "parents": [ + "1793" + ] + }, + { + "id": "1795", + "parents": [ + "1794" + ] + }, + { + "id": "1796", + "parents": [ + "1795" + ] + }, + { + "id": "1797", + "parents": [ + "1796" + ] + }, + { + "id": "1798", + "parents": [ + "1797" + ] + }, + { + "id": "1799", + "parents": [ + "1798" + ] + }, + { + "id": "1800", + "parents": [ + "1799" + ] + }, + { + "id": "1801", + "parents": [ + "1800" + ] + }, + { + "id": "1802", + "parents": [ + "1801" + ] + }, + { + "id": "1803", + "parents": [ + "1802" + ] + }, + { + "id": "1804", + "parents": [ + "1803" + ] + }, + { + "id": "1805", + "parents": [ + "1804" + ] + }, + { + "id": "1806", + "parents": [ + "1805" + ] + }, + { + "id": "1807", + "parents": [ + "1806" + ] + }, + { + "id": "1808", + "parents": [ + "1807" + ] + }, + { + "id": "1809", + "parents": [ + "1808" + ] + }, + { + "id": "1810", + "parents": [ + "1809" + ] + }, + { + "id": "1811", + "parents": [ + "1810" + ] + }, + { + "id": "1812", + "parents": [ + "1811" + ] + }, + { + "id": "1813", + "parents": [ + "1812" + ] + }, + { + "id": "1814", + "parents": [ + "1813" + ] + }, + { + "id": "1815", + "parents": [ + "1814" + ] + }, + { + "id": "1816", + "parents": [ + "1815" + ] + }, + { + "id": "1817", + "parents": [ + "1816" + ] + }, + { + "id": "1818", + "parents": [ + "1817" + ] + }, + { + "id": "1819", + "parents": [ + "1818" + ] + }, + { + "id": "1820", + "parents": [ + "1819" + ] + }, + { + "id": "1821", + "parents": [ + "1820" + ] + }, + { + "id": "1822", + "parents": [ + "1821" + ] + }, + { + "id": "1823", + "parents": [ + "1822" + ] + }, + { + "id": "1824", + "parents": [ + "1823" + ] + }, + { + "id": "1825", + "parents": [ + "1824" + ] + }, + { + "id": "1826", + "parents": [ + "1825" + ] + }, + { + "id": "1827", + "parents": [ + "1826" + ] + }, + { + "id": "1828", + "parents": [ + "1827" + ] + }, + { + "id": "1829", + "parents": [ + "1828" + ] + }, + { + "id": "1830", + "parents": [ + "1829" + ] + }, + { + "id": "1831", + "parents": [ + "1830" + ] + }, + { + "id": "1832", + "parents": [ + "1831" + ] + }, + { + "id": "1833", + "parents": [ + "1832" + ] + }, + { + "id": "1834", + "parents": [ + "1833" + ] + }, + { + "id": "1835", + "parents": [ + "1834" + ] + }, + { + "id": "1836", + "parents": [ + "1835" + ] + }, + { + "id": "1837", + "parents": [ + "1836" + ] + }, + { + "id": "1838", + "parents": [ + "1837" + ] + }, + { + "id": "1839", + "parents": [ + "1838" + ] + }, + { + "id": "1840", + "parents": [ + "1839" + ] + }, + { + "id": "1841", + "parents": [ + "1840" + ] + }, + { + "id": "1842", + "parents": [ + "1841" + ] + }, + { + "id": "1843", + "parents": [ + "1842" + ] + }, + { + "id": "1844", + "parents": [ + "1843" + ] + }, + { + "id": "1845", + "parents": [ + "1844" + ] + }, + { + "id": "1846", + "parents": [ + "1845" + ] + }, + { + "id": "1847", + "parents": [ + "1846" + ] + }, + { + "id": "1848", + "parents": [ + "1847" + ] + }, + { + "id": "1849", + "parents": [ + "1848" + ] + }, + { + "id": "1850", + "parents": [ + "1849" + ] + }, + { + "id": "1851", + "parents": [ + "1850" + ] + }, + { + "id": "1852", + "parents": [ + "1851" + ] + }, + { + "id": "1853", + "parents": [ + "1852" + ] + }, + { + "id": "1854", + "parents": [ + "1853" + ] + }, + { + "id": "1855", + "parents": [ + "1854" + ] + }, + { + "id": "1856", + "parents": [ + "1855" + ] + }, + { + "id": "1857", + "parents": [ + "1856" + ] + }, + { + "id": "1858", + "parents": [ + "1857" + ] + }, + { + "id": "1859", + "parents": [ + "1858" + ] + }, + { + "id": "1860", + "parents": [ + "1859" + ] + }, + { + "id": "1861", + "parents": [ + "1860" + ] + }, + { + "id": "1862", + "parents": [ + "1861" + ] + }, + { + "id": "1863", + "parents": [ + "1862" + ] + }, + { + "id": "1864", + "parents": [ + "1863" + ] + }, + { + "id": "1865", + "parents": [ + "1864" + ] + }, + { + "id": "1866", + "parents": [ + "1865" + ] + }, + { + "id": "1867", + "parents": [ + "1866" + ] + }, + { + "id": "1868", + "parents": [ + "1867" + ] + }, + { + "id": "1869", + "parents": [ + "1868" + ] + }, + { + "id": "1870", + "parents": [ + "1869" + ] + }, + { + "id": "1871", + "parents": [ + "1870" + ] + }, + { + "id": "1872", + "parents": [ + "1871" + ] + }, + { + "id": "1873", + "parents": [ + "1872" + ] + }, + { + "id": "1874", + "parents": [ + "1873" + ] + }, + { + "id": "1875", + "parents": [ + "1874" + ] + }, + { + "id": "1876", + "parents": [ + "1875" + ] + }, + { + "id": "1877", + "parents": [ + "1876" + ] + }, + { + "id": "1878", + "parents": [ + "1877" + ] + }, + { + "id": "1879", + "parents": [ + "1878" + ] + }, + { + "id": "1880", + "parents": [ + "1879" + ] + }, + { + "id": "1881", + "parents": [ + "1880" + ] + }, + { + "id": "1882", + "parents": [ + "1881" + ] + }, + { + "id": "1883", + "parents": [ + "1882" + ] + }, + { + "id": "1884", + "parents": [ + "1883" + ] + }, + { + "id": "1885", + "parents": [ + "1884" + ] + }, + { + "id": "1886", + "parents": [ + "1885" + ] + }, + { + "id": "1887", + "parents": [ + "1886" + ] + }, + { + "id": "1888", + "parents": [ + "1887" + ] + }, + { + "id": "1889", + "parents": [ + "1888" + ] + }, + { + "id": "1890", + "parents": [ + "1889" + ] + }, + { + "id": "1891", + "parents": [ + "1890" + ] + }, + { + "id": "1892", + "parents": [ + "1891" + ] + }, + { + "id": "1893", + "parents": [ + "1892" + ] + }, + { + "id": "1894", + "parents": [ + "1893" + ] + }, + { + "id": "1895", + "parents": [ + "1894" + ] + }, + { + "id": "1896", + "parents": [ + "1895" + ] + }, + { + "id": "1897", + "parents": [ + "1896" + ] + }, + { + "id": "1898", + "parents": [ + "1897" + ] + }, + { + "id": "1899", + "parents": [ + "1898" + ] + }, + { + "id": "1900", + "parents": [ + "1899" + ] + }, + { + "id": "1901", + "parents": [ + "1900" + ] + }, + { + "id": "1902", + "parents": [ + "1901" + ] + }, + { + "id": "1903", + "parents": [ + "1902" + ] + }, + { + "id": "1904", + "parents": [ + "1903" + ] + }, + { + "id": "1905", + "parents": [ + "1904" + ] + }, + { + "id": "1906", + "parents": [ + "1905" + ] + }, + { + "id": "1907", + "parents": [ + "1906" + ] + }, + { + "id": "1908", + "parents": [ + "1907" + ] + }, + { + "id": "1909", + "parents": [ + "1908" + ] + }, + { + "id": "1910", + "parents": [ + "1909" + ] + }, + { + "id": "1911", + "parents": [ + "1910" + ] + }, + { + "id": "1912", + "parents": [ + "1911" + ] + }, + { + "id": "1913", + "parents": [ + "1912" + ] + }, + { + "id": "1914", + "parents": [ + "1913" + ] + }, + { + "id": "1915", + "parents": [ + "1914" + ] + }, + { + "id": "1916", + "parents": [ + "1915" + ] + }, + { + "id": "1917", + "parents": [ + "1916" + ] + }, + { + "id": "1918", + "parents": [ + "1917" + ] + }, + { + "id": "1919", + "parents": [ + "1918" + ] + }, + { + "id": "1920", + "parents": [ + "1919" + ] + }, + { + "id": "1921", + "parents": [ + "1920" + ] + }, + { + "id": "1922", + "parents": [ + "1921" + ] + }, + { + "id": "1923", + "parents": [ + "1922" + ] + }, + { + "id": "1924", + "parents": [ + "1923" + ] + }, + { + "id": "1925", + "parents": [ + "1924" + ] + }, + { + "id": "1926", + "parents": [ + "1925" + ] + }, + { + "id": "1927", + "parents": [ + "1926" + ] + }, + { + "id": "1928", + "parents": [ + "1927" + ] + }, + { + "id": "1929", + "parents": [ + "1928" + ] + }, + { + "id": "1930", + "parents": [ + "1929" + ] + }, + { + "id": "1931", + "parents": [ + "1930" + ] + }, + { + "id": "1932", + "parents": [ + "1931" + ] + }, + { + "id": "1933", + "parents": [ + "1932" + ] + }, + { + "id": "1934", + "parents": [ + "1933" + ] + }, + { + "id": "1935", + "parents": [ + "1934" + ] + }, + { + "id": "1936", + "parents": [ + "1935" + ] + }, + { + "id": "1937", + "parents": [ + "1936" + ] + }, + { + "id": "1938", + "parents": [ + "1937" + ] + }, + { + "id": "1939", + "parents": [ + "1938" + ] + }, + { + "id": "1940", + "parents": [ + "1939" + ] + }, + { + "id": "1941", + "parents": [ + "1940" + ] + }, + { + "id": "1942", + "parents": [ + "1941" + ] + }, + { + "id": "1943", + "parents": [ + "1942" + ] + }, + { + "id": "1944", + "parents": [ + "1943" + ] + }, + { + "id": "1945", + "parents": [ + "1944" + ] + }, + { + "id": "1946", + "parents": [ + "1945" + ] + }, + { + "id": "1947", + "parents": [ + "1946" + ] + }, + { + "id": "1948", + "parents": [ + "1947" + ] + }, + { + "id": "1949", + "parents": [ + "1948" + ] + }, + { + "id": "1950", + "parents": [ + "1949" + ] + }, + { + "id": "1951", + "parents": [ + "1950" + ] + }, + { + "id": "1952", + "parents": [ + "1951" + ] + }, + { + "id": "1953", + "parents": [ + "1952" + ] + }, + { + "id": "1954", + "parents": [ + "1953" + ] + }, + { + "id": "1955", + "parents": [ + "1954" + ] + }, + { + "id": "1956", + "parents": [ + "1955" + ] + }, + { + "id": "1957", + "parents": [ + "1956" + ] + }, + { + "id": "1958", + "parents": [ + "1957" + ] + }, + { + "id": "1959", + "parents": [ + "1958" + ] + }, + { + "id": "1960", + "parents": [ + "1959" + ] + }, + { + "id": "1961", + "parents": [ + "1960" + ] + }, + { + "id": "1962", + "parents": [ + "1961" + ] + }, + { + "id": "1963", + "parents": [ + "1962" + ] + }, + { + "id": "1964", + "parents": [ + "1963" + ] + }, + { + "id": "1965", + "parents": [ + "1964" + ] + }, + { + "id": "1966", + "parents": [ + "1965" + ] + }, + { + "id": "1967", + "parents": [ + "1966" + ] + }, + { + "id": "1968", + "parents": [ + "1967" + ] + }, + { + "id": "1969", + "parents": [ + "1968" + ] + }, + { + "id": "1970", + "parents": [ + "1969" + ] + }, + { + "id": "1971", + "parents": [ + "1970" + ] + }, + { + "id": "1972", + "parents": [ + "1971" + ] + }, + { + "id": "1973", + "parents": [ + "1972" + ] + }, + { + "id": "1974", + "parents": [ + "1973" + ] + }, + { + "id": "1975", + "parents": [ + "1974" + ] + }, + { + "id": "1976", + "parents": [ + "1975" + ] + }, + { + "id": "1977", + "parents": [ + "1976" + ] + }, + { + "id": "1978", + "parents": [ + "1977" + ] + }, + { + "id": "1979", + "parents": [ + "1978" + ] + }, + { + "id": "1980", + "parents": [ + "1979" + ] + }, + { + "id": "1981", + "parents": [ + "1980" + ] + }, + { + "id": "1982", + "parents": [ + "1981" + ] + }, + { + "id": "1983", + "parents": [ + "1982" + ] + }, + { + "id": "1984", + "parents": [ + "1983" + ] + }, + { + "id": "1985", + "parents": [ + "1984" + ] + }, + { + "id": "1986", + "parents": [ + "1985" + ] + }, + { + "id": "1987", + "parents": [ + "1986" + ] + }, + { + "id": "1988", + "parents": [ + "1987" + ] + }, + { + "id": "1989", + "parents": [ + "1988" + ] + }, + { + "id": "1990", + "parents": [ + "1989" + ] + }, + { + "id": "1991", + "parents": [ + "1990" + ] + }, + { + "id": "1992", + "parents": [ + "1991" + ] + }, + { + "id": "1993", + "parents": [ + "1992" + ] + }, + { + "id": "1994", + "parents": [ + "1993" + ] + }, + { + "id": "1995", + "parents": [ + "1994" + ] + }, + { + "id": "1996", + "parents": [ + "1995" + ] + }, + { + "id": "1997", + "parents": [ + "1996" + ] + }, + { + "id": "1998", + "parents": [ + "1997" + ] + }, + { + "id": "1999", + "parents": [ + "1998" + ] } ] } \ No newline at end of file diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index f62c10a96..929df0be8 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -5,44 +5,15 @@ import ( ) func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { - isAwaitingUTXOSet, ibdRootUTXOBlockHash, err := sm.isAwaitingUTXOSet() - if err != nil { - return nil, err - } - headerCount := sm.getHeaderCount() blockCount := sm.getBlockCount() return &externalapi.SyncInfo{ - IsAwaitingUTXOSet: isAwaitingUTXOSet, - IBDRootUTXOBlockHash: ibdRootUTXOBlockHash, - HeaderCount: headerCount, - BlockCount: blockCount, + HeaderCount: headerCount, + BlockCount: blockCount, }, nil } -func (sm *syncManager) isAwaitingUTXOSet() (isAwaitingUTXOSet bool, ibdRootUTXOBlockHash *externalapi.DomainHash, - err error) { - - pruningPointByHeaders, err := sm.pruningManager.CalculatePruningPointByHeaderSelectedTip() - if err != nil { - return false, nil, err - } - - pruningPoint, err := sm.pruningStore.PruningPoint(sm.databaseContext) - if err != nil { - return false, nil, err - } - - // 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.Equal(pruningPointByHeaders) { - return true, pruningPointByHeaders, nil - } - - return false, nil, nil -} - func (sm *syncManager) getHeaderCount() uint64 { return sm.blockHeaderStore.Count() } diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 667e57402..8e8c50c8f 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -177,6 +177,8 @@ var ( ErrPruningPointViolation = newRuleError("ErrPruningPointViolation") ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint") + + ErrSuggestedPruningViolatesFinality = newRuleError("ErrSuggestedPruningViolatesFinality") ) // RuleError identifies a rule violation. It is used to indicate that diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 3c4c3ff73..20908c403 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -56,6 +56,8 @@ type KaspadMessage struct { // *KaspadMessage_IbdRootUTXOSetAndBlock // *KaspadMessage_RequestIBDBlocks // *KaspadMessage_IbdRootNotFound + // *KaspadMessage_RequestIBDRootHash + // *KaspadMessage_IbdRootHash // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -331,6 +333,20 @@ func (x *KaspadMessage) GetIbdRootNotFound() *IBDRootNotFoundMessage { return nil } +func (x *KaspadMessage) GetRequestIBDRootHash() *RequestIBDRootHash { + if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDRootHash); ok { + return x.RequestIBDRootHash + } + return nil +} + +func (x *KaspadMessage) GetIbdRootHash() *IBDRootHash { + if x, ok := x.GetPayload().(*KaspadMessage_IbdRootHash); ok { + return x.IbdRootHash + } + return nil +} + func (x *KaspadMessage) GetGetCurrentNetworkRequest() *GetCurrentNetworkRequestMessage { if x, ok := x.GetPayload().(*KaspadMessage_GetCurrentNetworkRequest); ok { return x.GetCurrentNetworkRequest @@ -841,6 +857,14 @@ type KaspadMessage_IbdRootNotFound struct { IbdRootNotFound *IBDRootNotFoundMessage `protobuf:"bytes,27,opt,name=ibdRootNotFound,proto3,oneof"` } +type KaspadMessage_RequestIBDRootHash struct { + RequestIBDRootHash *RequestIBDRootHash `protobuf:"bytes,28,opt,name=requestIBDRootHash,proto3,oneof"` +} + +type KaspadMessage_IbdRootHash struct { + IbdRootHash *IBDRootHash `protobuf:"bytes,29,opt,name=ibdRootHash,proto3,oneof"` +} + type KaspadMessage_GetCurrentNetworkRequest struct { GetCurrentNetworkRequest *GetCurrentNetworkRequestMessage `protobuf:"bytes,1001,opt,name=getCurrentNetworkRequest,proto3,oneof"` } @@ -1123,6 +1147,10 @@ func (*KaspadMessage_RequestIBDBlocks) isKaspadMessage_Payload() {} func (*KaspadMessage_IbdRootNotFound) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestIBDRootHash) isKaspadMessage_Payload() {} + +func (*KaspadMessage_IbdRootHash) isKaspadMessage_Payload() {} + func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkResponse) isKaspadMessage_Payload() {} @@ -2963,6 +2991,93 @@ func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{31} } +// RequestIBDRootHash start +type RequestIBDRootHash struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RequestIBDRootHash) Reset() { + *x = RequestIBDRootHash{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestIBDRootHash) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestIBDRootHash) ProtoMessage() {} + +func (x *RequestIBDRootHash) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestIBDRootHash.ProtoReflect.Descriptor instead. +func (*RequestIBDRootHash) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{32} +} + +// IBDRootHash start +type IBDRootHash struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (x *IBDRootHash) Reset() { + *x = IBDRootHash{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IBDRootHash) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IBDRootHash) ProtoMessage() {} + +func (x *IBDRootHash) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IBDRootHash.ProtoReflect.Descriptor instead. +func (*IBDRootHash) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{33} +} + +func (x *IBDRootHash) GetHash() *Hash { + if x != nil { + return x.Hash + } + return nil +} + type RPCError struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2974,7 +3089,7 @@ type RPCError struct { func (x *RPCError) Reset() { *x = RPCError{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2987,7 +3102,7 @@ func (x *RPCError) String() string { func (*RPCError) ProtoMessage() {} func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3000,7 +3115,7 @@ func (x *RPCError) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCError.ProtoReflect.Descriptor instead. func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{32} + return file_messages_proto_rawDescGZIP(), []int{34} } func (x *RPCError) GetMessage() string { @@ -3019,7 +3134,7 @@ type GetCurrentNetworkRequestMessage struct { func (x *GetCurrentNetworkRequestMessage) Reset() { *x = GetCurrentNetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3032,7 +3147,7 @@ func (x *GetCurrentNetworkRequestMessage) String() string { func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3045,7 +3160,7 @@ func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{33} + return file_messages_proto_rawDescGZIP(), []int{35} } type GetCurrentNetworkResponseMessage struct { @@ -3060,7 +3175,7 @@ type GetCurrentNetworkResponseMessage struct { func (x *GetCurrentNetworkResponseMessage) Reset() { *x = GetCurrentNetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3073,7 +3188,7 @@ func (x *GetCurrentNetworkResponseMessage) String() string { func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3086,7 +3201,7 @@ func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} + return file_messages_proto_rawDescGZIP(), []int{36} } func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { @@ -3114,7 +3229,7 @@ type SubmitBlockRequestMessage struct { func (x *SubmitBlockRequestMessage) Reset() { *x = SubmitBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3127,7 +3242,7 @@ func (x *SubmitBlockRequestMessage) String() string { func (*SubmitBlockRequestMessage) ProtoMessage() {} func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3140,7 +3255,7 @@ func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{35} + return file_messages_proto_rawDescGZIP(), []int{37} } func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { @@ -3161,7 +3276,7 @@ type SubmitBlockResponseMessage struct { func (x *SubmitBlockResponseMessage) Reset() { *x = SubmitBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3174,7 +3289,7 @@ func (x *SubmitBlockResponseMessage) String() string { func (*SubmitBlockResponseMessage) ProtoMessage() {} func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3187,7 +3302,7 @@ func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} + return file_messages_proto_rawDescGZIP(), []int{38} } func (x *SubmitBlockResponseMessage) GetError() *RPCError { @@ -3208,7 +3323,7 @@ type GetBlockTemplateRequestMessage struct { func (x *GetBlockTemplateRequestMessage) Reset() { *x = GetBlockTemplateRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3221,7 +3336,7 @@ func (x *GetBlockTemplateRequestMessage) String() string { func (*GetBlockTemplateRequestMessage) ProtoMessage() {} func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3234,7 +3349,7 @@ func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} + return file_messages_proto_rawDescGZIP(), []int{39} } func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { @@ -3256,7 +3371,7 @@ type GetBlockTemplateResponseMessage struct { func (x *GetBlockTemplateResponseMessage) Reset() { *x = GetBlockTemplateResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3269,7 +3384,7 @@ func (x *GetBlockTemplateResponseMessage) String() string { func (*GetBlockTemplateResponseMessage) ProtoMessage() {} func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3282,7 +3397,7 @@ func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} + return file_messages_proto_rawDescGZIP(), []int{40} } func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { @@ -3308,7 +3423,7 @@ type NotifyBlockAddedRequestMessage struct { func (x *NotifyBlockAddedRequestMessage) Reset() { *x = NotifyBlockAddedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3321,7 +3436,7 @@ func (x *NotifyBlockAddedRequestMessage) String() string { func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3334,7 +3449,7 @@ func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} + return file_messages_proto_rawDescGZIP(), []int{41} } type NotifyBlockAddedResponseMessage struct { @@ -3348,7 +3463,7 @@ type NotifyBlockAddedResponseMessage struct { func (x *NotifyBlockAddedResponseMessage) Reset() { *x = NotifyBlockAddedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3361,7 +3476,7 @@ func (x *NotifyBlockAddedResponseMessage) String() string { func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3374,7 +3489,7 @@ func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} + return file_messages_proto_rawDescGZIP(), []int{42} } func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { @@ -3395,7 +3510,7 @@ type BlockAddedNotificationMessage struct { func (x *BlockAddedNotificationMessage) Reset() { *x = BlockAddedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3408,7 +3523,7 @@ func (x *BlockAddedNotificationMessage) String() string { func (*BlockAddedNotificationMessage) ProtoMessage() {} func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3421,7 +3536,7 @@ func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} + return file_messages_proto_rawDescGZIP(), []int{43} } func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { @@ -3440,7 +3555,7 @@ type GetPeerAddressesRequestMessage struct { func (x *GetPeerAddressesRequestMessage) Reset() { *x = GetPeerAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3453,7 +3568,7 @@ func (x *GetPeerAddressesRequestMessage) String() string { func (*GetPeerAddressesRequestMessage) ProtoMessage() {} func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3466,7 +3581,7 @@ func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} + return file_messages_proto_rawDescGZIP(), []int{44} } type GetPeerAddressesResponseMessage struct { @@ -3482,7 +3597,7 @@ type GetPeerAddressesResponseMessage struct { func (x *GetPeerAddressesResponseMessage) Reset() { *x = GetPeerAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3495,7 +3610,7 @@ func (x *GetPeerAddressesResponseMessage) String() string { func (*GetPeerAddressesResponseMessage) ProtoMessage() {} func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3508,7 +3623,7 @@ func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} + return file_messages_proto_rawDescGZIP(), []int{45} } func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { @@ -3543,7 +3658,7 @@ type GetPeerAddressesKnownAddressMessage struct { func (x *GetPeerAddressesKnownAddressMessage) Reset() { *x = GetPeerAddressesKnownAddressMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3556,7 +3671,7 @@ func (x *GetPeerAddressesKnownAddressMessage) String() string { func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3569,7 +3684,7 @@ func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} + return file_messages_proto_rawDescGZIP(), []int{46} } func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { @@ -3588,7 +3703,7 @@ type GetSelectedTipHashRequestMessage struct { func (x *GetSelectedTipHashRequestMessage) Reset() { *x = GetSelectedTipHashRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3601,7 +3716,7 @@ func (x *GetSelectedTipHashRequestMessage) String() string { func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3614,7 +3729,7 @@ func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} + return file_messages_proto_rawDescGZIP(), []int{47} } type GetSelectedTipHashResponseMessage struct { @@ -3629,7 +3744,7 @@ type GetSelectedTipHashResponseMessage struct { func (x *GetSelectedTipHashResponseMessage) Reset() { *x = GetSelectedTipHashResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3642,7 +3757,7 @@ func (x *GetSelectedTipHashResponseMessage) String() string { func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3655,7 +3770,7 @@ func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} + return file_messages_proto_rawDescGZIP(), []int{48} } func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { @@ -3685,7 +3800,7 @@ type MempoolEntry struct { func (x *MempoolEntry) Reset() { *x = MempoolEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3698,7 +3813,7 @@ func (x *MempoolEntry) String() string { func (*MempoolEntry) ProtoMessage() {} func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3711,7 +3826,7 @@ func (x *MempoolEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} + return file_messages_proto_rawDescGZIP(), []int{49} } func (x *MempoolEntry) GetFee() uint64 { @@ -3739,7 +3854,7 @@ type GetMempoolEntryRequestMessage struct { func (x *GetMempoolEntryRequestMessage) Reset() { *x = GetMempoolEntryRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3752,7 +3867,7 @@ func (x *GetMempoolEntryRequestMessage) String() string { func (*GetMempoolEntryRequestMessage) ProtoMessage() {} func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3765,7 +3880,7 @@ func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} + return file_messages_proto_rawDescGZIP(), []int{50} } func (x *GetMempoolEntryRequestMessage) GetTxId() string { @@ -3787,7 +3902,7 @@ type GetMempoolEntryResponseMessage struct { func (x *GetMempoolEntryResponseMessage) Reset() { *x = GetMempoolEntryResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3800,7 +3915,7 @@ func (x *GetMempoolEntryResponseMessage) String() string { func (*GetMempoolEntryResponseMessage) ProtoMessage() {} func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3813,7 +3928,7 @@ func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} + return file_messages_proto_rawDescGZIP(), []int{51} } func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { @@ -3839,7 +3954,7 @@ type GetMempoolEntriesRequestMessage struct { func (x *GetMempoolEntriesRequestMessage) Reset() { *x = GetMempoolEntriesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3852,7 +3967,7 @@ func (x *GetMempoolEntriesRequestMessage) String() string { func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3865,7 +3980,7 @@ func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} + return file_messages_proto_rawDescGZIP(), []int{52} } type GetMempoolEntriesResponseMessage struct { @@ -3880,7 +3995,7 @@ type GetMempoolEntriesResponseMessage struct { func (x *GetMempoolEntriesResponseMessage) Reset() { *x = GetMempoolEntriesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3893,7 +4008,7 @@ func (x *GetMempoolEntriesResponseMessage) String() string { func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3906,7 +4021,7 @@ func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} + return file_messages_proto_rawDescGZIP(), []int{53} } func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { @@ -3932,7 +4047,7 @@ type GetConnectedPeerInfoRequestMessage struct { func (x *GetConnectedPeerInfoRequestMessage) Reset() { *x = GetConnectedPeerInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3945,7 +4060,7 @@ func (x *GetConnectedPeerInfoRequestMessage) String() string { func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3958,7 +4073,7 @@ func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} + return file_messages_proto_rawDescGZIP(), []int{54} } type GetConnectedPeerInfoResponseMessage struct { @@ -3973,7 +4088,7 @@ type GetConnectedPeerInfoResponseMessage struct { func (x *GetConnectedPeerInfoResponseMessage) Reset() { *x = GetConnectedPeerInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3986,7 +4101,7 @@ func (x *GetConnectedPeerInfoResponseMessage) String() string { func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3999,7 +4114,7 @@ func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} + return file_messages_proto_rawDescGZIP(), []int{55} } func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { @@ -4034,7 +4149,7 @@ type GetConnectedPeerInfoMessage struct { func (x *GetConnectedPeerInfoMessage) Reset() { *x = GetConnectedPeerInfoMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4047,7 +4162,7 @@ func (x *GetConnectedPeerInfoMessage) String() string { func (*GetConnectedPeerInfoMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4060,7 +4175,7 @@ func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} + return file_messages_proto_rawDescGZIP(), []int{56} } func (x *GetConnectedPeerInfoMessage) GetId() string { @@ -4131,7 +4246,7 @@ type AddPeerRequestMessage struct { func (x *AddPeerRequestMessage) Reset() { *x = AddPeerRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4144,7 +4259,7 @@ func (x *AddPeerRequestMessage) String() string { func (*AddPeerRequestMessage) ProtoMessage() {} func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4157,7 +4272,7 @@ func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} + return file_messages_proto_rawDescGZIP(), []int{57} } func (x *AddPeerRequestMessage) GetAddress() string { @@ -4185,7 +4300,7 @@ type AddPeerResponseMessage struct { func (x *AddPeerResponseMessage) Reset() { *x = AddPeerResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4198,7 +4313,7 @@ func (x *AddPeerResponseMessage) String() string { func (*AddPeerResponseMessage) ProtoMessage() {} func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4211,7 +4326,7 @@ func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} + return file_messages_proto_rawDescGZIP(), []int{58} } func (x *AddPeerResponseMessage) GetError() *RPCError { @@ -4232,7 +4347,7 @@ type SubmitTransactionRequestMessage struct { func (x *SubmitTransactionRequestMessage) Reset() { *x = SubmitTransactionRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4245,7 +4360,7 @@ func (x *SubmitTransactionRequestMessage) String() string { func (*SubmitTransactionRequestMessage) ProtoMessage() {} func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4258,7 +4373,7 @@ func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} + return file_messages_proto_rawDescGZIP(), []int{59} } func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { @@ -4280,7 +4395,7 @@ type SubmitTransactionResponseMessage struct { func (x *SubmitTransactionResponseMessage) Reset() { *x = SubmitTransactionResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4293,7 +4408,7 @@ func (x *SubmitTransactionResponseMessage) String() string { func (*SubmitTransactionResponseMessage) ProtoMessage() {} func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4306,7 +4421,7 @@ func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} + return file_messages_proto_rawDescGZIP(), []int{60} } func (x *SubmitTransactionResponseMessage) GetTransactionId() string { @@ -4332,7 +4447,7 @@ type NotifyVirtualSelectedParentChainChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4345,7 +4460,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4358,7 +4473,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() p // Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} + return file_messages_proto_rawDescGZIP(), []int{61} } type NotifyVirtualSelectedParentChainChangedResponseMessage struct { @@ -4372,7 +4487,7 @@ type NotifyVirtualSelectedParentChainChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4385,7 +4500,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4398,7 +4513,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() // Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} + return file_messages_proto_rawDescGZIP(), []int{62} } func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { @@ -4420,7 +4535,7 @@ type VirtualSelectedParentChainChangedNotificationMessage struct { func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { *x = VirtualSelectedParentChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4433,7 +4548,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4446,7 +4561,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() pr // Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} + return file_messages_proto_rawDescGZIP(), []int{63} } func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { @@ -4475,7 +4590,7 @@ type ChainBlock struct { func (x *ChainBlock) Reset() { *x = ChainBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4488,7 +4603,7 @@ func (x *ChainBlock) String() string { func (*ChainBlock) ProtoMessage() {} func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4501,7 +4616,7 @@ func (x *ChainBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} + return file_messages_proto_rawDescGZIP(), []int{64} } func (x *ChainBlock) GetHash() string { @@ -4530,7 +4645,7 @@ type AcceptedBlock struct { func (x *AcceptedBlock) Reset() { *x = AcceptedBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4543,7 +4658,7 @@ func (x *AcceptedBlock) String() string { func (*AcceptedBlock) ProtoMessage() {} func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4556,7 +4671,7 @@ func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} + return file_messages_proto_rawDescGZIP(), []int{65} } func (x *AcceptedBlock) GetHash() string { @@ -4586,7 +4701,7 @@ type GetBlockRequestMessage struct { func (x *GetBlockRequestMessage) Reset() { *x = GetBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4599,7 +4714,7 @@ func (x *GetBlockRequestMessage) String() string { func (*GetBlockRequestMessage) ProtoMessage() {} func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4612,7 +4727,7 @@ func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} + return file_messages_proto_rawDescGZIP(), []int{66} } func (x *GetBlockRequestMessage) GetHash() string { @@ -4649,7 +4764,7 @@ type GetBlockResponseMessage struct { func (x *GetBlockResponseMessage) Reset() { *x = GetBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4662,7 +4777,7 @@ func (x *GetBlockResponseMessage) String() string { func (*GetBlockResponseMessage) ProtoMessage() {} func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4675,7 +4790,7 @@ func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} + return file_messages_proto_rawDescGZIP(), []int{67} } func (x *GetBlockResponseMessage) GetBlockHash() string { @@ -4723,7 +4838,7 @@ type BlockVerboseData struct { func (x *BlockVerboseData) Reset() { *x = BlockVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4736,7 +4851,7 @@ func (x *BlockVerboseData) String() string { func (*BlockVerboseData) ProtoMessage() {} func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4749,7 +4864,7 @@ func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} + return file_messages_proto_rawDescGZIP(), []int{68} } func (x *BlockVerboseData) GetHash() string { @@ -4874,7 +4989,7 @@ type TransactionVerboseData struct { func (x *TransactionVerboseData) Reset() { *x = TransactionVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4887,7 +5002,7 @@ func (x *TransactionVerboseData) String() string { func (*TransactionVerboseData) ProtoMessage() {} func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4900,7 +5015,7 @@ func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} + return file_messages_proto_rawDescGZIP(), []int{69} } func (x *TransactionVerboseData) GetTxId() string { @@ -5015,7 +5130,7 @@ type TransactionVerboseInput struct { func (x *TransactionVerboseInput) Reset() { *x = TransactionVerboseInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5028,7 +5143,7 @@ func (x *TransactionVerboseInput) String() string { func (*TransactionVerboseInput) ProtoMessage() {} func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5041,7 +5156,7 @@ func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} + return file_messages_proto_rawDescGZIP(), []int{70} } func (x *TransactionVerboseInput) GetTxId() string { @@ -5084,7 +5199,7 @@ type ScriptSig struct { func (x *ScriptSig) Reset() { *x = ScriptSig{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5097,7 +5212,7 @@ func (x *ScriptSig) String() string { func (*ScriptSig) ProtoMessage() {} func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5110,7 +5225,7 @@ func (x *ScriptSig) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} + return file_messages_proto_rawDescGZIP(), []int{71} } func (x *ScriptSig) GetAsm() string { @@ -5140,7 +5255,7 @@ type TransactionVerboseOutput struct { func (x *TransactionVerboseOutput) Reset() { *x = TransactionVerboseOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5153,7 +5268,7 @@ func (x *TransactionVerboseOutput) String() string { func (*TransactionVerboseOutput) ProtoMessage() {} func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5166,7 +5281,7 @@ func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} + return file_messages_proto_rawDescGZIP(), []int{72} } func (x *TransactionVerboseOutput) GetValue() uint64 { @@ -5204,7 +5319,7 @@ type ScriptPubKeyResult struct { func (x *ScriptPubKeyResult) Reset() { *x = ScriptPubKeyResult{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5217,7 +5332,7 @@ func (x *ScriptPubKeyResult) String() string { func (*ScriptPubKeyResult) ProtoMessage() {} func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5230,7 +5345,7 @@ func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptPubKeyResult.ProtoReflect.Descriptor instead. func (*ScriptPubKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} + return file_messages_proto_rawDescGZIP(), []int{73} } func (x *ScriptPubKeyResult) GetAsm() string { @@ -5272,7 +5387,7 @@ type GetSubnetworkRequestMessage struct { func (x *GetSubnetworkRequestMessage) Reset() { *x = GetSubnetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5285,7 +5400,7 @@ func (x *GetSubnetworkRequestMessage) String() string { func (*GetSubnetworkRequestMessage) ProtoMessage() {} func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5298,7 +5413,7 @@ func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} + return file_messages_proto_rawDescGZIP(), []int{74} } func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { @@ -5320,7 +5435,7 @@ type GetSubnetworkResponseMessage struct { func (x *GetSubnetworkResponseMessage) Reset() { *x = GetSubnetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5333,7 +5448,7 @@ func (x *GetSubnetworkResponseMessage) String() string { func (*GetSubnetworkResponseMessage) ProtoMessage() {} func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5346,7 +5461,7 @@ func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} + return file_messages_proto_rawDescGZIP(), []int{75} } func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { @@ -5374,7 +5489,7 @@ type GetVirtualSelectedParentChainFromBlockRequestMessage struct { func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5387,7 +5502,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5400,7 +5515,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() pr // Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} + return file_messages_proto_rawDescGZIP(), []int{76} } func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { @@ -5423,7 +5538,7 @@ type GetVirtualSelectedParentChainFromBlockResponseMessage struct { func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5436,7 +5551,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5449,7 +5564,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() p // Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} + return file_messages_proto_rawDescGZIP(), []int{77} } func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { @@ -5487,7 +5602,7 @@ type GetBlocksRequestMessage struct { func (x *GetBlocksRequestMessage) Reset() { *x = GetBlocksRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5500,7 +5615,7 @@ func (x *GetBlocksRequestMessage) String() string { func (*GetBlocksRequestMessage) ProtoMessage() {} func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5513,7 +5628,7 @@ func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} + return file_messages_proto_rawDescGZIP(), []int{78} } func (x *GetBlocksRequestMessage) GetLowHash() string { @@ -5558,7 +5673,7 @@ type GetBlocksResponseMessage struct { func (x *GetBlocksResponseMessage) Reset() { *x = GetBlocksResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5571,7 +5686,7 @@ func (x *GetBlocksResponseMessage) String() string { func (*GetBlocksResponseMessage) ProtoMessage() {} func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5584,7 +5699,7 @@ func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} + return file_messages_proto_rawDescGZIP(), []int{79} } func (x *GetBlocksResponseMessage) GetBlockHashes() []string { @@ -5624,7 +5739,7 @@ type GetBlockCountRequestMessage struct { func (x *GetBlockCountRequestMessage) Reset() { *x = GetBlockCountRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5637,7 +5752,7 @@ func (x *GetBlockCountRequestMessage) String() string { func (*GetBlockCountRequestMessage) ProtoMessage() {} func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5650,7 +5765,7 @@ func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} + return file_messages_proto_rawDescGZIP(), []int{80} } type GetBlockCountResponseMessage struct { @@ -5666,7 +5781,7 @@ type GetBlockCountResponseMessage struct { func (x *GetBlockCountResponseMessage) Reset() { *x = GetBlockCountResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5679,7 +5794,7 @@ func (x *GetBlockCountResponseMessage) String() string { func (*GetBlockCountResponseMessage) ProtoMessage() {} func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5692,7 +5807,7 @@ func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} + return file_messages_proto_rawDescGZIP(), []int{81} } func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { @@ -5725,7 +5840,7 @@ type GetBlockDagInfoRequestMessage struct { func (x *GetBlockDagInfoRequestMessage) Reset() { *x = GetBlockDagInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5738,7 +5853,7 @@ func (x *GetBlockDagInfoRequestMessage) String() string { func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5751,7 +5866,7 @@ func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} + return file_messages_proto_rawDescGZIP(), []int{82} } type GetBlockDagInfoResponseMessage struct { @@ -5772,7 +5887,7 @@ type GetBlockDagInfoResponseMessage struct { func (x *GetBlockDagInfoResponseMessage) Reset() { *x = GetBlockDagInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5785,7 +5900,7 @@ func (x *GetBlockDagInfoResponseMessage) String() string { func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5798,7 +5913,7 @@ func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} + return file_messages_proto_rawDescGZIP(), []int{83} } func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { @@ -5868,7 +5983,7 @@ type ResolveFinalityConflictRequestMessage struct { func (x *ResolveFinalityConflictRequestMessage) Reset() { *x = ResolveFinalityConflictRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5881,7 +5996,7 @@ func (x *ResolveFinalityConflictRequestMessage) String() string { func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5894,7 +6009,7 @@ func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} + return file_messages_proto_rawDescGZIP(), []int{84} } func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { @@ -5915,7 +6030,7 @@ type ResolveFinalityConflictResponseMessage struct { func (x *ResolveFinalityConflictResponseMessage) Reset() { *x = ResolveFinalityConflictResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5928,7 +6043,7 @@ func (x *ResolveFinalityConflictResponseMessage) String() string { func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5941,7 +6056,7 @@ func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} + return file_messages_proto_rawDescGZIP(), []int{85} } func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { @@ -5960,7 +6075,7 @@ type NotifyFinalityConflictsRequestMessage struct { func (x *NotifyFinalityConflictsRequestMessage) Reset() { *x = NotifyFinalityConflictsRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5973,7 +6088,7 @@ func (x *NotifyFinalityConflictsRequestMessage) String() string { func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5986,7 +6101,7 @@ func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} + return file_messages_proto_rawDescGZIP(), []int{86} } type NotifyFinalityConflictsResponseMessage struct { @@ -6000,7 +6115,7 @@ type NotifyFinalityConflictsResponseMessage struct { func (x *NotifyFinalityConflictsResponseMessage) Reset() { *x = NotifyFinalityConflictsResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6013,7 +6128,7 @@ func (x *NotifyFinalityConflictsResponseMessage) String() string { func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6026,7 +6141,7 @@ func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} + return file_messages_proto_rawDescGZIP(), []int{87} } func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { @@ -6047,7 +6162,7 @@ type FinalityConflictNotificationMessage struct { func (x *FinalityConflictNotificationMessage) Reset() { *x = FinalityConflictNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6060,7 +6175,7 @@ func (x *FinalityConflictNotificationMessage) String() string { func (*FinalityConflictNotificationMessage) ProtoMessage() {} func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6073,7 +6188,7 @@ func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} + return file_messages_proto_rawDescGZIP(), []int{88} } func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { @@ -6094,7 +6209,7 @@ type FinalityConflictResolvedNotificationMessage struct { func (x *FinalityConflictResolvedNotificationMessage) Reset() { *x = FinalityConflictResolvedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6107,7 +6222,7 @@ func (x *FinalityConflictResolvedNotificationMessage) String() string { func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6120,7 +6235,7 @@ func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflec // Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} + return file_messages_proto_rawDescGZIP(), []int{89} } func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { @@ -6139,7 +6254,7 @@ type ShutDownRequestMessage struct { func (x *ShutDownRequestMessage) Reset() { *x = ShutDownRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6152,7 +6267,7 @@ func (x *ShutDownRequestMessage) String() string { func (*ShutDownRequestMessage) ProtoMessage() {} func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6165,7 +6280,7 @@ func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} + return file_messages_proto_rawDescGZIP(), []int{90} } type ShutDownResponseMessage struct { @@ -6179,7 +6294,7 @@ type ShutDownResponseMessage struct { func (x *ShutDownResponseMessage) Reset() { *x = ShutDownResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6192,7 +6307,7 @@ func (x *ShutDownResponseMessage) String() string { func (*ShutDownResponseMessage) ProtoMessage() {} func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6205,7 +6320,7 @@ func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} + return file_messages_proto_rawDescGZIP(), []int{91} } func (x *ShutDownResponseMessage) GetError() *RPCError { @@ -6228,7 +6343,7 @@ type GetHeadersRequestMessage struct { func (x *GetHeadersRequestMessage) Reset() { *x = GetHeadersRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6241,7 +6356,7 @@ func (x *GetHeadersRequestMessage) String() string { func (*GetHeadersRequestMessage) ProtoMessage() {} func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[92] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6254,7 +6369,7 @@ func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{90} + return file_messages_proto_rawDescGZIP(), []int{92} } func (x *GetHeadersRequestMessage) GetStartHash() string { @@ -6290,7 +6405,7 @@ type GetHeadersResponseMessage struct { func (x *GetHeadersResponseMessage) Reset() { *x = GetHeadersResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6303,7 +6418,7 @@ func (x *GetHeadersResponseMessage) String() string { func (*GetHeadersResponseMessage) ProtoMessage() {} func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[93] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6316,7 +6431,7 @@ func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{91} + return file_messages_proto_rawDescGZIP(), []int{93} } func (x *GetHeadersResponseMessage) GetHeaders() []string { @@ -6344,7 +6459,7 @@ type NotifyUtxosChangedRequestMessage struct { func (x *NotifyUtxosChangedRequestMessage) Reset() { *x = NotifyUtxosChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6357,7 +6472,7 @@ func (x *NotifyUtxosChangedRequestMessage) String() string { func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[94] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6370,7 +6485,7 @@ func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{92} + return file_messages_proto_rawDescGZIP(), []int{94} } func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { @@ -6391,7 +6506,7 @@ type NotifyUtxosChangedResponseMessage struct { func (x *NotifyUtxosChangedResponseMessage) Reset() { *x = NotifyUtxosChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6404,7 +6519,7 @@ func (x *NotifyUtxosChangedResponseMessage) String() string { func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[95] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6417,7 +6532,7 @@ func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{93} + return file_messages_proto_rawDescGZIP(), []int{95} } func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { @@ -6439,7 +6554,7 @@ type UtxosChangedNotificationMessage struct { func (x *UtxosChangedNotificationMessage) Reset() { *x = UtxosChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6452,7 +6567,7 @@ func (x *UtxosChangedNotificationMessage) String() string { func (*UtxosChangedNotificationMessage) ProtoMessage() {} func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[96] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6465,7 +6580,7 @@ func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{94} + return file_messages_proto_rawDescGZIP(), []int{96} } func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { @@ -6495,7 +6610,7 @@ type UtxosByAddressesEntry struct { func (x *UtxosByAddressesEntry) Reset() { *x = UtxosByAddressesEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6508,7 +6623,7 @@ func (x *UtxosByAddressesEntry) String() string { func (*UtxosByAddressesEntry) ProtoMessage() {} func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[97] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6521,7 +6636,7 @@ func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{95} + return file_messages_proto_rawDescGZIP(), []int{97} } func (x *UtxosByAddressesEntry) GetAddress() string { @@ -6563,7 +6678,7 @@ type RpcTransaction struct { func (x *RpcTransaction) Reset() { *x = RpcTransaction{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6576,7 +6691,7 @@ func (x *RpcTransaction) String() string { func (*RpcTransaction) ProtoMessage() {} func (x *RpcTransaction) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[98] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6589,7 +6704,7 @@ func (x *RpcTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. func (*RpcTransaction) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{96} + return file_messages_proto_rawDescGZIP(), []int{98} } func (x *RpcTransaction) GetVersion() int32 { @@ -6661,7 +6776,7 @@ type RpcTransactionInput struct { func (x *RpcTransactionInput) Reset() { *x = RpcTransactionInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6674,7 +6789,7 @@ func (x *RpcTransactionInput) String() string { func (*RpcTransactionInput) ProtoMessage() {} func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[99] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6687,7 +6802,7 @@ func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. func (*RpcTransactionInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{97} + return file_messages_proto_rawDescGZIP(), []int{99} } func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { @@ -6723,7 +6838,7 @@ type RpcTransactionOutput struct { func (x *RpcTransactionOutput) Reset() { *x = RpcTransactionOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6736,7 +6851,7 @@ func (x *RpcTransactionOutput) String() string { func (*RpcTransactionOutput) ProtoMessage() {} func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[100] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6749,7 +6864,7 @@ func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{98} + return file_messages_proto_rawDescGZIP(), []int{100} } func (x *RpcTransactionOutput) GetAmount() uint64 { @@ -6778,7 +6893,7 @@ type RpcOutpoint struct { func (x *RpcOutpoint) Reset() { *x = RpcOutpoint{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6791,7 +6906,7 @@ func (x *RpcOutpoint) String() string { func (*RpcOutpoint) ProtoMessage() {} func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[101] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6804,7 +6919,7 @@ func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. func (*RpcOutpoint) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{99} + return file_messages_proto_rawDescGZIP(), []int{101} } func (x *RpcOutpoint) GetTransactionId() string { @@ -6835,7 +6950,7 @@ type RpcUtxoEntry struct { func (x *RpcUtxoEntry) Reset() { *x = RpcUtxoEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6848,7 +6963,7 @@ func (x *RpcUtxoEntry) String() string { func (*RpcUtxoEntry) ProtoMessage() {} func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[102] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6861,7 +6976,7 @@ func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{100} + return file_messages_proto_rawDescGZIP(), []int{102} } func (x *RpcUtxoEntry) GetAmount() uint64 { @@ -6903,7 +7018,7 @@ type GetUtxosByAddressesRequestMessage struct { func (x *GetUtxosByAddressesRequestMessage) Reset() { *x = GetUtxosByAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6916,7 +7031,7 @@ func (x *GetUtxosByAddressesRequestMessage) String() string { func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[103] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6929,7 +7044,7 @@ func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{101} + return file_messages_proto_rawDescGZIP(), []int{103} } func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { @@ -6951,7 +7066,7 @@ type GetUtxosByAddressesResponseMessage struct { func (x *GetUtxosByAddressesResponseMessage) Reset() { *x = GetUtxosByAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6964,7 +7079,7 @@ func (x *GetUtxosByAddressesResponseMessage) String() string { func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[104] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6977,7 +7092,7 @@ func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{102} + return file_messages_proto_rawDescGZIP(), []int{104} } func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { @@ -7003,7 +7118,7 @@ type GetVirtualSelectedParentBlueScoreRequestMessage struct { func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7016,7 +7131,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[105] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7029,7 +7144,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protore // Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{103} + return file_messages_proto_rawDescGZIP(), []int{105} } type GetVirtualSelectedParentBlueScoreResponseMessage struct { @@ -7044,7 +7159,7 @@ type GetVirtualSelectedParentBlueScoreResponseMessage struct { func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7057,7 +7172,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[106] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7070,7 +7185,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protor // Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{104} + return file_messages_proto_rawDescGZIP(), []int{106} } func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { @@ -7096,7 +7211,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7109,7 +7224,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() str func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[107] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7122,7 +7237,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{105} + return file_messages_proto_rawDescGZIP(), []int{107} } type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { @@ -7136,7 +7251,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7149,7 +7264,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() st func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[108] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7162,7 +7277,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflec // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{106} + return file_messages_proto_rawDescGZIP(), []int{108} } func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { @@ -7183,7 +7298,7 @@ type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7196,7 +7311,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() stri func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[109] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7209,7 +7324,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect( // Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{107} + return file_messages_proto_rawDescGZIP(), []int{109} } func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { @@ -7223,7 +7338,7 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xf9, 0x42, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0x86, 0x44, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -7339,1203 +7454,1217 @@ var file_messages_proto_rawDesc = []byte{ 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, - 0x64, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, - 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x64, 0x12, 0x4f, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, + 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x12, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x3a, 0x0a, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x48, + 0x00, 0x52, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x69, + 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, - 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, - 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, - 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, - 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, - 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, - 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 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, 0x48, - 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, - 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, - 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, - 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, - 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, - 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, - 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, - 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, - 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, - 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, - 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, - 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, - 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, - 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, - 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, - 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, - 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, - 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, - 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, - 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, - 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, - 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, - 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, - 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, - 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, - 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, - 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, - 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, - 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, - 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, - 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, - 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, - 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, - 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, - 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, - 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, - 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, - 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, - 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, + 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 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, 0x4a, - 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, - 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, + 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, + 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, + 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, + 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, - 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 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, 0x39, - 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, - 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, - 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 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, 0x24, - 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, - 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, - 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, - 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, - 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, - 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, - 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, - 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, + 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, + 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, + 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, + 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, - 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 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, - 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 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, 0xb3, - 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 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, 0x54, 0x0a, - 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x2a, 0x0a, 0x05, 0x65, 0x72, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x14, 0x67, + 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x15, + 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 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, 0x48, + 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, + 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, + 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, + 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, + 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, + 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, + 0x1e, 0x6e, 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, 0x12, + 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, + 0x6e, 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, 0x12, + 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, + 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, + 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, + 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, + 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, + 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, + 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, + 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, + 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, + 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, + 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, + 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, + 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, + 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, + 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, + 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, + 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, + 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, + 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, + 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, + 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, + 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, + 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, + 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, + 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, + 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, + 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x22, 0x32, 0x0a, 0x0b, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, + 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, + 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 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, 0x40, 0x0a, 0x1e, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, + 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 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, 0x4e, 0x0a, 0x1d, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, + 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, + 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, + 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 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, + 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, + 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, + 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, + 0x72, 0x79, 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, 0x21, + 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, + 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, 0xb5, 0x02, + 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, + 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, + 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, + 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, + 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 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, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, + 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, + 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, + 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, 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, 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, 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, 0x22, 0x40, - 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, - 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, - 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, - 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, - 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, - 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, - 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, - 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, - 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, - 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, - 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 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, 0x31, - 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, + 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, - 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, + 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, + 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, + 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, + 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, + 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, + 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, + 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, + 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, + 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, + 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, + 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, + 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 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, 0x82, 0x01, + 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 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, 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 ( @@ -8550,7 +8679,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 108) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 110) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage @@ -8584,82 +8713,84 @@ var file_messages_proto_goTypes = []interface{}{ (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage - (*RPCError)(nil), // 32: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 33: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 34: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 35: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 36: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 37: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 38: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 39: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 40: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 41: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 42: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 43: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 44: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 45: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 46: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 47: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 48: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 49: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 50: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 51: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 52: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 53: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 54: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 55: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 56: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 57: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 58: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 59: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 60: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 61: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*ChainBlock)(nil), // 62: protowire.ChainBlock - (*AcceptedBlock)(nil), // 63: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 64: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 65: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 66: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 67: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 68: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 69: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 70: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 71: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 72: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 73: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 74: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 75: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 76: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 77: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 78: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 79: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 80: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 81: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 82: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 83: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 84: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 85: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 86: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 87: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 88: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 89: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 90: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 91: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 92: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 93: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 94: protowire.UtxosChangedNotificationMessage - (*UtxosByAddressesEntry)(nil), // 95: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 96: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 97: protowire.RpcTransactionInput - (*RpcTransactionOutput)(nil), // 98: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 99: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 100: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 101: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 102: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 103: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 104: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 105: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 106: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 107: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*RequestIBDRootHash)(nil), // 32: protowire.RequestIBDRootHash + (*IBDRootHash)(nil), // 33: protowire.IBDRootHash + (*RPCError)(nil), // 34: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 35: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 36: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 37: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 38: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 39: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 40: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 41: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 42: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 43: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 44: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 45: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 46: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 47: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 48: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 49: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 50: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 51: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 52: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 53: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 54: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 55: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 56: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 57: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 58: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 59: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 60: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 61: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 62: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 63: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*ChainBlock)(nil), // 64: protowire.ChainBlock + (*AcceptedBlock)(nil), // 65: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 66: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 67: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 68: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 69: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 70: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 71: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 72: protowire.TransactionVerboseOutput + (*ScriptPubKeyResult)(nil), // 73: protowire.ScriptPubKeyResult + (*GetSubnetworkRequestMessage)(nil), // 74: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 75: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 76: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 77: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 78: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 79: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 80: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 81: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 82: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 83: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 84: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 85: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 86: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 87: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 88: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 89: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 90: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 91: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 92: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 93: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 94: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 95: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 96: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 97: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 98: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 99: protowire.RpcTransactionInput + (*RpcTransactionOutput)(nil), // 100: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 101: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 102: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 103: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 104: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 105: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 106: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 107: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 108: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 109: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -8687,156 +8818,159 @@ var file_messages_proto_depIdxs = []int32{ 29, // 22: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage 30, // 23: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage 31, // 24: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 33, // 25: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 34, // 26: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 35, // 27: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 36, // 28: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 37, // 29: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 38, // 30: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 39, // 31: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 40, // 32: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 41, // 33: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 42, // 34: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 43, // 35: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 45, // 36: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 46, // 37: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 48, // 38: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 49, // 39: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 52, // 40: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 53, // 41: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 55, // 42: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 56, // 43: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 57, // 44: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 58, // 45: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 59, // 46: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 60, // 47: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 61, // 48: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 64, // 49: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 65, // 50: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 72, // 51: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 73, // 52: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 74, // 53: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 75, // 54: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 76, // 55: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 77, // 56: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 78, // 57: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 79, // 58: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 80, // 59: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 81, // 60: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 82, // 61: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 83, // 62: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 84, // 63: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 85, // 64: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 86, // 65: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 87, // 66: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 50, // 67: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 51, // 68: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 88, // 69: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 89, // 70: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 90, // 71: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 91, // 72: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 92, // 73: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 93, // 74: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 94, // 75: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 101, // 76: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 102, // 77: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 103, // 78: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 104, // 79: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 105, // 80: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 106, // 81: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 107, // 82: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 4, // 83: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId - 3, // 84: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 6, // 85: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 86: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 4, // 87: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 88: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 89: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint - 8, // 90: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId - 11, // 91: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 92: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 93: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 12, // 94: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 95: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash - 12, // 96: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 12, // 97: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 98: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 99: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 100: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 12, // 101: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 12, // 102: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 103: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId - 8, // 104: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId - 12, // 105: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 106: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId - 3, // 107: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 4, // 108: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 109: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 110: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 111: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 32, // 112: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 113: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 32, // 114: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 115: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 32, // 116: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 32, // 117: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 118: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 44, // 119: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 44, // 120: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 32, // 121: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 32, // 122: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 67, // 123: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 47, // 124: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 32, // 125: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 47, // 126: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 32, // 127: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 54, // 128: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 32, // 129: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 32, // 130: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 96, // 131: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 32, // 132: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 32, // 133: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 62, // 134: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 63, // 135: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 66, // 136: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 137: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 67, // 138: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 68, // 139: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 70, // 140: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 69, // 141: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 71, // 142: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 32, // 143: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 62, // 144: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 32, // 145: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 66, // 146: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 32, // 147: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 32, // 148: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 32, // 149: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 32, // 150: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 32, // 151: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 32, // 152: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 32, // 153: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 32, // 154: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 95, // 155: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 95, // 156: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 99, // 157: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 100, // 158: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 97, // 159: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 98, // 160: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 99, // 161: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 95, // 162: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 32, // 163: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 32, // 164: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 32, // 165: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 0, // 166: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 167: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 168: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 169: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 168, // [168:170] is the sub-list for method output_type - 166, // [166:168] is the sub-list for method input_type - 166, // [166:166] is the sub-list for extension type_name - 166, // [166:166] is the sub-list for extension extendee - 0, // [0:166] is the sub-list for field type_name + 32, // 25: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHash + 33, // 26: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHash + 35, // 27: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 36, // 28: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 37, // 29: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 38, // 30: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 39, // 31: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 40, // 32: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 41, // 33: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 42, // 34: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 43, // 35: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 44, // 36: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 45, // 37: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 47, // 38: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 48, // 39: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 50, // 40: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 51, // 41: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 54, // 42: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 55, // 43: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 57, // 44: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 58, // 45: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 59, // 46: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 60, // 47: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 61, // 48: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 62, // 49: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 63, // 50: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 66, // 51: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 67, // 52: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 74, // 53: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 75, // 54: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 76, // 55: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 77, // 56: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 78, // 57: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 79, // 58: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 80, // 59: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 81, // 60: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 82, // 61: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 83, // 62: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 84, // 63: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 85, // 64: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 86, // 65: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 87, // 66: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 88, // 67: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 89, // 68: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 52, // 69: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 53, // 70: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 90, // 71: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 91, // 72: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 92, // 73: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 93, // 74: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 94, // 75: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 95, // 76: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 96, // 77: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 103, // 78: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 104, // 79: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 105, // 80: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 106, // 81: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 107, // 82: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 108, // 83: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 109, // 84: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 4, // 85: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId + 3, // 86: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 6, // 87: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 88: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 4, // 89: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 90: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 7, // 91: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint + 8, // 92: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId + 11, // 93: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 94: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 95: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 96: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 97: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash + 12, // 98: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 99: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 100: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 101: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 102: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 103: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 104: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 105: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 8, // 106: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId + 12, // 107: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 108: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId + 3, // 109: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 4, // 110: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 111: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 112: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 113: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 12, // 114: protowire.IBDRootHash.hash:type_name -> protowire.Hash + 34, // 115: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 116: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 34, // 117: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 118: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 34, // 119: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 34, // 120: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 121: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 46, // 122: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 46, // 123: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 34, // 124: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 34, // 125: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 69, // 126: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 49, // 127: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 34, // 128: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 49, // 129: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 34, // 130: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 56, // 131: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 34, // 132: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 133: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 98, // 134: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 34, // 135: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 34, // 136: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 64, // 137: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 65, // 138: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 68, // 139: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 140: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 69, // 141: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 70, // 142: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 72, // 143: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 71, // 144: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 73, // 145: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 34, // 146: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 64, // 147: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 34, // 148: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 68, // 149: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 34, // 150: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 34, // 151: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 34, // 152: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 34, // 153: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 34, // 154: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 34, // 155: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 34, // 156: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 34, // 157: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 97, // 158: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 97, // 159: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 101, // 160: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 102, // 161: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 99, // 162: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 100, // 163: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 101, // 164: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 97, // 165: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 34, // 166: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 34, // 167: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 34, // 168: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 0, // 169: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 170: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 171: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 172: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 171, // [171:173] is the sub-list for method output_type + 169, // [169:171] is the sub-list for method input_type + 169, // [169:169] is the sub-list for extension type_name + 169, // [169:169] is the sub-list for extension extendee + 0, // [0:169] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -9230,7 +9364,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCError); i { + switch v := v.(*RequestIBDRootHash); i { case 0: return &v.state case 1: @@ -9242,7 +9376,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkRequestMessage); i { + switch v := v.(*IBDRootHash); i { case 0: return &v.state case 1: @@ -9254,7 +9388,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkResponseMessage); i { + switch v := v.(*RPCError); i { case 0: return &v.state case 1: @@ -9266,7 +9400,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockRequestMessage); i { + switch v := v.(*GetCurrentNetworkRequestMessage); i { case 0: return &v.state case 1: @@ -9278,7 +9412,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockResponseMessage); i { + switch v := v.(*GetCurrentNetworkResponseMessage); i { case 0: return &v.state case 1: @@ -9290,7 +9424,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateRequestMessage); i { + switch v := v.(*SubmitBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9302,7 +9436,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateResponseMessage); i { + switch v := v.(*SubmitBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9314,7 +9448,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedRequestMessage); i { + switch v := v.(*GetBlockTemplateRequestMessage); i { case 0: return &v.state case 1: @@ -9326,7 +9460,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedResponseMessage); i { + switch v := v.(*GetBlockTemplateResponseMessage); i { case 0: return &v.state case 1: @@ -9338,7 +9472,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockAddedNotificationMessage); i { + switch v := v.(*NotifyBlockAddedRequestMessage); i { case 0: return &v.state case 1: @@ -9350,7 +9484,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesRequestMessage); i { + switch v := v.(*NotifyBlockAddedResponseMessage); i { case 0: return &v.state case 1: @@ -9362,7 +9496,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesResponseMessage); i { + switch v := v.(*BlockAddedNotificationMessage); i { case 0: return &v.state case 1: @@ -9374,7 +9508,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesKnownAddressMessage); i { + switch v := v.(*GetPeerAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -9386,7 +9520,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashRequestMessage); i { + switch v := v.(*GetPeerAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -9398,7 +9532,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashResponseMessage); i { + switch v := v.(*GetPeerAddressesKnownAddressMessage); i { case 0: return &v.state case 1: @@ -9410,7 +9544,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MempoolEntry); i { + switch v := v.(*GetSelectedTipHashRequestMessage); i { case 0: return &v.state case 1: @@ -9422,7 +9556,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryRequestMessage); i { + switch v := v.(*GetSelectedTipHashResponseMessage); i { case 0: return &v.state case 1: @@ -9434,7 +9568,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryResponseMessage); i { + switch v := v.(*MempoolEntry); i { case 0: return &v.state case 1: @@ -9446,7 +9580,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesRequestMessage); i { + switch v := v.(*GetMempoolEntryRequestMessage); i { case 0: return &v.state case 1: @@ -9458,7 +9592,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesResponseMessage); i { + switch v := v.(*GetMempoolEntryResponseMessage); i { case 0: return &v.state case 1: @@ -9470,7 +9604,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoRequestMessage); i { + switch v := v.(*GetMempoolEntriesRequestMessage); i { case 0: return &v.state case 1: @@ -9482,7 +9616,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoResponseMessage); i { + switch v := v.(*GetMempoolEntriesResponseMessage); i { case 0: return &v.state case 1: @@ -9494,7 +9628,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoMessage); i { + switch v := v.(*GetConnectedPeerInfoRequestMessage); i { case 0: return &v.state case 1: @@ -9506,7 +9640,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerRequestMessage); i { + switch v := v.(*GetConnectedPeerInfoResponseMessage); i { case 0: return &v.state case 1: @@ -9518,7 +9652,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerResponseMessage); i { + switch v := v.(*GetConnectedPeerInfoMessage); i { case 0: return &v.state case 1: @@ -9530,7 +9664,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionRequestMessage); i { + switch v := v.(*AddPeerRequestMessage); i { case 0: return &v.state case 1: @@ -9542,7 +9676,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionResponseMessage); i { + switch v := v.(*AddPeerResponseMessage); i { case 0: return &v.state case 1: @@ -9554,7 +9688,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { + switch v := v.(*SubmitTransactionRequestMessage); i { case 0: return &v.state case 1: @@ -9566,7 +9700,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { + switch v := v.(*SubmitTransactionResponseMessage); i { case 0: return &v.state case 1: @@ -9578,7 +9712,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { case 0: return &v.state case 1: @@ -9590,7 +9724,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainBlock); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { case 0: return &v.state case 1: @@ -9602,7 +9736,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptedBlock); i { + switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -9614,7 +9748,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockRequestMessage); i { + switch v := v.(*ChainBlock); i { case 0: return &v.state case 1: @@ -9626,7 +9760,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockResponseMessage); i { + switch v := v.(*AcceptedBlock); i { case 0: return &v.state case 1: @@ -9638,7 +9772,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockVerboseData); i { + switch v := v.(*GetBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9650,7 +9784,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseData); i { + switch v := v.(*GetBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9662,7 +9796,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseInput); i { + switch v := v.(*BlockVerboseData); i { case 0: return &v.state case 1: @@ -9674,7 +9808,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptSig); i { + switch v := v.(*TransactionVerboseData); i { case 0: return &v.state case 1: @@ -9686,7 +9820,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseOutput); i { + switch v := v.(*TransactionVerboseInput); i { case 0: return &v.state case 1: @@ -9698,7 +9832,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPubKeyResult); i { + switch v := v.(*ScriptSig); i { case 0: return &v.state case 1: @@ -9710,7 +9844,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkRequestMessage); i { + switch v := v.(*TransactionVerboseOutput); i { case 0: return &v.state case 1: @@ -9722,7 +9856,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkResponseMessage); i { + switch v := v.(*ScriptPubKeyResult); i { case 0: return &v.state case 1: @@ -9734,7 +9868,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { + switch v := v.(*GetSubnetworkRequestMessage); i { case 0: return &v.state case 1: @@ -9746,7 +9880,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { + switch v := v.(*GetSubnetworkResponseMessage); i { case 0: return &v.state case 1: @@ -9758,7 +9892,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9770,7 +9904,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9782,7 +9916,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountRequestMessage); i { + switch v := v.(*GetBlocksRequestMessage); i { case 0: return &v.state case 1: @@ -9794,7 +9928,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountResponseMessage); i { + switch v := v.(*GetBlocksResponseMessage); i { case 0: return &v.state case 1: @@ -9806,7 +9940,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoRequestMessage); i { + switch v := v.(*GetBlockCountRequestMessage); i { case 0: return &v.state case 1: @@ -9818,7 +9952,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoResponseMessage); i { + switch v := v.(*GetBlockCountResponseMessage); i { case 0: return &v.state case 1: @@ -9830,7 +9964,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictRequestMessage); i { + switch v := v.(*GetBlockDagInfoRequestMessage); i { case 0: return &v.state case 1: @@ -9842,7 +9976,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictResponseMessage); i { + switch v := v.(*GetBlockDagInfoResponseMessage); i { case 0: return &v.state case 1: @@ -9854,7 +9988,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsRequestMessage); i { + switch v := v.(*ResolveFinalityConflictRequestMessage); i { case 0: return &v.state case 1: @@ -9866,7 +10000,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsResponseMessage); i { + switch v := v.(*ResolveFinalityConflictResponseMessage); i { case 0: return &v.state case 1: @@ -9878,7 +10012,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictNotificationMessage); i { + switch v := v.(*NotifyFinalityConflictsRequestMessage); i { case 0: return &v.state case 1: @@ -9890,7 +10024,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + switch v := v.(*NotifyFinalityConflictsResponseMessage); i { case 0: return &v.state case 1: @@ -9902,7 +10036,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownRequestMessage); i { + switch v := v.(*FinalityConflictNotificationMessage); i { case 0: return &v.state case 1: @@ -9914,7 +10048,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownResponseMessage); i { + switch v := v.(*FinalityConflictResolvedNotificationMessage); i { case 0: return &v.state case 1: @@ -9926,7 +10060,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersRequestMessage); i { + switch v := v.(*ShutDownRequestMessage); i { case 0: return &v.state case 1: @@ -9938,7 +10072,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersResponseMessage); i { + switch v := v.(*ShutDownResponseMessage); i { case 0: return &v.state case 1: @@ -9950,7 +10084,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedRequestMessage); i { + switch v := v.(*GetHeadersRequestMessage); i { case 0: return &v.state case 1: @@ -9962,7 +10096,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedResponseMessage); i { + switch v := v.(*GetHeadersResponseMessage); i { case 0: return &v.state case 1: @@ -9974,7 +10108,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosChangedNotificationMessage); i { + switch v := v.(*NotifyUtxosChangedRequestMessage); i { case 0: return &v.state case 1: @@ -9986,7 +10120,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosByAddressesEntry); i { + switch v := v.(*NotifyUtxosChangedResponseMessage); i { case 0: return &v.state case 1: @@ -9998,7 +10132,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransaction); i { + switch v := v.(*UtxosChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -10010,7 +10144,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionInput); i { + switch v := v.(*UtxosByAddressesEntry); i { case 0: return &v.state case 1: @@ -10022,7 +10156,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionOutput); i { + switch v := v.(*RpcTransaction); i { case 0: return &v.state case 1: @@ -10034,7 +10168,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcOutpoint); i { + switch v := v.(*RpcTransactionInput); i { case 0: return &v.state case 1: @@ -10046,7 +10180,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcUtxoEntry); i { + switch v := v.(*RpcTransactionOutput); i { case 0: return &v.state case 1: @@ -10058,7 +10192,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesRequestMessage); i { + switch v := v.(*RpcOutpoint); i { case 0: return &v.state case 1: @@ -10070,7 +10204,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesResponseMessage); i { + switch v := v.(*RpcUtxoEntry); i { case 0: return &v.state case 1: @@ -10082,7 +10216,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -10094,7 +10228,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -10106,7 +10240,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { case 0: return &v.state case 1: @@ -10118,7 +10252,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { case 0: return &v.state case 1: @@ -10130,6 +10264,30 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { case 0: return &v.state @@ -10168,6 +10326,8 @@ func file_messages_proto_init() { (*KaspadMessage_IbdRootUTXOSetAndBlock)(nil), (*KaspadMessage_RequestIBDBlocks)(nil), (*KaspadMessage_IbdRootNotFound)(nil), + (*KaspadMessage_RequestIBDRootHash)(nil), + (*KaspadMessage_IbdRootHash)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), @@ -10233,7 +10393,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 108, + NumMessages: 110, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 63aa88c13..7158fcd02 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -30,6 +30,8 @@ message KaspadMessage { IBDRootUTXOSetAndBlockMessage ibdRootUTXOSetAndBlock = 25; RequestIBDBlocksMessage requestIBDBlocks = 26; IBDRootNotFoundMessage ibdRootNotFound = 27; + RequestIBDRootHash requestIBDRootHash = 28; + IBDRootHash ibdRootHash = 29; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; @@ -297,6 +299,17 @@ message IBDRootNotFoundMessage{ } // IBDRootNotFoundMessage end +// RequestIBDRootHash start +message RequestIBDRootHash{ +} +// RequestIBDRootHash end + +// IBDRootHash start +message IBDRootHash{ + Hash hash = 1; +} +// IBDRootHash end + service P2P { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go new file mode 100644 index 000000000..2c48f2836 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go @@ -0,0 +1,19 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_IbdRootHash) toAppMessage() (appmessage.Message, error) { + hash, err := x.IbdRootHash.Hash.toDomain() + if err != nil { + return nil, err + } + + return &appmessage.MsgIBDRootHash{Hash: hash}, nil +} + +func (x *KaspadMessage_IbdRootHash) fromAppMessage(msgIBDRootHash *appmessage.MsgIBDRootHash) error { + x.IbdRootHash = &IBDRootHash{ + Hash: domainHashToProto(msgIBDRootHash.Hash), + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go new file mode 100644 index 000000000..da9c3e38e --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go @@ -0,0 +1,11 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestIBDRootHash) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgRequestIBDRootHash{}, nil +} + +func (x *KaspadMessage_RequestIBDRootHash) fromAppMessage(_ *appmessage.MsgRequestIBDRootHash) error { + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index e50fd9c69..a68f1017e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -232,6 +232,22 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { } return payload, nil + case *appmessage.MsgRequestIBDRootHash: + payload := new(KaspadMessage_RequestIBDRootHash) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + + case *appmessage.MsgIBDRootHash: + payload := new(KaspadMessage_IbdRootHash) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + default: return nil, nil } From 273c271771061a9bb14a0ee5798b0c39f473a295 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 23 Dec 2020 12:42:37 +0200 Subject: [PATCH 152/351] Remove hash reversal (#1270) * Remove hash reversing * Move toBig to pow.go * Update some tests --- app/appmessage/p2p_msgtx_test.go | 10 +++++----- domain/consensus/model/externalapi/hash.go | 6 +----- domain/consensus/model/pow/pow.go | 17 +++++++++++++++-- domain/consensus/ruleerrors/rule_error_test.go | 4 ++-- domain/consensus/utils/hashes/strings.go | 17 ++++------------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index c1dba1885..dd124e653 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -132,8 +132,8 @@ func TestTx(t *testing.T) { // TestTxHash tests the ability to generate the hash of a transaction accurately. func TestTxHashAndID(t *testing.T) { - txHash1Str := "c2ac1e792c5c49260103ad9f86caf749d431958b7c7e5e5129346ceab8b709cf" - txID1Str := "47ce12a5ee5727cf97c0481eebedad0d80646b743305b0921a2403f1836f8b37" + txHash1Str := "cf09b7b8ea6c3429515e7e7c8b9531d449f7ca869fad030126495c2c791eacc2" + txID1Str := "378b6f83f103241a92b00533746b64800dadedeb1e48c097cf2757eea512ce47" wantTxID1, err := transactionid.FromString(txID1Str) if err != nil { t.Fatalf("NewTxIDFromStr: %v", err) @@ -174,7 +174,7 @@ func TestTxHashAndID(t *testing.T) { tx1Hash := tx1.TxHash() if *tx1Hash != (externalapi.DomainHash)(*wantTxHash1) { t.Errorf("TxHash: wrong hash - got %v, want %v", - spew.Sprint(tx1Hash), spew.Sprint(wantTxID1)) + spew.Sprint(tx1Hash), spew.Sprint(wantTxHash1)) } // Ensure the TxID for coinbase transaction is the same as TxHash. @@ -184,14 +184,14 @@ func TestTxHashAndID(t *testing.T) { spew.Sprint(tx1ID), spew.Sprint(wantTxID1)) } - hash2Str := "6b769655a1420022e4690a4f7bb9b1c381185ebbefe3070351f06fb573a0600c" + hash2Str := "0c60a073b56ff0510307e3efbb5e1881c3b1b97b4f0a69e4220042a15596766b" wantHash2, err := hashes.FromString(hash2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) return } - id2Str := "af916032e271adaaa21f02bee4b44db2cca4dad9149dcaebc188009c7313ec68" + id2Str := "68ec13739c0088c1ebca9d14d9daa4ccb24db4e4be021fa2aaad71e2326091af" wantID2, err := transactionid.FromString(id2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index e7080e1bc..d52feac3c 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -8,12 +8,8 @@ const DomainHashSize = 32 // DomainHash is the domain representation of a Hash type DomainHash [DomainHashSize]byte -// String returns the Hash as the hexadecimal string of the byte-reversed -// hash. +// String returns the Hash as the hexadecimal string of the hash. func (hash DomainHash) String() string { - for i := 0; i < DomainHashSize/2; i++ { - hash[i], hash[DomainHashSize-1-i] = hash[DomainHashSize-1-i], hash[i] - } return hex.EncodeToString(hash[:]) } diff --git a/domain/consensus/model/pow/pow.go b/domain/consensus/model/pow/pow.go index 17edd68dc..c3fe5a717 100644 --- a/domain/consensus/model/pow/pow.go +++ b/domain/consensus/model/pow/pow.go @@ -1,13 +1,14 @@ package pow import ( + "math/big" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" "github.com/kaspanet/kaspad/util" "github.com/pkg/errors" - "math/big" ) // CheckProofOfWorkWithTarget check's if the block has a valid PoW according to the provided target @@ -47,5 +48,17 @@ func calcPowValue(header *externalapi.DomainBlockHeader) *big.Int { if err != nil { panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error")) } - return hashes.ToBig(writer.Finalize()) + return toBig(writer.Finalize()) +} + +// ToBig converts a externalapi.DomainHash into a big.Int treated as a little endian string. +func toBig(hash *externalapi.DomainHash) *big.Int { + // We treat the Hash as little-endian for PoW purposes, but the big package wants the bytes in big-endian, so reverse them. + buf := hash.Clone() + blen := len(buf) + for i := 0; i < blen/2; i++ { + buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] + } + + return new(big.Int).SetBytes(buf[:]) } diff --git a/domain/consensus/ruleerrors/rule_error_test.go b/domain/consensus/ruleerrors/rule_error_test.go index 5c95aafff..025f83ff9 100644 --- a/domain/consensus/ruleerrors/rule_error_test.go +++ b/domain/consensus/ruleerrors/rule_error_test.go @@ -9,7 +9,7 @@ import ( func TestNewErrMissingTxOut(t *testing.T) { outer := NewErrMissingTxOut([]*externalapi.DomainOutpoint{{TransactionID: externalapi.DomainTransactionID{255, 255, 255}, Index: 5}}) - expectedOuterErr := "ErrMissingTxOut: missing the following outpoint: [(0000000000000000000000000000000000000000000000000000000000ffffff: 5)]" + expectedOuterErr := "ErrMissingTxOut: missing the following outpoint: [(ffffff0000000000000000000000000000000000000000000000000000000000: 5)]" inner := &ErrMissingTxOut{} if !errors.As(outer, inner) { t.Fatal("TestWrapInRuleError: Outer should contain ErrMissingTxOut in it") @@ -41,7 +41,7 @@ func TestNewErrMissingTxOut(t *testing.T) { func TestNewErrInvalidTransactionsInNewBlock(t *testing.T) { outer := NewErrInvalidTransactionsInNewBlock([]InvalidTransaction{{&externalapi.DomainTransaction{Fee: 1337}, ErrNoTxInputs}}) //TODO: Implement Stringer for `DomainTransaction` - expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(4ea5363088df94b7b52afa9df9db7b44561e0a2219f2bf85b2f1d699cade933e: ErrNoTxInputs)]" + expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(3e93deca99d6f1b285bff219220a1e56447bdbf99dfa2ab5b794df883036a54e: ErrNoTxInputs)]" inner := &ErrInvalidTransactionsInNewBlock{} if !errors.As(outer, inner) { t.Fatal("TestNewErrInvalidTransactionsInNewBlock: Outer should contain ErrInvalidTransactionsInNewBlock in it") diff --git a/domain/consensus/utils/hashes/strings.go b/domain/consensus/utils/hashes/strings.go index 3c4b9625e..022dd94bf 100644 --- a/domain/consensus/utils/hashes/strings.go +++ b/domain/consensus/utils/hashes/strings.go @@ -8,7 +8,7 @@ import ( ) // FromString creates a DomainHash from a hash string. The string should be -// the hexadecimal string of a byte-reversed hash, but any missing characters +// the hexadecimal string of a hash, but any missing characters // result in zero padding at the end of the Hash. func FromString(hash string) (*externalapi.DomainHash, error) { ret := new(externalapi.DomainHash) @@ -19,8 +19,7 @@ func FromString(hash string) (*externalapi.DomainHash, error) { return ret, nil } -// decode decodes the byte-reversed hexadecimal string encoding of a Hash to a -// destination. +// decode decodes the hexadecimal string encoding of a Hash to a destination. func decode(dst *externalapi.DomainHash, src string) error { expectedSrcLength := externalapi.DomainHashSize * 2 // Return error if hash string is too long. @@ -40,19 +39,11 @@ func decode(dst *externalapi.DomainHash, src string) error { copy(srcBytes[1:], src) } - // Hex decode the source bytes to a temporary destination. - var reversedHash externalapi.DomainHash - _, err := hex.Decode(reversedHash[externalapi.DomainHashSize-hex.DecodedLen(len(srcBytes)):], srcBytes) + // Hex decode the source bytes + _, err := hex.Decode(dst[externalapi.DomainHashSize-hex.DecodedLen(len(srcBytes)):], srcBytes) if err != nil { return errors.Wrap(err, "couldn't decode hash hex") } - - // Reverse copy from the temporary hash to destination. Because the - // temporary was zeroed, the written result will be correctly padded. - for i, b := range reversedHash[:externalapi.DomainHashSize/2] { - dst[i], dst[externalapi.DomainHashSize-1-i] = reversedHash[externalapi.DomainHashSize-1-i], b - } - return nil } From 6ef8eaf133ffb70b4e306108df2b0199360cd485 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 23 Dec 2020 15:08:02 +0200 Subject: [PATCH 153/351] Fix AddBlock not returning validation failure errors (#1268) * Fix AddBlock not returning validation failure errors. * Elevate a log from Info to Warning. * Elevate a log from Info to Warning. --- app/protocol/flowcontext/blocks.go | 3 +-- app/protocol/flowcontext/orphans.go | 2 +- app/rpc/rpchandlers/submit_block.go | 5 +++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index d6393ccf9..4458b1a9d 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -101,8 +101,7 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { blockInsertionResult, 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) - return nil + log.Warnf("Validation failed for block %s: %s", consensushashing.BlockHash(block), err) } return err } diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 853462255..773e9064a 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -149,7 +149,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa blockInsertionResult, 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) + log.Warnf("Validation failed for orphan block %s: %s", orphanHash, err) return nil, nil } return nil, err diff --git a/app/rpc/rpchandlers/submit_block.go b/app/rpc/rpchandlers/submit_block.go index e5fb5f799..45aca8806 100644 --- a/app/rpc/rpchandlers/submit_block.go +++ b/app/rpc/rpchandlers/submit_block.go @@ -3,8 +3,10 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/pkg/errors" ) // HandleSubmitBlock handles the respectively named RPC command @@ -16,6 +18,9 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap err := context.ProtocolManager.AddBlock(domainBlock) if err != nil { + if !errors.As(err, &ruleerrors.RuleError{}) { + return nil, err + } errorMessage := &appmessage.SubmitBlockResponseMessage{} errorMessage.Error = appmessage.RPCErrorf("Block rejected. Reason: %s", err) return errorMessage, nil From 717914319ad5ecede8cbae74d77f6115a15f6553 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 24 Dec 2020 10:27:05 +0200 Subject: [PATCH 154/351] Increase size of reachability and block-relations cache (#1272) * Increase size of reachability cache * Increase cache size for BlockRelationStore --- domain/consensus/factory.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 934a060e2..72b0bdbee 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -74,11 +74,11 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat if err != nil { return nil, err } - blockRelationStore := blockrelationstore.New(200) + blockRelationStore := blockrelationstore.New(10_000) blockStatusStore := blockstatusstore.New(200) multisetStore := multisetstore.New(200) pruningStore := pruningstore.New() - reachabilityDataStore := reachabilitydatastore.New(200) + reachabilityDataStore := reachabilitydatastore.New(10_000) utxoDiffStore := utxodiffstore.New(200) consensusStateStore := consensusstatestore.New() ghostdagDataStore := ghostdagdatastore.New(10_000) From b749b2db0b089ba1665b72d4aa1fc4446126c2b1 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 24 Dec 2020 10:40:56 +0200 Subject: [PATCH 155/351] Fix transaction relay not working (#1279) * Implement HandleGetMempoolEntry. * Fix equality bug in handleRelayedTransactionsFlow. --- .../handle_relayed_transactions.go | 2 +- app/rpc/rpchandlers/get_mempool_entry.go | 25 ++++++++++++++++++- testing/integration/tx_relay_test.go | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/protocol/flows/transactionrelay/handle_relayed_transactions.go b/app/protocol/flows/transactionrelay/handle_relayed_transactions.go index 26f9d6d2c..2bcd8afc9 100644 --- a/app/protocol/flows/transactionrelay/handle_relayed_transactions.go +++ b/app/protocol/flows/transactionrelay/handle_relayed_transactions.go @@ -168,7 +168,7 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact } tx := appmessage.MsgTxToDomainTransaction(msgTx) txID := consensushashing.TransactionID(tx) - if txID != expectedID { + if !txID.Equal(expectedID) { return protocolerrors.Errorf(true, "expected transaction %s, but got %s", expectedID, txID) } diff --git a/app/rpc/rpchandlers/get_mempool_entry.go b/app/rpc/rpchandlers/get_mempool_entry.go index 104441a37..3a3bc5db3 100644 --- a/app/rpc/rpchandlers/get_mempool_entry.go +++ b/app/rpc/rpchandlers/get_mempool_entry.go @@ -3,10 +3,33 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) // HandleGetMempoolEntry handles the respectively named RPC command func HandleGetMempoolEntry(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - return &appmessage.GetMempoolEntryResponseMessage{}, nil + getMempoolEntryRequest := request.(*appmessage.GetMempoolEntryRequestMessage) + + transactionID, err := transactionid.FromString(getMempoolEntryRequest.TxID) + if err != nil { + errorMessage := &appmessage.GetMempoolEntryResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Transaction ID could not be parsed: %s", err) + return errorMessage, nil + } + + transaction, ok := context.Domain.MiningManager().GetTransaction(transactionID) + if !ok { + errorMessage := &appmessage.GetMempoolEntryResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Transaction %s was not found", transactionID) + return errorMessage, nil + } + + transactionVerboseData, err := context.BuildTransactionVerboseData( + transaction, getMempoolEntryRequest.TxID, nil, "") + if err != nil { + return nil, err + } + + return appmessage.NewGetMempoolEntryResponseMessage(transaction.Fee, transactionVerboseData), nil } diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 3c23e0a73..3e6b85fe3 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -60,7 +60,7 @@ func TestTxRelay(t *testing.T) { for range ticker.C { _, err := payee.rpcClient.GetMempoolEntry(txID) if err != nil { - if strings.Contains(err.Error(), "transaction is not in the pool") { + if strings.Contains(err.Error(), "not found") { continue } From a0b93e1230194d1104f96b9100b06652665c8722 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 24 Dec 2020 13:53:16 +0200 Subject: [PATCH 156/351] Fix deletePastBlocks (#1280) --- .../consensus/processes/pruningmanager/pruningmanager.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 305255ceb..7cf73adda 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -198,7 +198,14 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) return err } if !hasPruningPointInPast { - isInVirtualPast, err := pm.dagTopologyManager.IsAncestorOf(model.VirtualBlockHash, tip) + virtualParents, err := pm.dagTopologyManager.Parents(model.VirtualBlockHash) + if err != nil { + return err + } + + // Because virtual doesn't have reachability data, we need to check reachability + // using it parents. + isInVirtualPast, err := pm.dagTopologyManager.IsAncestorOfAny(tip, virtualParents) if err != nil { return err } From 7cbda3b0182d9812202f9e900bcca64722a1b75d Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 24 Dec 2020 15:17:34 +0200 Subject: [PATCH 157/351] Fix RPC requests with unknown payloads crashing kaspad (#1203) * [NOD-1596] Return an error on an unknown field. * [NOD-1596] Don't use unknownFields to check whether a message is invalid. --- .../network/netadapter/server/grpcserver/protowire/wire.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index a68f1017e..a5782f999 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -11,7 +11,11 @@ type converter interface { // ToAppMessage converts a KaspadMessage to its appmessage.Message representation func (x *KaspadMessage) ToAppMessage() (appmessage.Message, error) { - appMessage, err := x.Payload.(converter).toAppMessage() + converter, ok := x.Payload.(converter) + if !ok { + return nil, errors.Errorf("received invalid message") + } + appMessage, err := converter.toAppMessage() if err != nil { return nil, err } From 05941a76e7a19a035a27f24b4197f622d9d52e3e Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 24 Dec 2020 16:15:23 +0200 Subject: [PATCH 158/351] Make DomainHash and TransactionID read-only structs (#1282) * Increase size of reachability cache * Change DomainHash to struct with unexported hashArray * Fixing compilation errors stemming from new DomainHash structure * Remove obsolete Read/WriteElement methods in appmessage * Fix all tests * Fix all tests * Add comments * A few renamings * go mod tidy --- app/appmessage/common.go | 340 ------------------ app/appmessage/common_test.go | 212 +---------- app/appmessage/domainconverters.go | 8 +- app/appmessage/p2p_msgblocklocator_test.go | 4 +- .../p2p_msgrequestblocklocator_test.go | 4 +- app/appmessage/p2p_msgrequestheaders_test.go | 6 +- app/appmessage/p2p_msgtx_test.go | 7 +- app/rpc/rpccontext/chain_changed.go | 9 +- app/rpc/rpccontext/notificationmanager.go | 6 +- app/rpc/rpccontext/utxos_by_addresses.go | 3 +- app/rpc/rpccontext/verbosedata.go | 4 +- app/rpc/rpchandlers/get_block.go | 4 +- ...irtual_selected_parent_chain_from_block.go | 11 +- .../consensus/database/serialization/hash.go | 5 +- .../database/serialization/transactionid.go | 2 +- .../acceptancedatastore.go | 2 +- .../blockheaderstore/blockheaderstore.go | 2 +- .../blockrelationstore/blockrelationstore.go | 2 +- .../blockstatusstore/blockstatusstore.go | 2 +- .../datastructures/blockstore/blockstore.go | 2 +- .../finalitystore/finality_store.go | 7 +- .../ghostdagdatastore/ghostdagdatastore.go | 2 +- .../headertipsstore.go | 8 +- .../multisetstore/multisetstore.go | 2 +- .../pruningstore/pruningstore.go | 4 +- .../reachabilitydatastore.go | 2 +- .../utxodiffstore/utxodiffstore.go | 12 +- .../model/acceptancedata_equal_clone_test.go | 239 ++++++------ .../model/blockrelations_equal_clone_test.go | 53 ++- domain/consensus/model/externalapi/block.go | 6 +- .../externalapi/block_equal_clone_test.go | 153 ++++---- .../externalapi/blocklocator_clone_test.go | 51 +-- .../consensus/model/externalapi/equal_test.go | 113 +++--- domain/consensus/model/externalapi/hash.go | 97 +++-- .../externalapi/hash_clone_equal_test.go | 64 +--- .../model/externalapi/transaction.go | 50 ++- .../transaction_equal_clone_test.go | 289 +++++++-------- domain/consensus/model/pow/pow.go | 6 +- domain/consensus/model/reachabilitydata.go | 9 +- .../reachabilitydata_equal_clone_test.go | 138 ++++--- domain/consensus/model/virtual.go | 4 +- .../blockbuilder/test_block_builder.go | 4 +- .../block_body_in_isolation_test.go | 118 +++--- .../processes/ghostdag2/ghostdagimpl.go | 11 +- .../ghostdagmanager/ghostdag_test.go | 34 +- .../reachabilitymanager/reachability_test.go | 11 +- .../consensus/ruleerrors/rule_error_test.go | 8 +- .../utils/consensushashing/transaction.go | 2 +- domain/consensus/utils/hashes/compare.go | 6 +- domain/consensus/utils/hashes/from_bytes.go | 17 - domain/consensus/utils/hashes/strings.go | 43 --- domain/consensus/utils/hashes/to_big.go | 5 +- domain/consensus/utils/hashes/writers.go | 7 +- domain/consensus/utils/merkle/merkle.go | 4 +- domain/consensus/utils/multiset/multiset.go | 11 +- .../consensus/utils/serialization/common.go | 4 +- .../consensus/utils/transactionid/compare.go | 22 +- .../utils/transactionid/from_bytes.go | 11 +- .../utils/transactionid/from_string.go | 3 +- .../consensus/utils/txscript/engine_test.go | 8 +- domain/consensus/utils/txscript/opcode.go | 7 +- domain/consensus/utils/txscript/sign.go | 2 +- domain/consensus/utils/utxo/serialization.go | 2 +- .../utils/utxo/serialization_test.go | 8 +- domain/dagconfig/genesis.go | 40 +-- domain/dagconfig/params.go | 8 +- domain/dagconfig/params_test.go | 9 +- go.sum | 11 + .../server/grpcserver/protowire/common.go | 10 +- .../integration/selected_parent_chain_test.go | 22 +- 70 files changed, 966 insertions(+), 1426 deletions(-) delete mode 100644 domain/consensus/utils/hashes/from_bytes.go diff --git a/app/appmessage/common.go b/app/appmessage/common.go index 66b5ca531..c772b1acd 100644 --- a/app/appmessage/common.go +++ b/app/appmessage/common.go @@ -5,19 +5,9 @@ package appmessage import ( - "fmt" - "io" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/id" - "github.com/kaspanet/kaspad/util/binaryserializer" - "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" ) -// MaxVarIntPayload is the maximum payload size for a variable length integer. -const MaxVarIntPayload = 9 - // MaxInvPerMsg is the maximum number of inventory vectors that can be in any type of kaspa inv message. const MaxInvPerMsg = 1 << 17 @@ -28,333 +18,3 @@ var errNonCanonicalVarInt = "non-canonical varint %x - discriminant %x must " + // errNoEncodingForType signifies that there's no encoding for the given type. var errNoEncodingForType = errors.New("there's no encoding for this type") - -// int64Time represents a unix timestamp with milliseconds precision encoded with -// an int64. It is used as a way to signal the readElement function how to decode -// a timestamp into a Go mstime.Time since it is otherwise ambiguous. -type int64Time mstime.Time - -// ReadElement reads the next sequence of bytes from r using little endian -// depending on the concrete type of element pointed to. -func ReadElement(r io.Reader, element interface{}) error { - // Attempt to read the element based on the concrete type via fast - // type assertions first. - switch e := element.(type) { - case *int32: - rv, err := binaryserializer.Uint32(r) - if err != nil { - return err - } - *e = int32(rv) - return nil - - case *uint32: - rv, err := binaryserializer.Uint32(r) - if err != nil { - return err - } - *e = rv - return nil - - case *int64: - rv, err := binaryserializer.Uint64(r) - if err != nil { - return err - } - *e = int64(rv) - return nil - - case *uint64: - rv, err := binaryserializer.Uint64(r) - if err != nil { - return err - } - *e = rv - return nil - - case *uint8: - rv, err := binaryserializer.Uint8(r) - if err != nil { - return err - } - *e = rv - return nil - - case *bool: - rv, err := binaryserializer.Uint8(r) - if err != nil { - return err - } - if rv == 0x00 { - *e = false - } else { - *e = true - } - return nil - - // Unix timestamp encoded as an int64. - case *int64Time: - rv, err := binaryserializer.Uint64(r) - if err != nil { - return err - } - *e = int64Time(mstime.UnixMilliseconds(int64(rv))) - return nil - - // Message header checksum. - case *[4]byte: - _, err := io.ReadFull(r, e[:]) - if err != nil { - return err - } - return nil - - // Message header command. - case *MessageCommand: - rv, err := binaryserializer.Uint32(r) - if err != nil { - return err - } - *e = MessageCommand(rv) - return nil - - // IP address. - case *[16]byte: - _, err := io.ReadFull(r, e[:]) - if err != nil { - return err - } - return nil - - case *externalapi.DomainHash: - _, err := io.ReadFull(r, e[:]) - if err != nil { - return err - } - return nil - - case *id.ID: - return e.Deserialize(r) - - case *externalapi.DomainSubnetworkID: - _, err := io.ReadFull(r, e[:]) - if err != nil { - return err - } - return nil - - case *ServiceFlag: - rv, err := binaryserializer.Uint64(r) - if err != nil { - return err - } - *e = ServiceFlag(rv) - return nil - - case *KaspaNet: - rv, err := binaryserializer.Uint32(r) - if err != nil { - return err - } - *e = KaspaNet(rv) - return nil - } - - return errors.Wrapf(errNoEncodingForType, "couldn't find a way to read type %T", element) -} - -// readElements reads multiple items from r. It is equivalent to multiple -// calls to readElement. -func readElements(r io.Reader, elements ...interface{}) error { - for _, element := range elements { - err := ReadElement(r, element) - if err != nil { - return err - } - } - return nil -} - -// WriteElement writes the little endian representation of element to w. -func WriteElement(w io.Writer, element interface{}) error { - // Attempt to write the element based on the concrete type via fast - // type assertions first. - switch e := element.(type) { - case int32: - err := binaryserializer.PutUint32(w, uint32(e)) - if err != nil { - return err - } - return nil - - case uint32: - err := binaryserializer.PutUint32(w, e) - if err != nil { - return err - } - return nil - - case int64: - err := binaryserializer.PutUint64(w, uint64(e)) - if err != nil { - return err - } - return nil - - case uint64: - err := binaryserializer.PutUint64(w, e) - if err != nil { - return err - } - return nil - - case uint8: - err := binaryserializer.PutUint8(w, e) - if err != nil { - return err - } - return nil - - case bool: - var err error - if e { - err = binaryserializer.PutUint8(w, 0x01) - } else { - err = binaryserializer.PutUint8(w, 0x00) - } - if err != nil { - return err - } - return nil - - // Message header checksum. - case [4]byte: - _, err := w.Write(e[:]) - if err != nil { - return err - } - return nil - - // Message header command. - case MessageCommand: - err := binaryserializer.PutUint32(w, uint32(e)) - if err != nil { - return err - } - return nil - - // IP address. - case [16]byte: - _, err := w.Write(e[:]) - if err != nil { - return err - } - return nil - - case *externalapi.DomainHash: - _, err := w.Write(e[:]) - if err != nil { - return err - } - return nil - - case *id.ID: - return e.Serialize(w) - - case *externalapi.DomainSubnetworkID: - _, err := w.Write(e[:]) - if err != nil { - return err - } - return nil - - case ServiceFlag: - err := binaryserializer.PutUint64(w, uint64(e)) - if err != nil { - return err - } - return nil - - case KaspaNet: - err := binaryserializer.PutUint32(w, uint32(e)) - if err != nil { - return err - } - return nil - } - - return errors.Wrapf(errNoEncodingForType, "couldn't find a way to write type %T", element) -} - -// writeElements writes multiple items to w. It is equivalent to multiple -// calls to writeElement. -func writeElements(w io.Writer, elements ...interface{}) error { - for _, element := range elements { - err := WriteElement(w, element) - if err != nil { - return err - } - } - return nil -} - -// ReadVarInt reads a variable length integer from r and returns it as a uint64. -func ReadVarInt(r io.Reader) (uint64, error) { - discriminant, err := binaryserializer.Uint8(r) - if err != nil { - return 0, err - } - - var rv uint64 - switch discriminant { - case 0xff: - sv, err := binaryserializer.Uint64(r) - if err != nil { - return 0, err - } - rv = sv - - // The encoding is not canonical if the value could have been - // encoded using fewer bytes. - min := uint64(0x100000000) - if rv < min { - return 0, messageError("readVarInt", fmt.Sprintf( - errNonCanonicalVarInt, rv, discriminant, min)) - } - - case 0xfe: - sv, err := binaryserializer.Uint32(r) - if err != nil { - return 0, err - } - rv = uint64(sv) - - // The encoding is not canonical if the value could have been - // encoded using fewer bytes. - min := uint64(0x10000) - if rv < min { - return 0, messageError("readVarInt", fmt.Sprintf( - errNonCanonicalVarInt, rv, discriminant, min)) - } - - case 0xfd: - sv, err := binaryserializer.Uint16(r) - if err != nil { - return 0, err - } - rv = uint64(sv) - - // The encoding is not canonical if the value could have been - // encoded using fewer bytes. - min := uint64(0xfd) - if rv < min { - return 0, messageError("readVarInt", fmt.Sprintf( - errNonCanonicalVarInt, rv, discriminant, min)) - } - - default: - rv = uint64(discriminant) - } - - return rv, nil -} diff --git a/app/appmessage/common_test.go b/app/appmessage/common_test.go index 6644d4fd9..2069106db 100644 --- a/app/appmessage/common_test.go +++ b/app/appmessage/common_test.go @@ -1,234 +1,44 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - package appmessage -import ( - "bytes" - "io" - "reflect" - "testing" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" - - "github.com/davecgh/go-spew/spew" -) +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // mainnetGenesisHash is the hash of the first block in the block DAG for the // main network (genesis block). -var mainnetGenesisHash = &externalapi.DomainHash{ +var mainnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xdc, 0x5f, 0x5b, 0x5b, 0x1d, 0xc2, 0xa7, 0x25, 0x49, 0xd5, 0x1d, 0x4d, 0xee, 0xd7, 0xa4, 0x8b, 0xaf, 0xd3, 0x14, 0x4b, 0x56, 0x78, 0x98, 0xb1, 0x8c, 0xfd, 0x9f, 0x69, 0xdd, 0xcf, 0xbb, 0x63, -} +}) // simnetGenesisHash is the hash of the first block in the block DAG for the // simulation test network. -var simnetGenesisHash = &externalapi.DomainHash{ +var simnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x9d, 0x89, 0xb0, 0x6e, 0xb3, 0x47, 0xb5, 0x6e, 0xcd, 0x6c, 0x63, 0x99, 0x45, 0x91, 0xd5, 0xce, 0x9b, 0x43, 0x05, 0xc1, 0xa5, 0x5e, 0x2a, 0xda, 0x90, 0x4c, 0xf0, 0x6c, 0x4d, 0x5f, 0xd3, 0x62, -} +}) // mainnetGenesisMerkleRoot is the hash of the first transaction in the genesis // block for the main network. -var mainnetGenesisMerkleRoot = &externalapi.DomainHash{ +var mainnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4a, 0x5e, 0x1e, 0x4b, 0xaa, 0xb8, 0x9f, 0x3a, 0x32, 0x51, 0x8a, 0x88, 0xc3, 0x1b, 0xc8, 0x7f, 0x61, 0x8f, 0x76, 0x67, 0x3e, 0x2c, 0xc7, 0x7a, 0xb2, 0x12, 0x7b, 0x7a, 0xfd, 0xed, 0xa3, 0x3b, -} +}) -var exampleAcceptedIDMerkleRoot = &externalapi.DomainHash{ +var exampleAcceptedIDMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x09, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, 0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87, 0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63, 0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F, -} +}) -var exampleUTXOCommitment = &externalapi.DomainHash{ +var exampleUTXOCommitment = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x10, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, 0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87, 0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63, 0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F, -} - -// TestElementEncoding tests appmessage encode and decode for various element types. This -// is mainly to test the "fast" paths in readElement and writeElement which use -// type assertions to avoid reflection when possible. -func TestElementEncoding(t *testing.T) { - tests := []struct { - in interface{} // Value to encode - buf []byte // Encoded value - }{ - {int32(1), []byte{0x01, 0x00, 0x00, 0x00}}, - {uint32(256), []byte{0x00, 0x01, 0x00, 0x00}}, - { - int64(65536), - []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, - }, - { - uint64(4294967296), - []byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, - }, - { - true, - []byte{0x01}, - }, - { - false, - []byte{0x00}, - }, - { - [4]byte{0x01, 0x02, 0x03, 0x04}, - []byte{0x01, 0x02, 0x03, 0x04}, - }, - { - MessageCommand(0x10), - []byte{ - 0x10, 0x00, 0x00, 0x00, - }, - }, - { - [16]byte{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - }, - []byte{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - }, - }, - { - (*externalapi.DomainHash)(&[externalapi.DomainHashSize]byte{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - }), - []byte{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - }, - }, - { - ServiceFlag(SFNodeNetwork), - []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - }, - { - KaspaNet(Mainnet), - []byte{0x1d, 0xf7, 0xdc, 0x3d}, - }, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Write to appmessage format. - var buf bytes.Buffer - err := WriteElement(&buf, test.in) - if err != nil { - t.Errorf("writeElement #%d error %v", i, err) - continue - } - if !bytes.Equal(buf.Bytes(), test.buf) { - t.Errorf("writeElement #%d\n got: %s want: %s", i, - spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) - continue - } - - // Read from appmessage format. - rbuf := bytes.NewReader(test.buf) - val := test.in - if reflect.ValueOf(test.in).Kind() != reflect.Ptr { - val = reflect.New(reflect.TypeOf(test.in)).Interface() - } - err = ReadElement(rbuf, val) - if err != nil { - t.Errorf("readElement #%d error %v", i, err) - continue - } - ival := val - if reflect.ValueOf(test.in).Kind() != reflect.Ptr { - ival = reflect.Indirect(reflect.ValueOf(val)).Interface() - } - if !reflect.DeepEqual(ival, test.in) { - t.Errorf("readElement #%d\n got: %s want: %s", i, - spew.Sdump(ival), spew.Sdump(test.in)) - continue - } - } -} - -// TestElementEncodingErrors performs negative tests against appmessage encode and decode -// of various element types to confirm error paths work correctly. -func TestElementEncodingErrors(t *testing.T) { - type writeElementReflect int32 - - tests := []struct { - in interface{} // Value to encode - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error - }{ - {int32(1), 0, io.ErrShortWrite, io.EOF}, - {uint32(256), 0, io.ErrShortWrite, io.EOF}, - {int64(65536), 0, io.ErrShortWrite, io.EOF}, - {true, 0, io.ErrShortWrite, io.EOF}, - {[4]byte{0x01, 0x02, 0x03, 0x04}, 0, io.ErrShortWrite, io.EOF}, - { - MessageCommand(10), - 0, io.ErrShortWrite, io.EOF, - }, - { - [16]byte{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - }, - 0, io.ErrShortWrite, io.EOF, - }, - { - (*externalapi.DomainHash)(&[externalapi.DomainHashSize]byte{ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - }), - 0, io.ErrShortWrite, io.EOF, - }, - {ServiceFlag(SFNodeNetwork), 0, io.ErrShortWrite, io.EOF}, - {KaspaNet(Mainnet), 0, io.ErrShortWrite, io.EOF}, - // Type with no supported encoding. - {writeElementReflect(0), 0, errNoEncodingForType, errNoEncodingForType}, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - // Encode to appmessage format. - w := newFixedWriter(test.max) - err := WriteElement(w, test.in) - if !errors.Is(err, test.writeErr) { - t.Errorf("writeElement #%d wrong error got: %v, want: %v", - i, err, test.writeErr) - continue - } - - // Decode from appmessage format. - r := newFixedReader(test.max, nil) - val := test.in - if reflect.ValueOf(test.in).Kind() != reflect.Ptr { - val = reflect.New(reflect.TypeOf(test.in)).Interface() - } - err = ReadElement(r, val) - if !errors.Is(err, test.readErr) { - t.Errorf("readElement #%d wrong error got: %v, want: %v", - i, err, test.readErr) - continue - } - } -} +}) diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 21733ff87..46f52f9af 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -2,8 +2,8 @@ package appmessage import ( "encoding/hex" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "github.com/kaspanet/kaspad/util/mstime" @@ -208,7 +208,7 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa if err != nil { return nil, err } - payloadHash, err := hashes.FromBytes(payloadHashBytes) + payloadHash, err := externalapi.NewDomainHashFromByteSlice(payloadHashBytes) if err != nil { return nil, err } @@ -233,7 +233,7 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransaction) *RPCTransaction { inputs := make([]*RPCTransactionInput, len(transaction.Inputs)) for i, input := range transaction.Inputs { - transactionID := hex.EncodeToString(input.PreviousOutpoint.TransactionID[:]) + transactionID := input.PreviousOutpoint.TransactionID.String() previousOutpoint := &RPCOutpoint{ TransactionID: transactionID, Index: input.PreviousOutpoint.Index, @@ -254,7 +254,7 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio } } subnetworkID := hex.EncodeToString(transaction.SubnetworkID[:]) - payloadHash := hex.EncodeToString(transaction.PayloadHash[:]) + payloadHash := transaction.PayloadHash.String() payload := hex.EncodeToString(transaction.Payload) return &RPCTransaction{ Version: transaction.Version, diff --git a/app/appmessage/p2p_msgblocklocator_test.go b/app/appmessage/p2p_msgblocklocator_test.go index 1623c7a55..889fe487d 100644 --- a/app/appmessage/p2p_msgblocklocator_test.go +++ b/app/appmessage/p2p_msgblocklocator_test.go @@ -3,8 +3,6 @@ package appmessage import ( "testing" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/davecgh/go-spew/spew" @@ -13,7 +11,7 @@ import ( // TestBlockLocator tests the MsgBlockLocator API. func TestBlockLocator(t *testing.T) { hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - locatorHash, err := hashes.FromString(hashStr) + locatorHash, err := externalapi.NewDomainHashFromString(hashStr) if err != nil { t.Errorf("NewHashFromStr: %v", err) } diff --git a/app/appmessage/p2p_msgrequestblocklocator_test.go b/app/appmessage/p2p_msgrequestblocklocator_test.go index 925f3922b..e94f6ef94 100644 --- a/app/appmessage/p2p_msgrequestblocklocator_test.go +++ b/app/appmessage/p2p_msgrequestblocklocator_test.go @@ -4,14 +4,12 @@ import ( "testing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) // TestRequestBlockLocator tests the MsgRequestBlockLocator API. func TestRequestBlockLocator(t *testing.T) { hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - highHash, err := hashes.FromString(hashStr) + highHash, err := externalapi.NewDomainHashFromString(hashStr) if err != nil { t.Errorf("NewHashFromStr: %v", err) } diff --git a/app/appmessage/p2p_msgrequestheaders_test.go b/app/appmessage/p2p_msgrequestheaders_test.go index 9d0a60cd3..ac1f7a4a8 100644 --- a/app/appmessage/p2p_msgrequestheaders_test.go +++ b/app/appmessage/p2p_msgrequestheaders_test.go @@ -7,19 +7,19 @@ package appmessage import ( "testing" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) // TestRequstIBDBlocks tests the MsgRequestHeaders API. func TestRequstIBDBlocks(t *testing.T) { hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - lowHash, err := hashes.FromString(hashStr) + lowHash, err := externalapi.NewDomainHashFromString(hashStr) if err != nil { t.Errorf("NewHashFromStr: %v", err) } hashStr = "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - highHash, err := hashes.FromString(hashStr) + highHash, err := externalapi.NewDomainHashFromString(hashStr) if err != nil { t.Errorf("NewHashFromStr: %v", err) } diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index dd124e653..a8704e3df 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -7,12 +7,11 @@ package appmessage import ( "bytes" "fmt" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "math" "reflect" "testing" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" @@ -185,7 +184,7 @@ func TestTxHashAndID(t *testing.T) { } hash2Str := "0c60a073b56ff0510307e3efbb5e1881c3b1b97b4f0a69e4220042a15596766b" - wantHash2, err := hashes.FromString(hash2Str) + wantHash2, err := externalapi.NewDomainHashFromString(hash2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) return @@ -201,7 +200,7 @@ func TestTxHashAndID(t *testing.T) { txIns := []*TxIn{{ PreviousOutpoint: Outpoint{ Index: 0, - TxID: externalapi.DomainTransactionID{1, 2, 3}, + TxID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{1, 2, 3}), }, SignatureScript: []byte{ 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xDA, 0x0D, 0xC6, 0xAE, 0xCE, 0xFE, 0x1E, 0x06, 0xEF, 0xDF, diff --git a/app/rpc/rpccontext/chain_changed.go b/app/rpc/rpccontext/chain_changed.go index d3f0dd6b3..2375e3ce8 100644 --- a/app/rpc/rpccontext/chain_changed.go +++ b/app/rpc/rpccontext/chain_changed.go @@ -1,7 +1,6 @@ package rpccontext import ( - "encoding/hex" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" @@ -14,7 +13,7 @@ func (ctx *Context) ConvertVirtualSelectedParentChainChangesToChainChangedNotifi removedChainBlockHashes := make([]string, len(selectedParentChainChanges.Removed)) for i, removed := range selectedParentChainChanges.Removed { - removedChainBlockHashes[i] = hex.EncodeToString(removed[:]) + removedChainBlockHashes[i] = removed.String() } addedChainBlocks := make([]*appmessage.ChainBlock, len(selectedParentChainChanges.Added)) @@ -28,16 +27,16 @@ func (ctx *Context) ConvertVirtualSelectedParentChainChangesToChainChangedNotifi acceptedTransactionIDs := make([]string, len(acceptedBlock.TransactionAcceptanceData)) for k, transaction := range acceptedBlock.TransactionAcceptanceData { transactionID := consensushashing.TransactionID(transaction.Transaction) - acceptedTransactionIDs[k] = hex.EncodeToString(transactionID[:]) + acceptedTransactionIDs[k] = transactionID.String() } acceptedBlocks[j] = &appmessage.AcceptedBlock{ - Hash: hex.EncodeToString(acceptedBlock.BlockHash[:]), + Hash: acceptedBlock.BlockHash.String(), AcceptedTransactionIDs: acceptedTransactionIDs, } } addedChainBlocks[i] = &appmessage.ChainBlock{ - Hash: hex.EncodeToString(added[:]), + Hash: added.String(), AcceptedBlocks: acceptedBlocks, } } diff --git a/app/rpc/rpccontext/notificationmanager.go b/app/rpc/rpccontext/notificationmanager.go index 5fc44ac6d..284e5e4d0 100644 --- a/app/rpc/rpccontext/notificationmanager.go +++ b/app/rpc/rpccontext/notificationmanager.go @@ -1,12 +1,12 @@ package rpccontext import ( - "encoding/hex" + "sync" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/utxoindex" routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" - "sync" ) // NotificationManager manages notifications for the RPC @@ -236,7 +236,7 @@ func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification( notification.Removed = append(notification.Removed, &appmessage.UTXOsByAddressesEntry{ Address: listenerAddress.Address, Outpoint: &appmessage.RPCOutpoint{ - TransactionID: hex.EncodeToString(outpoint.TransactionID[:]), + TransactionID: outpoint.TransactionID.String(), Index: outpoint.Index, }, }) diff --git a/app/rpc/rpccontext/utxos_by_addresses.go b/app/rpc/rpccontext/utxos_by_addresses.go index b4ead0d75..7fd2458e7 100644 --- a/app/rpc/rpccontext/utxos_by_addresses.go +++ b/app/rpc/rpccontext/utxos_by_addresses.go @@ -2,6 +2,7 @@ package rpccontext import ( "encoding/hex" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/utxoindex" ) @@ -14,7 +15,7 @@ func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pair utxosByAddressesEntries = append(utxosByAddressesEntries, &appmessage.UTXOsByAddressesEntry{ Address: address, Outpoint: &appmessage.RPCOutpoint{ - TransactionID: hex.EncodeToString(outpoint.TransactionID[:]), + TransactionID: outpoint.TransactionID.String(), Index: outpoint.Index, }, UTXOEntry: &appmessage.RPCUTXOEntry{ diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 88b464072..1828dbf61 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -7,6 +7,8 @@ import ( "math/big" "strconv" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" @@ -37,7 +39,7 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ HashMerkleRoot: blockHeader.HashMerkleRoot.String(), AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot.String(), UTXOCommitment: blockHeader.UTXOCommitment.String(), - ParentHashes: externalapi.DomainHashesToStrings(blockHeader.ParentHashes), + ParentHashes: hashes.ToStrings(blockHeader.ParentHashes), Nonce: blockHeader.Nonce, Time: blockHeader.TimeInMilliseconds, Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), diff --git a/app/rpc/rpchandlers/get_block.go b/app/rpc/rpchandlers/get_block.go index dce3caf61..c2de8b106 100644 --- a/app/rpc/rpchandlers/get_block.go +++ b/app/rpc/rpchandlers/get_block.go @@ -3,7 +3,7 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -12,7 +12,7 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme getBlockRequest := request.(*appmessage.GetBlockRequestMessage) // Load the raw block bytes from the database. - hash, err := hashes.FromString(getBlockRequest.Hash) + hash, err := externalapi.NewDomainHashFromString(getBlockRequest.Hash) if err != nil { errorMessage := &appmessage.GetBlockResponseMessage{} errorMessage.Error = appmessage.RPCErrorf("Hash could not be parsed: %s", err) diff --git a/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go b/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go index c0a5789dd..c3430c193 100644 --- a/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go +++ b/app/rpc/rpchandlers/get_virtual_selected_parent_chain_from_block.go @@ -1,10 +1,9 @@ package rpchandlers import ( - "encoding/hex" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -12,13 +11,7 @@ import ( func HandleGetVirtualSelectedParentChainFromBlock(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { getVirtualSelectedParentChainFromBlockRequest := request.(*appmessage.GetVirtualSelectedParentChainFromBlockRequestMessage) - startHashBytes, err := hex.DecodeString(getVirtualSelectedParentChainFromBlockRequest.StartHash) - if err != nil { - errorMessage := &appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage{} - errorMessage.Error = appmessage.RPCErrorf("Could not parse startHash: %s", err) - return errorMessage, nil - } - startHash, err := hashes.FromBytes(startHashBytes) + startHash, err := externalapi.NewDomainHashFromString(getVirtualSelectedParentChainFromBlockRequest.StartHash) if err != nil { errorMessage := &appmessage.GetVirtualSelectedParentChainFromBlockResponseMessage{} errorMessage.Error = appmessage.RPCErrorf("Could not parse startHash: %s", err) diff --git a/domain/consensus/database/serialization/hash.go b/domain/consensus/database/serialization/hash.go index f09bc290a..6e4f7d5c0 100644 --- a/domain/consensus/database/serialization/hash.go +++ b/domain/consensus/database/serialization/hash.go @@ -2,17 +2,16 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) // DbHashToDomainHash converts a DbHash to a DomainHash func DbHashToDomainHash(dbHash *DbHash) (*externalapi.DomainHash, error) { - return hashes.FromBytes(dbHash.Hash) + return externalapi.NewDomainHashFromByteSlice(dbHash.Hash) } // DomainHashToDbHash converts a DomainHash to a DbHash func DomainHashToDbHash(domainHash *externalapi.DomainHash) *DbHash { - return &DbHash{Hash: domainHash[:]} + return &DbHash{Hash: domainHash.ByteSlice()} } // DomainHashesToDbHashes converts a slice of DomainHash to a slice of DbHash diff --git a/domain/consensus/database/serialization/transactionid.go b/domain/consensus/database/serialization/transactionid.go index dab925b7b..24c1c0664 100644 --- a/domain/consensus/database/serialization/transactionid.go +++ b/domain/consensus/database/serialization/transactionid.go @@ -12,5 +12,5 @@ func DbTransactionIDToDomainTransactionID(dbTransactionID *DbTransactionId) (*ex // DomainTransactionIDToDbTransactionID converts DomainTransactionID to DbTransactionId func DomainTransactionIDToDbTransactionID(domainTransactionID *externalapi.DomainTransactionID) *DbTransactionId { - return &DbTransactionId{TransactionId: domainTransactionID[:]} + return &DbTransactionId{TransactionId: domainTransactionID.ByteSlice()} } diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index ce824e215..2cbb76acf 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -113,5 +113,5 @@ func (ads *acceptanceDataStore) deserializeAcceptanceData(acceptanceDataBytes [] } func (ads *acceptanceDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index 81934893b..ce80f7078 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -164,7 +164,7 @@ func (bhs *blockHeaderStore) Delete(blockHash *externalapi.DomainHash) { } func (bhs *blockHeaderStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } func (bhs *blockHeaderStore) serializeHeader(header *externalapi.DomainBlockHeader) ([]byte, error) { diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index 64b69e5cf..d1c6a75c2 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -89,7 +89,7 @@ func (brs *blockRelationStore) Has(dbContext model.DBReader, blockHash *external } func (brs *blockRelationStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } func (brs *blockRelationStore) serializeBlockRelations(blockRelations *model.BlockRelations) ([]byte, error) { diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index 943d3ad5c..40c97433b 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -111,5 +111,5 @@ func (bss *blockStatusStore) deserializeBlockStatus(statusBytes []byte) (externa } func (bss *blockStatusStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index 20c51efb1..a688d0853 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -178,7 +178,7 @@ func (bs *blockStore) deserializeBlock(blockBytes []byte) (*externalapi.DomainBl } func (bs *blockStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } func (bs *blockStore) Count() uint64 { diff --git a/domain/consensus/datastructures/finalitystore/finality_store.go b/domain/consensus/datastructures/finalitystore/finality_store.go index 4cd34e35c..002f1d309 100644 --- a/domain/consensus/datastructures/finalitystore/finality_store.go +++ b/domain/consensus/datastructures/finalitystore/finality_store.go @@ -4,7 +4,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) @@ -43,7 +42,7 @@ func (fs *finalityStore) FinalityPoint( if err != nil { return nil, err } - finalityPointHash, err := hashes.FromBytes(finalityPointHashBytes) + finalityPointHash, err := externalapi.NewDomainHashFromByteSlice(finalityPointHashBytes) if err != nil { return nil, err } @@ -58,7 +57,7 @@ func (fs *finalityStore) Discard() { func (fs *finalityStore) Commit(dbTx model.DBTransaction) error { for hash, finalityPointHash := range fs.staging { - err := dbTx.Put(fs.hashAsKey(&hash), finalityPointHash[:]) + err := dbTx.Put(fs.hashAsKey(&hash), finalityPointHash.ByteSlice()) if err != nil { return err } @@ -74,5 +73,5 @@ func (fs *finalityStore) IsStaged() bool { } func (fs *finalityStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index c42a01402..c8b1a7c01 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -79,7 +79,7 @@ func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externala } func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) ([]byte, error) { diff --git a/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go b/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go index 8926c1c12..f0df6910b 100644 --- a/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go +++ b/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go @@ -56,7 +56,7 @@ func (hts *headerSelectedTipStore) Commit(dbTx model.DBTransaction) error { } func (hts *headerSelectedTipStore) Stage(selectedTip *externalapi.DomainHash) { - hts.staging = selectedTip.Clone() + hts.staging = selectedTip } func (hts *headerSelectedTipStore) IsStaged() bool { @@ -65,11 +65,11 @@ func (hts *headerSelectedTipStore) IsStaged() bool { func (hts *headerSelectedTipStore) HeadersSelectedTip(dbContext model.DBReader) (*externalapi.DomainHash, error) { if hts.staging != nil { - return hts.staging.Clone(), nil + return hts.staging, nil } if hts.cache != nil { - return hts.cache.Clone(), nil + return hts.cache, nil } selectedTipBytes, err := dbContext.Get(headerSelectedTipKey) @@ -82,7 +82,7 @@ func (hts *headerSelectedTipStore) HeadersSelectedTip(dbContext model.DBReader) return nil, err } hts.cache = selectedTip - return hts.cache.Clone(), nil + return hts.cache, nil } func (hts *headerSelectedTipStore) serializeHeadersSelectedTip(selectedTip *externalapi.DomainHash) ([]byte, error) { diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go index 17aa680c5..20beca609 100644 --- a/domain/consensus/datastructures/multisetstore/multisetstore.go +++ b/domain/consensus/datastructures/multisetstore/multisetstore.go @@ -99,7 +99,7 @@ func (ms *multisetStore) Delete(blockHash *externalapi.DomainHash) { } func (ms *multisetStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { - return bucket.Key(hash[:]) + return bucket.Key(hash.ByteSlice()) } func (ms *multisetStore) serializeMultiset(multiset model.Multiset) ([]byte, error) { diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index ba69a749a..24a25258a 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -22,7 +22,7 @@ type pruningStore struct { } func (ps *pruningStore) StagePruningPointCandidate(candidate *externalapi.DomainHash) { - ps.pruningPointCandidateStaging = candidate.Clone() + ps.pruningPointCandidateStaging = candidate } func (ps *pruningStore) PruningPointCandidate(dbContext model.DBReader) (*externalapi.DomainHash, error) { @@ -66,7 +66,7 @@ func New() model.PruningStore { // Stage stages the pruning state func (ps *pruningStore) StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) { - ps.pruningPointStaging = pruningPointBlockHash.Clone() + ps.pruningPointStaging = pruningPointBlockHash ps.serializedUTXOSetStaging = pruningPointUTXOSetBytes } diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index f466e9d9c..c14f0e997 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -137,7 +137,7 @@ func (rds *reachabilityDataStore) ReachabilityReindexRoot(dbContext model.DBRead } func (rds *reachabilityDataStore) reachabilityDataBlockHashAsKey(hash *externalapi.DomainHash) model.DBKey { - return reachabilityDataBucket.Key(hash[:]) + return reachabilityDataBucket.Key(hash.ByteSlice()) } func (rds *reachabilityDataStore) serializeReachabilityData(reachabilityData *model.ReachabilityData) ([]byte, error) { diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index 60d5e55e3..9fa0adc18 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -38,7 +38,7 @@ func (uds *utxoDiffStore) Stage(blockHash *externalapi.DomainHash, utxoDiff mode uds.utxoDiffStaging[*blockHash] = utxoDiff if utxoDiffChild != nil { - uds.utxoDiffChildStaging[*blockHash] = utxoDiffChild.Clone() + uds.utxoDiffChildStaging[*blockHash] = utxoDiffChild } } @@ -132,11 +132,11 @@ func (uds *utxoDiffStore) UTXODiff(dbContext model.DBReader, blockHash *external // UTXODiffChild gets the utxoDiff child associated with the given blockHash func (uds *utxoDiffStore) UTXODiffChild(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { if utxoDiffChild, ok := uds.utxoDiffChildStaging[*blockHash]; ok { - return utxoDiffChild.Clone(), nil + return utxoDiffChild, nil } if utxoDiffChild, ok := uds.utxoDiffChildCache.Get(blockHash); ok { - return utxoDiffChild.(*externalapi.DomainHash).Clone(), nil + return utxoDiffChild.(*externalapi.DomainHash), nil } utxoDiffChildBytes, err := dbContext.Get(uds.utxoDiffChildHashAsKey(blockHash)) @@ -149,7 +149,7 @@ func (uds *utxoDiffStore) UTXODiffChild(dbContext model.DBReader, blockHash *ext return nil, err } uds.utxoDiffChildCache.Add(blockHash, utxoDiffChild) - return utxoDiffChild.Clone(), nil + return utxoDiffChild, nil } // HasUTXODiffChild returns true if the given blockHash has a UTXODiffChild @@ -180,11 +180,11 @@ func (uds *utxoDiffStore) Delete(blockHash *externalapi.DomainHash) { } func (uds *utxoDiffStore) utxoDiffHashAsKey(hash *externalapi.DomainHash) model.DBKey { - return utxoDiffBucket.Key(hash[:]) + return utxoDiffBucket.Key(hash.ByteSlice()) } func (uds *utxoDiffStore) utxoDiffChildHashAsKey(hash *externalapi.DomainHash) model.DBKey { - return utxoDiffChildBucket.Key(hash[:]) + return utxoDiffChildBucket.Key(hash.ByteSlice()) } func (uds *utxoDiffStore) serializeUTXODiff(utxoDiff model.UTXODiff) ([]byte, error) { diff --git a/domain/consensus/model/acceptancedata_equal_clone_test.go b/domain/consensus/model/acceptancedata_equal_clone_test.go index 73bc29c9a..b3d7936f2 100644 --- a/domain/consensus/model/acceptancedata_equal_clone_test.go +++ b/domain/consensus/model/acceptancedata_equal_clone_test.go @@ -1,10 +1,11 @@ package model_test import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "reflect" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" ) func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAcceptanceData { @@ -14,7 +15,7 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep &externalapi.DomainTransaction{ Version: 1, Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -25,17 +26,19 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -60,7 +63,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru &externalapi.DomainTransaction{ Version: 1, Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -71,17 +74,19 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -91,7 +96,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru &externalapi.DomainTransaction{ Version: 1, Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -102,17 +107,18 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -122,7 +128,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru &externalapi.DomainTransaction{ Version: 2, Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -133,17 +139,18 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -153,7 +160,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru &externalapi.DomainTransaction{ Version: 1, Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -164,17 +171,19 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 2, true, @@ -184,7 +193,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru &externalapi.DomainTransaction{ Version: 1, Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -195,17 +204,19 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, false, @@ -280,16 +291,18 @@ func TestTransactionAcceptanceData_Clone(t *testing.T) { func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { - tests := []*externalapi.BlockAcceptanceData{{&externalapi.DomainHash{1}, + tests := []*externalapi.BlockAcceptanceData{{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{ { &externalapi.DomainTransaction{ 1, - []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, - []byte{1, 2, 3}, - uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionInput{ + {externalapi.DomainOutpoint{ + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), + 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), []byte{1, 2}}, {uint64(0xFFFF), @@ -297,17 +310,19 @@ func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -329,13 +344,13 @@ type testBlockAcceptanceDataStruct struct { func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { var testBlockAcceptanceDataBase = externalapi.BlockAcceptanceData{ - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -346,30 +361,32 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, }}} //test 1: structs are equal var testBlockAcceptanceData1 = externalapi.BlockAcceptanceData{ - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -380,30 +397,32 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, }}} // test 2: different size var testBlockAcceptanceData2 = externalapi.BlockAcceptanceData{ - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -414,30 +433,32 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, }, {}}} //test 3: different transactions, same size var testBlockAcceptanceData3 = externalapi.BlockAcceptanceData{ - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -448,17 +469,19 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, false, @@ -466,13 +489,13 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { // test 4 - different block hash var testBlockAcceptanceData4 = externalapi.BlockAcceptanceData{ - &externalapi.DomainHash{2}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -483,17 +506,19 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -571,13 +596,13 @@ func TestBlockAcceptanceData_Clone(t *testing.T) { func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { test1 := []*externalapi.BlockAcceptanceData{{ - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{ { &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -588,17 +613,19 @@ func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, @@ -622,13 +649,13 @@ type testAcceptanceDataStruct struct { func initAcceptanceDataForEqual() []testAcceptanceDataStruct { var testAcceptanceDataBase = []*externalapi.BlockAcceptanceData{ { - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -639,30 +666,32 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, }}}} //test 1: structs are equal var testAcceptanceData1 = []*externalapi.BlockAcceptanceData{ - {&externalapi.DomainHash{1}, + {externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -673,30 +702,32 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, }}}} // test 2: different size var testAcceptanceData2 = []*externalapi.BlockAcceptanceData{ - {&externalapi.DomainHash{1}, + {externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -707,30 +738,32 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, }}}, {}} //test 3: different transactions, same size var testAcceptanceData3 = []*externalapi.BlockAcceptanceData{ - {&externalapi.DomainHash{1}, + {externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), []*externalapi.TransactionAcceptanceData{{ &externalapi.DomainTransaction{ 2, []*externalapi.DomainTransactionInput{{ externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -741,17 +774,19 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, 1, true, diff --git a/domain/consensus/model/blockrelations_equal_clone_test.go b/domain/consensus/model/blockrelations_equal_clone_test.go index 39c05e8e3..98193c22a 100644 --- a/domain/consensus/model/blockrelations_equal_clone_test.go +++ b/domain/consensus/model/blockrelations_equal_clone_test.go @@ -1,17 +1,24 @@ package model import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "reflect" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) func initTestBlockRelationsForClone() []*BlockRelations { tests := []*BlockRelations{ { - []*externalapi.DomainHash{{1}, {2}}, - []*externalapi.DomainHash{{3}, {4}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + }, }, } return tests @@ -30,23 +37,47 @@ type testBlockRelationsStruct struct { func initTestBlockRelationsForEqual() []testBlockRelationsStruct { var testBlockRelationsBase = BlockRelations{ - []*externalapi.DomainHash{{1}, {2}}, - []*externalapi.DomainHash{{3}, {4}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + }, } //First test: structs are equal var testBlockRelations1 = BlockRelations{ - []*externalapi.DomainHash{{1}, {2}}, - []*externalapi.DomainHash{{3}, {4}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + }, } //Second test: children changed var testBlockRelations2 = BlockRelations{ - []*externalapi.DomainHash{{1}, {2}}, - []*externalapi.DomainHash{{3}, {5}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{5}), + }, } //Third test: parents changed var testBlockRelations3 = BlockRelations{ - []*externalapi.DomainHash{{6}, {2}}, - []*externalapi.DomainHash{{3}, {4}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{6}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + }, } tests := []testBlockRelationsStruct{ diff --git a/domain/consensus/model/externalapi/block.go b/domain/consensus/model/externalapi/block.go index 07d0d5cbb..1ff82a4cb 100644 --- a/domain/consensus/model/externalapi/block.go +++ b/domain/consensus/model/externalapi/block.go @@ -63,9 +63,9 @@ func (header *DomainBlockHeader) Clone() *DomainBlockHeader { return &DomainBlockHeader{ Version: header.Version, ParentHashes: CloneHashes(header.ParentHashes), - HashMerkleRoot: *header.HashMerkleRoot.Clone(), - AcceptedIDMerkleRoot: *header.AcceptedIDMerkleRoot.Clone(), - UTXOCommitment: *header.UTXOCommitment.Clone(), + HashMerkleRoot: header.HashMerkleRoot, + AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot, + UTXOCommitment: header.UTXOCommitment, TimeInMilliseconds: header.TimeInMilliseconds, Bits: header.Bits, Nonce: header.Nonce, diff --git a/domain/consensus/model/externalapi/block_equal_clone_test.go b/domain/consensus/model/externalapi/block_equal_clone_test.go index 9a032d847..35dd50308 100644 --- a/domain/consensus/model/externalapi/block_equal_clone_test.go +++ b/domain/consensus/model/externalapi/block_equal_clone_test.go @@ -24,17 +24,19 @@ func initTestBaseTransactions() []*DomainTransaction { LockTime: 1, SubnetworkID: DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }} return testTx } @@ -48,17 +50,19 @@ func initTestAnotherTransactions() []*DomainTransaction { LockTime: 1, SubnetworkID: DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), }} return testTx } @@ -72,17 +76,19 @@ func initTestTwoTransactions() []*DomainTransaction { LockTime: 1, SubnetworkID: DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), }, { Version: 1, Inputs: []*DomainTransactionInput{}, @@ -90,17 +96,19 @@ func initTestTwoTransactions() []*DomainTransaction { LockTime: 1, SubnetworkID: DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), }} return testTx } @@ -112,10 +120,10 @@ func initTestBlockStructsForClone() []*DomainBlock { &DomainBlockHeader{ 0, - []*DomainHash{{0}}, - DomainHash{1}, - DomainHash{2}, - DomainHash{3}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), 4, 5, 6, @@ -126,9 +134,9 @@ func initTestBlockStructsForClone() []*DomainBlock { 0, []*DomainHash{}, - DomainHash{1}, - DomainHash{2}, - DomainHash{3}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), 4, 5, 6, @@ -153,10 +161,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{0}}, - DomainHash{1}, - DomainHash{2}, - DomainHash{3}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), 4, 5, 6, @@ -169,10 +177,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { baseBlock: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -188,10 +196,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -203,10 +211,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -218,10 +226,13 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}, {2}}, // Changed - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{ + NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + }, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -233,10 +244,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{100}}, // Changed - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{100})}, // Changed + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -248,10 +259,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{100}, // Changed - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), // Changed + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -263,10 +274,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{100}, // Changed - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), // Changed + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -278,10 +289,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{100}, // Changed + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), // Changed 5, 6, 7, @@ -293,10 +304,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 100, // Changed 6, 7, @@ -308,10 +319,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 100, // Changed 7, @@ -323,10 +334,10 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { block: &DomainBlock{ &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 100, // Changed diff --git a/domain/consensus/model/externalapi/blocklocator_clone_test.go b/domain/consensus/model/externalapi/blocklocator_clone_test.go index 149a51b2a..28e907687 100644 --- a/domain/consensus/model/externalapi/blocklocator_clone_test.go +++ b/domain/consensus/model/externalapi/blocklocator_clone_test.go @@ -8,48 +8,57 @@ import ( func initTestBlockLocatorForClone() []*BlockLocator { tests := []*BlockLocator{{ - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, - {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}, - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}), }, { - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2}, - {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1}, - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1, 1}, - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1, 1}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{ + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2, 1}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2, 1}), }, } return tests diff --git a/domain/consensus/model/externalapi/equal_test.go b/domain/consensus/model/externalapi/equal_test.go index 4ccd24508..cc4797a0c 100644 --- a/domain/consensus/model/externalapi/equal_test.go +++ b/domain/consensus/model/externalapi/equal_test.go @@ -24,10 +24,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{0}}, - DomainHash{1}, - DomainHash{2}, - DomainHash{3}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), 4, 5, 6, @@ -39,10 +39,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { baseHeader: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -55,10 +55,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -68,10 +68,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 100, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -81,10 +81,13 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}, {2}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + // []*DomainHash{{1}, {2}}, + []*DomainHash{ + NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + NewDomainHashFromByteArray(&[DomainHashSize]byte{2})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -94,10 +97,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{100}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{100})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -107,10 +110,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{100}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -120,10 +123,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{100}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 7, @@ -133,10 +136,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{100}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), 5, 6, 7, @@ -146,10 +149,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 100, 6, 7, @@ -159,10 +162,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 100, 7, @@ -172,10 +175,10 @@ func TestDomainBlockHeader_Equal(t *testing.T) { { header: &DomainBlockHeader{ 0, - []*DomainHash{{1}}, - DomainHash{2}, - DomainHash{3}, - DomainHash{4}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), 5, 6, 100, @@ -205,10 +208,10 @@ func TestDomainBlockHeader_Clone(t *testing.T) { headers := []*DomainBlockHeader{ { 0, - []*DomainHash{{0}}, - DomainHash{1}, - DomainHash{2}, - DomainHash{3}, + []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), 4, 5, 6, @@ -216,9 +219,9 @@ func TestDomainBlockHeader_Clone(t *testing.T) { { 0, []*DomainHash{}, - DomainHash{1}, - DomainHash{2}, - DomainHash{3}, + *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), 4, 5, 6, diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index d52feac3c..02317d888 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -1,27 +1,79 @@ package externalapi -import "encoding/hex" +import ( + "encoding/hex" + + "github.com/pkg/errors" +) // DomainHashSize of array used to store hashes. const DomainHashSize = 32 // DomainHash is the domain representation of a Hash -type DomainHash [DomainHashSize]byte +type DomainHash struct { + hashArray [DomainHashSize]byte +} + +// NewDomainHashFromByteArray constructs a new DomainHash out of a byte array +func NewDomainHashFromByteArray(hashBytes *[DomainHashSize]byte) *DomainHash { + return &DomainHash{ + hashArray: *hashBytes, + } +} + +// NewDomainHashFromByteSlice constructs a new DomainHash out of a byte slice. +// Returns an error if the length of the byte slice is not exactly `DomainHashSize` +func NewDomainHashFromByteSlice(hashBytes []byte) (*DomainHash, error) { + if len(hashBytes) != DomainHashSize { + return nil, errors.Errorf("invalid hash size. Want: %d, got: %d", + DomainHashSize, len(hashBytes)) + } + domainHash := DomainHash{ + hashArray: [DomainHashSize]byte{}, + } + copy(domainHash.hashArray[:], hashBytes) + return &domainHash, nil +} + +// NewDomainHashFromString constructs a new DomainHash out of a hex-encoded string. +// Returns an error if the length of the string is not exactly `DomainHashSize * 2` +func NewDomainHashFromString(hashString string) (*DomainHash, error) { + expectedLength := DomainHashSize * 2 + // Return error if hash string is too long. + if len(hashString) != expectedLength { + return nil, errors.Errorf("hash string length is %d, while it should be be %d", + len(hashString), expectedLength) + } + + hashBytes, err := hex.DecodeString(hashString) + if err != nil { + return nil, errors.WithStack(err) + } + + return NewDomainHashFromByteSlice(hashBytes) +} // String returns the Hash as the hexadecimal string of the hash. func (hash DomainHash) String() string { - return hex.EncodeToString(hash[:]) + return hex.EncodeToString(hash.hashArray[:]) } -// Clone clones the hash -func (hash *DomainHash) Clone() *DomainHash { - hashClone := *hash - return &hashClone +// ByteArray returns the bytes in this hash represented as a byte array. +// The hash bytes are cloned, therefore it is safe to modify the resulting array. +func (hash *DomainHash) ByteArray() *[DomainHashSize]byte { + arrayClone := hash.hashArray + return &arrayClone +} + +// ByteSlice returns the bytes in this hash represented as a byte slice. +// The hash bytes are cloned, therefore it is safe to modify the resulting slice. +func (hash *DomainHash) ByteSlice() []byte { + return hash.ByteArray()[:] } // If this doesn't compile, it means the type definition has been changed, so it's // an indication to update Equal and Clone accordingly. -var _ DomainHash = [DomainHashSize]byte{} +var _ DomainHash = DomainHash{hashArray: [DomainHashSize]byte{}} // Equal returns whether hash equals to other func (hash *DomainHash) Equal(other *DomainHash) bool { @@ -29,7 +81,15 @@ func (hash *DomainHash) Equal(other *DomainHash) bool { return hash == other } - return *hash == *other + return hash.hashArray == other.hashArray +} + +// CloneHashes returns a clone of the given hashes slice. +// Note: since DomainHash is a read-only type, the clone is shallow +func CloneHashes(hashes []*DomainHash) []*DomainHash { + clone := make([]*DomainHash, len(hashes)) + copy(clone, hashes) + return clone } // HashesEqual returns whether the given hash slices are equal. @@ -45,22 +105,3 @@ func HashesEqual(a, b []*DomainHash) bool { } return true } - -// CloneHashes returns a clone of the given hashes slice -func CloneHashes(hashes []*DomainHash) []*DomainHash { - clone := make([]*DomainHash, len(hashes)) - for i, hash := range hashes { - clone[i] = hash.Clone() - } - return clone -} - -// DomainHashesToStrings returns a slice of strings representing the hashes in the given slice of hashes -func DomainHashesToStrings(hashes []*DomainHash) []string { - strings := make([]string, len(hashes)) - for i, hash := range hashes { - strings[i] = hash.String() - } - - return strings -} diff --git a/domain/consensus/model/externalapi/hash_clone_equal_test.go b/domain/consensus/model/externalapi/hash_clone_equal_test.go index 89e2c844e..7e47b0356 100644 --- a/domain/consensus/model/externalapi/hash_clone_equal_test.go +++ b/domain/consensus/model/externalapi/hash_clone_equal_test.go @@ -1,38 +1,9 @@ package externalapi import ( - "reflect" "testing" ) -func initTestDomainHashForClone() []*DomainHash { - - tests := []*DomainHash{ - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, - } - return tests -} - type testHashToCompare struct { hash *DomainHash expectedResult bool @@ -52,33 +23,37 @@ func initTestDomainHashForEqual() []*testHashStruct { hash: nil, expectedResult: true, }, { - hash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + hash: NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), expectedResult: false, }, }, }, { - baseHash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + baseHash: NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}), hashesToCompareTo: []testHashToCompare{ { hash: nil, expectedResult: false, }, { - hash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + hash: NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), expectedResult: false, }, { - hash: &DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + hash: NewDomainHashFromByteArray(&[DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}), expectedResult: true, }, }, @@ -88,7 +63,6 @@ func initTestDomainHashForEqual() []*testHashStruct { } func TestDomainHash_Equal(t *testing.T) { - hashTests := initTestDomainHashForEqual() for i, test := range hashTests { for j, subTest := range test.hashesToCompareTo { @@ -103,17 +77,3 @@ func TestDomainHash_Equal(t *testing.T) { } } } - -func TestDomainHash_Clone(t *testing.T) { - - hashes := initTestDomainHashForClone() - for i, hash := range hashes { - hashClone := hash.Clone() - if !hashClone.Equal(hash) { - t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) - } - if !reflect.DeepEqual(hash, hashClone) { - t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) - } - } -} diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index d0410e9f3..0dec46d5a 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -3,6 +3,7 @@ package externalapi import ( "bytes" "fmt" + "github.com/pkg/errors" ) @@ -52,7 +53,7 @@ func (tx *DomainTransaction) Clone() *DomainTransaction { LockTime: tx.LockTime, SubnetworkID: *tx.SubnetworkID.Clone(), Gas: tx.Gas, - PayloadHash: *tx.PayloadHash.Clone(), + PayloadHash: tx.PayloadHash, Payload: payloadClone, Fee: tx.Fee, Mass: tx.Mass, @@ -263,6 +264,31 @@ func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput { // DomainTransactionID represents the ID of a Kaspa transaction type DomainTransactionID DomainHash +// NewDomainTransactionIDFromByteArray constructs a new TransactionID out of a byte array +func NewDomainTransactionIDFromByteArray(transactionIDBytes *[DomainHashSize]byte) *DomainTransactionID { + return (*DomainTransactionID)(NewDomainHashFromByteArray(transactionIDBytes)) +} + +// NewDomainTransactionIDFromByteSlice constructs a new TransactionID out of a byte slice +// Returns an error if the length of the byte slice is not exactly `DomainHashSize` +func NewDomainTransactionIDFromByteSlice(transactionIDBytes []byte) (*DomainTransactionID, error) { + hash, err := NewDomainHashFromByteSlice(transactionIDBytes) + if err != nil { + return nil, err + } + return (*DomainTransactionID)(hash), nil +} + +// NewDomainTransactionIDFromString constructs a new TransactionID out of a string +// Returns an error if the length of the string is not exactly `DomainHashSize * 2` +func NewDomainTransactionIDFromString(transactionIDString string) (*DomainTransactionID, error) { + hash, err := NewDomainHashFromString(transactionIDString) + if err != nil { + return nil, err + } + return (*DomainTransactionID)(hash), nil +} + // String stringifies a transaction ID. func (id DomainTransactionID) String() string { return DomainHash(id).String() @@ -274,15 +300,19 @@ func (id *DomainTransactionID) Clone() *DomainTransactionID { return &idClone } -// If this doesn't compile, it means the type definition has been changed, so it's -// an indication to update Equal and Clone accordingly. -var _ DomainTransactionID = [DomainHashSize]byte{} - // Equal returns whether id equals to other func (id *DomainTransactionID) Equal(other *DomainTransactionID) bool { - if id == nil || other == nil { - return id == other - } - - return *id == *other + return (*DomainHash)(id).Equal((*DomainHash)(other)) +} + +// ByteArray returns the bytes in this transactionID represented as a byte array. +// The transactionID bytes are cloned, therefore it is safe to modify the resulting array. +func (id *DomainTransactionID) ByteArray() *[DomainHashSize]byte { + return (*DomainHash)(id).ByteArray() +} + +// ByteSlice returns the bytes in this transactionID represented as a byte slice. +// The transactionID bytes are cloned, therefore it is safe to modify the resulting slice. +func (id *DomainTransactionID) ByteSlice() []byte { + return (*DomainHash)(id).ByteSlice() } diff --git a/domain/consensus/model/externalapi/transaction_equal_clone_test.go b/domain/consensus/model/externalapi/transaction_equal_clone_test.go index 9a6c6e7b8..43f3d3d8d 100644 --- a/domain/consensus/model/externalapi/transaction_equal_clone_test.go +++ b/domain/consensus/model/externalapi/transaction_equal_clone_test.go @@ -1,10 +1,11 @@ package externalapi_test import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "reflect" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" ) // Changed fields of a test struct compared to a base test struct marked as "changed" and @@ -66,7 +67,7 @@ func initTestBaseTransaction() *externalapi.DomainTransaction { testTx := &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -77,17 +78,17 @@ func initTestBaseTransaction() *externalapi.DomainTransaction { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), } return testTx } @@ -98,7 +99,7 @@ func initTestTransactionToCompare() []*transactionToCompare { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -109,24 +110,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, //Changed + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), //Changed []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -137,24 +138,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -165,24 +166,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01, 0x02}, //Changed 1, - externalapi.DomainHash{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -193,24 +194,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01, 0x02}, //Changed 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -220,17 +221,17 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: true, }, @@ -239,7 +240,7 @@ func initTestTransactionToCompare() []*transactionToCompare { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -249,17 +250,17 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}), }, expectsPanic: true, }, @@ -267,7 +268,7 @@ func initTestTransactionToCompare() []*transactionToCompare { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -278,24 +279,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 1000000000, //Changed 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 2, //Changed []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -305,24 +306,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, //6 expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -332,24 +333,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 2, //Changed - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), }, //7 expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -359,29 +360,29 @@ func initTestTransactionToCompare() []*transactionToCompare { 2, //Changed externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, {externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -391,24 +392,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -419,24 +420,24 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, @@ -446,10 +447,10 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, @@ -460,7 +461,7 @@ func initTestTransactionToCompare() []*transactionToCompare { tx: &externalapi.DomainTransaction{ 1, []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3, 4}, true, 2)}}, @@ -470,17 +471,17 @@ func initTestTransactionToCompare() []*transactionToCompare { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, @@ -495,7 +496,7 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction { Version: 1, Inputs: []*externalapi.DomainTransactionInput{ {externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x01}, 0xFFFF}, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, @@ -505,17 +506,17 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction { LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), Payload: []byte{0x01}, Fee: 5555555555, Mass: 1, - ID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, { Version: 1, Inputs: []*externalapi.DomainTransactionInput{}, @@ -523,14 +524,14 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction { LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: &externalapi.DomainTransactionID{}, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{}), }, } return tests @@ -553,17 +554,17 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, expectedResult: false, }, { @@ -577,17 +578,17 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, - &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, transactionToCompareTo: []*transactionToCompare{{ tx: nil, @@ -600,10 +601,10 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 1, externalapi.DomainSubnetworkID{0x01}, 0, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, @@ -618,10 +619,10 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 1, externalapi.DomainSubnetworkID{0x01}, 1, - externalapi.DomainHash{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, 0, 1, @@ -636,7 +637,7 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { func initTestBaseDomainTransactionInput() *externalapi.DomainTransactionInput { basetxInput := &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), @@ -647,7 +648,7 @@ func initTestBaseDomainTransactionInput() *externalapi.DomainTransactionInput { func initTestDomainTxInputToCompare() []*transactionInputToCompare { txInput := []*transactionInputToCompare{{ tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), @@ -655,7 +656,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { expectedResult: true, }, { tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, false, 2), // Changed @@ -663,7 +664,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { expectedResult: false, }, { tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), @@ -671,7 +672,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { expectedResult: false, }, { tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3, 4}, // Changed uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), @@ -679,7 +680,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { expectedResult: false, }, { tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01, 0x02}, 0xFFFF}, // Changed + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), @@ -687,7 +688,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { expectedResult: false, }, { tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01, 0x02}, 0xFFFF}, // Changed + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed utxo.NewUTXOEntry(2 /* Changed */, []byte{0, 1, 2, 3}, true, 2), // Changed @@ -695,7 +696,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { expectedResult: false, }, { tx: &externalapi.DomainTransactionInput{ - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01, 0x02}, 0xFFFF}, // Changed + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed utxo.NewUTXOEntry(3 /* Changed */, []byte{0, 1, 2, 3}, true, 3), // Changed @@ -712,19 +713,19 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { func initTestDomainTransactionInputForClone() []*externalapi.DomainTransactionInput { txInput := []*externalapi.DomainTransactionInput{ { - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), }, { - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), }, { - externalapi.DomainOutpoint{externalapi.DomainTransactionID{0x01}, 0xFFFF}, + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), @@ -954,10 +955,10 @@ func TestDomainTransactionOutput_Clone(t *testing.T) { func initTestDomainOutpointForClone() []*externalapi.DomainOutpoint { outpoint := []*externalapi.DomainOutpoint{{ - externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}), 1}, } return outpoint @@ -967,43 +968,43 @@ func initTestDomainOutpointForEqual() []testDomainOutpointStruct { var outpoint = []*domainOutpointToCompare{{ domainOutpoint: &externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), 1}, expectedResult: true, }, { domainOutpoint: &externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}), 1}, expectedResult: false, }, { domainOutpoint: &externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0}), 2}, expectedResult: false, }} tests := []testDomainOutpointStruct{ { baseDomainOutpoint: &externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), 1}, domainOutpointToCompareTo: outpoint, }, {baseDomainOutpoint: &externalapi.DomainOutpoint{ - externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), 1}, domainOutpointToCompareTo: []*domainOutpointToCompare{{domainOutpoint: nil, expectedResult: false}}, }, {baseDomainOutpoint: nil, @@ -1044,56 +1045,41 @@ func TestDomainOutpoint_Clone(t *testing.T) { } } -func initTestDomainTransactionIDForClone() []*externalapi.DomainTransactionID { - outpoint := []*externalapi.DomainTransactionID{ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - } - - return outpoint -} - func initTestDomainTransactionIDForEqual() []testDomainTransactionIDStruct { var outpoint = []*domainTransactionIDToCompare{{ - domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + domainTransactionID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), expectedResult: true, }, { - domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + domainTransactionID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}), expectedResult: false, }, { - domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + domainTransactionID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0}), expectedResult: false, }} tests := []testDomainTransactionIDStruct{ { - baseDomainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + baseDomainTransactionID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), domainTransactionIDToCompareTo: outpoint, }, { baseDomainTransactionID: nil, domainTransactionIDToCompareTo: []*domainTransactionIDToCompare{{ - domainTransactionID: &externalapi.DomainTransactionID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + domainTransactionID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}), expectedResult: false, }}, }, @@ -1102,7 +1088,6 @@ func initTestDomainTransactionIDForEqual() []testDomainTransactionIDStruct { } func TestDomainTransactionID_Equal(t *testing.T) { - domainDomainTransactionIDs := initTestDomainTransactionIDForEqual() for i, test := range domainDomainTransactionIDs { for j, subTest := range test.domainTransactionIDToCompareTo { @@ -1117,17 +1102,3 @@ func TestDomainTransactionID_Equal(t *testing.T) { } } } - -func TestDomainTransactionID_Clone(t *testing.T) { - - domainDomainTransactionIDs := initTestDomainTransactionIDForClone() - for i, domainTransactionID := range domainDomainTransactionIDs { - domainTransactionIDClone := domainTransactionID.Clone() - if !domainTransactionIDClone.Equal(domainTransactionID) { - t.Fatalf("Test #%d:[Equal] clone should be equal to the original", i) - } - if !reflect.DeepEqual(domainTransactionID, domainTransactionIDClone) { - t.Fatalf("Test #%d:[DeepEqual] clone should be equal to the original", i) - } - } -} diff --git a/domain/consensus/model/pow/pow.go b/domain/consensus/model/pow/pow.go index c3fe5a717..323fdb93d 100644 --- a/domain/consensus/model/pow/pow.go +++ b/domain/consensus/model/pow/pow.go @@ -37,7 +37,7 @@ func calcPowValue(header *externalapi.DomainBlockHeader) *big.Int { // PRE_POW_HASH || TIME || 32 zero byte padding || NONCE writer := hashes.NewPoWHashWriter() - writer.InfallibleWrite(prePowHash[:]) + writer.InfallibleWrite(prePowHash.ByteSlice()) err := serialization.WriteElement(writer, timestamp) if err != nil { panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error")) @@ -54,11 +54,11 @@ func calcPowValue(header *externalapi.DomainBlockHeader) *big.Int { // ToBig converts a externalapi.DomainHash into a big.Int treated as a little endian string. func toBig(hash *externalapi.DomainHash) *big.Int { // We treat the Hash as little-endian for PoW purposes, but the big package wants the bytes in big-endian, so reverse them. - buf := hash.Clone() + buf := hash.ByteSlice() blen := len(buf) for i := 0; i < blen/2; i++ { buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] } - return new(big.Int).SetBytes(buf[:]) + return new(big.Int).SetBytes(buf) } diff --git a/domain/consensus/model/reachabilitydata.go b/domain/consensus/model/reachabilitydata.go index f90c42e5a..d95e5f809 100644 --- a/domain/consensus/model/reachabilitydata.go +++ b/domain/consensus/model/reachabilitydata.go @@ -2,6 +2,7 @@ package model import ( "fmt" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) @@ -93,15 +94,9 @@ func (rtn *ReachabilityTreeNode) Equal(other *ReachabilityTreeNode) bool { // Clone returns a clone of ReachabilityTreeNode func (rtn *ReachabilityTreeNode) Clone() *ReachabilityTreeNode { - - var parentClone *externalapi.DomainHash - if rtn.Parent != nil { - parentClone = rtn.Parent.Clone() - } - return &ReachabilityTreeNode{ Children: externalapi.CloneHashes(rtn.Children), - Parent: parentClone, + Parent: rtn.Parent, Interval: rtn.Interval.Clone(), } } diff --git a/domain/consensus/model/reachabilitydata_equal_clone_test.go b/domain/consensus/model/reachabilitydata_equal_clone_test.go index 408981ec9..a4251ddfa 100644 --- a/domain/consensus/model/reachabilitydata_equal_clone_test.go +++ b/domain/consensus/model/reachabilitydata_equal_clone_test.go @@ -1,9 +1,10 @@ package model import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "reflect" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) func TestReachabilityData_Equal(t *testing.T) { @@ -45,7 +46,10 @@ func TestReachabilityData_Equal(t *testing.T) { { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}}, // Changed + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, // Changed &externalapi.DomainHash{}, &ReachabilityInterval{}, }, @@ -57,7 +61,7 @@ func TestReachabilityData_Equal(t *testing.T) { data: &ReachabilityData{ &ReachabilityTreeNode{ []*externalapi.DomainHash{}, - &externalapi.DomainHash{1}, // Changed + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), // Changed &ReachabilityInterval{}, }, FutureCoveringTreeNodeSet{}, @@ -93,7 +97,9 @@ func TestReachabilityData_Equal(t *testing.T) { &externalapi.DomainHash{}, &ReachabilityInterval{}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, // Changed + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, // Changed }, expectedResult: false, }, @@ -103,29 +109,42 @@ func TestReachabilityData_Equal(t *testing.T) { { baseData: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}, {3}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, dataToCompareTo: []dataToCompare{ { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}, {3}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: true, }, { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}, {3}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, FutureCoveringTreeNodeSet{}, // Changed @@ -135,33 +154,48 @@ func TestReachabilityData_Equal(t *testing.T) { { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}, {3}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{200, 200}, // Changed start }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: false, }, { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}, {3}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), nil, //Changed }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: false, }, { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}, {3}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 100}, // Changed end }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: false, }, @@ -169,40 +203,52 @@ func TestReachabilityData_Equal(t *testing.T) { data: &ReachabilityData{ &ReachabilityTreeNode{ []*externalapi.DomainHash{}, // Changed - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: false, }, { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, &externalapi.DomainHash{}, // Changed &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: false, }, { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{}, // Changed }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, expectedResult: false, }, { data: &ReachabilityData{ &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, FutureCoveringTreeNodeSet{}, // Changed @@ -251,35 +297,47 @@ func TestReachabilityData_Clone(t *testing.T) { }, { &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, { &ReachabilityTreeNode{ []*externalapi.DomainHash{}, - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, { &ReachabilityTreeNode{ - []*externalapi.DomainHash{{1}, {2}}, - &externalapi.DomainHash{1}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, { &ReachabilityTreeNode{ []*externalapi.DomainHash{}, - &externalapi.DomainHash{1}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), &ReachabilityInterval{100, 200}, }, - FutureCoveringTreeNodeSet{{1}, {2}}, + FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, }, } diff --git a/domain/consensus/model/virtual.go b/domain/consensus/model/virtual.go index 1162b36df..5aeab2de6 100644 --- a/domain/consensus/model/virtual.go +++ b/domain/consensus/model/virtual.go @@ -3,9 +3,9 @@ package model import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // VirtualBlockHash is a marker hash for the virtual block -var VirtualBlockHash = &externalapi.DomainHash{ +var VirtualBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 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, 0xff, -} +}) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 3248fcfa9..3e3fa7507 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -16,8 +16,8 @@ type testBlockBuilder struct { nonceCounter uint64 } -var tempBlockHash = &externalapi.DomainHash{ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} +var tempBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) // NewTestBlockBuilder creates an instance of a TestBlockBuilder func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus testapi.TestConsensus) testapi.TestBlockBuilder { diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index a3668bfde..929312b9a 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -122,37 +122,37 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 0x10000000, ParentHashes: []*externalapi.DomainHash{ - { + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, - }, - { + }), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 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, - }, + }), }, - HashMerkleRoot: externalapi.DomainHash{ + HashMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xf8, 0x55, 0x7b, 0xd0, 0xda, 0xf2, 0x06, 0x8b, 0x3b, 0xb1, 0x93, 0x5a, 0x2c, 0x52, 0x43, 0xf0, 0x02, 0xf2, 0xb1, 0x40, 0x81, 0x2c, 0x0c, 0x15, 0x8d, 0x04, 0x3d, 0xe2, 0x23, 0x54, 0x98, 0x88, - }, - AcceptedIDMerkleRoot: externalapi.DomainHash{ + }), + AcceptedIDMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, - }, - UTXOCommitment: externalapi.DomainHash{ + }), + UTXOCommitment: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, - }, + }), TimeInMilliseconds: 0x5cd18053000, Bits: 0x207fffff, Nonce: 0x1, @@ -163,7 +163,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{}, + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{}), Index: 0xffffffff, }, SignatureScript: []byte{ @@ -185,19 +185,19 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDCoinbase, Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, - PayloadHash: externalapi.DomainHash{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, - }, + }), }, { Version: 1, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, @@ -267,7 +267,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, @@ -336,7 +336,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, @@ -396,32 +396,32 @@ var exampleValidBlock = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 0x10000000, ParentHashes: []*externalapi.DomainHash{ - { + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 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, - }, - { + }), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, - }, + }), }, - HashMerkleRoot: externalapi.DomainHash{ + HashMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x33, 0x70, 0xa7, 0x40, 0x9f, 0x2d, 0x87, 0xe1, 0x26, 0xaf, 0x0f, 0x5c, 0x7e, 0xc3, 0x84, 0x5e, 0x4f, 0x68, 0x42, 0x0a, 0xbf, 0x90, 0xcd, 0xef, 0x94, 0x9b, 0xe1, 0x9a, 0xf7, 0xdd, 0xb0, 0xb5, - }, - AcceptedIDMerkleRoot: externalapi.DomainHash{ + }), + AcceptedIDMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3, 0x5d, 0x4e, 0x2c, 0xc9, 0x57, 0x88, 0x30, 0x65, 0x81, 0xb8, 0xa0, 0x68, 0x77, 0xc4, 0x02, 0x1e, 0x3c, 0xb1, 0x16, 0x8f, 0x5f, 0x6b, 0x45, 0x87, - }, - UTXOCommitment: [32]byte{}, + }), + UTXOCommitment: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}), TimeInMilliseconds: 0x17305aa654a, Bits: 0x207fffff, Nonce: 1, @@ -432,12 +432,12 @@ var exampleValidBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50, 0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33, 0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a, 0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f, - }, + }), Index: 0xffffffff, }, SignatureScript: nil, @@ -457,36 +457,36 @@ var exampleValidBlock = externalapi.DomainBlock{ LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDCoinbase, Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, - PayloadHash: externalapi.DomainHash{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, - }, + }), }, { Version: 1, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 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, }, Sequence: math.MaxUint64, }, { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, - }, + }), Index: 0xffffffff, }, Sequence: math.MaxUint64, @@ -499,7 +499,7 @@ var exampleValidBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, @@ -569,7 +569,7 @@ var exampleValidBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, @@ -638,12 +638,12 @@ var exampleValidBlock = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, - }, // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b + }), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b Index: 0, }, SignatureScript: []byte{ @@ -698,37 +698,37 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{ - { + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 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, - }, - { + }), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, - }, + }), }, - HashMerkleRoot: externalapi.DomainHash{ + HashMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xac, 0xa4, 0x21, 0xe1, 0xa6, 0xc3, 0xbe, 0x5d, 0x52, 0x66, 0xf3, 0x0b, 0x21, 0x87, 0xbc, 0xf3, 0xf3, 0x2d, 0xd1, 0x05, 0x64, 0xb5, 0x16, 0x76, 0xe4, 0x66, 0x7d, 0x51, 0x53, 0x18, 0x6d, 0xb1, - }, - AcceptedIDMerkleRoot: externalapi.DomainHash{ + }), + AcceptedIDMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, - }, - UTXOCommitment: externalapi.DomainHash{ + }), + UTXOCommitment: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, - }, + }), TimeInMilliseconds: 0x5cd16eaa000, Bits: 0x207fffff, Nonce: 1, @@ -739,12 +739,12 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50, 0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33, 0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a, 0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f, - }, + }), Index: 0xffffffff, }, SignatureScript: nil, @@ -764,36 +764,36 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDCoinbase, Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, - PayloadHash: externalapi.DomainHash{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, - }, + }), }, { Version: 1, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 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, }, Sequence: math.MaxUint64, }, { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, - }, + }), Index: 0xffffffff, }, Sequence: math.MaxUint64, @@ -806,7 +806,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, @@ -871,14 +871,14 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ LockTime: 0, SubnetworkID: externalapi.DomainSubnetworkID{11}, Payload: []byte{}, - PayloadHash: [32]byte{0xFF, 0xFF}, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0xFF, 0xFF}), }, { Version: 1, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, @@ -947,7 +947,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index ec2ad1ef1..05a3030f7 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -5,10 +5,11 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" + "math/big" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/util" - "math/big" ) type ghostdagHelper struct { @@ -122,12 +123,14 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error /* --------isMoreHash(w, selectedParent)----------------*/ func ismoreHash(parent *externalapi.DomainHash, selectedParent *externalapi.DomainHash) bool { + parentByteArray := parent.ByteArray() + selectedParentByteArray := selectedParent.ByteArray() //Check if parentHash is more then selectedParentHash - for i := len(parent) - 1; i >= 0; i-- { + for i := len(parentByteArray) - 1; i >= 0; i-- { switch { - case parent[i] < selectedParent[i]: + case parentByteArray[i] < selectedParentByteArray[i]: return false - case parent[i] > selectedParent[i]: + case parentByteArray[i] > selectedParentByteArray[i]: return true } } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index 08f64b32c..a05a6a29b 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -56,7 +56,6 @@ func TestGHOSTDAG(t *testing.T) { {ghostdag2.New, "Tal's impl"}, } testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - dagTopology := &DAGTopologyManagerImpl{ parentsMap: make(map[externalapi.DomainHash][]*externalapi.DomainHash), } @@ -95,8 +94,7 @@ func TestGHOSTDAG(t *testing.T) { } params.K = test.K - var genesisHash externalapi.DomainHash - copy(genesisHash[:], test.GenesisID) + genesisHash := *StringToDomainHash(test.GenesisID) dagTopology.parentsMap[genesisHash] = nil @@ -108,10 +106,10 @@ func TestGHOSTDAG(t *testing.T) { g := factory.function(nil, dagTopology, ghostdagDataStore, blockHeadersStore, test.K) for _, testBlockData := range test.Blocks { - blockID := StringToByte(testBlockData.ID) - dagTopology.parentsMap[*blockID] = StringToByteArray(testBlockData.Parents) + blockID := StringToDomainHash(testBlockData.ID) + dagTopology.parentsMap[*blockID] = StringToDomainHashSlice(testBlockData.Parents) blockHeadersStore.dagMap[*blockID] = &externalapi.DomainBlockHeader{ - ParentHashes: StringToByteArray(testBlockData.Parents), + ParentHashes: StringToDomainHashSlice(testBlockData.Parents), Bits: genesisHeader.Bits, } @@ -137,17 +135,17 @@ func TestGHOSTDAG(t *testing.T) { factory.implName, info.Name(), testBlockData.ID, testBlockData.Score, ghostdagData.BlueScore()) } - if !StringToByte(testBlockData.SelectedParent).Equal(ghostdagData.SelectedParent()) { - t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %v.", - factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, string(ghostdagData.SelectedParent()[:])) + if !StringToDomainHash(testBlockData.SelectedParent).Equal(ghostdagData.SelectedParent()) { + t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected selected parent %v but got %s.", + factory.implName, info.Name(), testBlockData.ID, testBlockData.SelectedParent, ghostdagData.SelectedParent()) } - if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues()) { + if !reflect.DeepEqual(StringToDomainHashSlice(testBlockData.MergeSetBlues), ghostdagData.MergeSetBlues()) { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set blues %v but got %v.", factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetBlues, hashesToStrings(ghostdagData.MergeSetBlues())) } - if !reflect.DeepEqual(StringToByteArray(testBlockData.MergeSetReds), ghostdagData.MergeSetReds()) { + if !reflect.DeepEqual(StringToDomainHashSlice(testBlockData.MergeSetReds), ghostdagData.MergeSetReds()) { t.Fatalf("\nTEST FAILED:\n Impl: %s, FileName: %s \nBlock: %s, \nError: expected merge set reds %v but got %v.", factory.implName, info.Name(), testBlockData.ID, testBlockData.MergeSetReds, hashesToStrings(ghostdagData.MergeSetReds())) } @@ -175,21 +173,21 @@ func TestGHOSTDAG(t *testing.T) { func hashesToStrings(arr []*externalapi.DomainHash) []string { var strArr = make([]string, len(arr)) for i, hash := range arr { - strArr[i] = string(hash[:]) + strArr[i] = hash.String() } return strArr } -func StringToByte(strID string) *externalapi.DomainHash { - var domainHash externalapi.DomainHash - copy(domainHash[:], strID) - return &domainHash +func StringToDomainHash(strID string) *externalapi.DomainHash { + var genesisHashArray [externalapi.DomainHashSize]byte + copy(genesisHashArray[:], strID) + return externalapi.NewDomainHashFromByteArray(&genesisHashArray) } -func StringToByteArray(stringIDArr []string) []*externalapi.DomainHash { +func StringToDomainHashSlice(stringIDArr []string) []*externalapi.DomainHash { domainHashArr := make([]*externalapi.DomainHash, len(stringIDArr)) for i, strID := range stringIDArr { - domainHashArr[i] = StringToByte(strID) + domainHashArr[i] = StringToDomainHash(strID) } return domainHashArr } diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go index 0e7f36af7..cb45f6ad1 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go @@ -2,11 +2,12 @@ package reachabilitymanager import ( "encoding/binary" - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "reflect" "strings" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) type reachabilityDataStoreMock struct { @@ -87,10 +88,10 @@ type testHelper struct { } func (th *testHelper) generateHash() *externalapi.DomainHash { - var hash externalapi.DomainHash - binary.LittleEndian.PutUint64(hash[:], th.hashCounter) + var hashArray [externalapi.DomainHashSize]byte + binary.LittleEndian.PutUint64(hashArray[:], th.hashCounter) th.hashCounter++ - return &hash + return externalapi.NewDomainHashFromByteArray(&hashArray) } func (th *testHelper) newNode() *externalapi.DomainHash { diff --git a/domain/consensus/ruleerrors/rule_error_test.go b/domain/consensus/ruleerrors/rule_error_test.go index 025f83ff9..ebeeb517b 100644 --- a/domain/consensus/ruleerrors/rule_error_test.go +++ b/domain/consensus/ruleerrors/rule_error_test.go @@ -8,7 +8,13 @@ import ( ) func TestNewErrMissingTxOut(t *testing.T) { - outer := NewErrMissingTxOut([]*externalapi.DomainOutpoint{{TransactionID: externalapi.DomainTransactionID{255, 255, 255}, Index: 5}}) + outer := NewErrMissingTxOut( + []*externalapi.DomainOutpoint{ + { + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{255, 255, 255}), + Index: 5, + }, + }) expectedOuterErr := "ErrMissingTxOut: missing the following outpoint: [(ffffff0000000000000000000000000000000000000000000000000000000000: 5)]" inner := &ErrMissingTxOut{} if !errors.As(outer, inner) { diff --git a/domain/consensus/utils/consensushashing/transaction.go b/domain/consensus/utils/consensushashing/transaction.go index 79c3ad2f6..a0c74660b 100644 --- a/domain/consensus/utils/consensushashing/transaction.go +++ b/domain/consensus/utils/consensushashing/transaction.go @@ -180,7 +180,7 @@ func writeTransactionInput(w io.Writer, ti *externalapi.DomainTransactionInput, } func writeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error { - _, err := w.Write(outpoint.TransactionID[:]) + _, err := w.Write(outpoint.TransactionID.ByteSlice()) if err != nil { return err } diff --git a/domain/consensus/utils/hashes/compare.go b/domain/consensus/utils/hashes/compare.go index 0b644086f..fdf16db18 100644 --- a/domain/consensus/utils/hashes/compare.go +++ b/domain/consensus/utils/hashes/compare.go @@ -11,12 +11,14 @@ import ( // +1 if a > b // func cmp(a, b *externalapi.DomainHash) int { + aBytes := a.ByteArray() + bBytes := b.ByteArray() // We compare the hashes backwards because Hash is stored as a little endian byte array. for i := externalapi.DomainHashSize - 1; i >= 0; i-- { switch { - case a[i] < b[i]: + case aBytes[i] < bBytes[i]: return -1 - case a[i] > b[i]: + case aBytes[i] > bBytes[i]: return 1 } } diff --git a/domain/consensus/utils/hashes/from_bytes.go b/domain/consensus/utils/hashes/from_bytes.go deleted file mode 100644 index 8b397ccb7..000000000 --- a/domain/consensus/utils/hashes/from_bytes.go +++ /dev/null @@ -1,17 +0,0 @@ -package hashes - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" -) - -// FromBytes creates a DomainHash from the given byte slice -func FromBytes(hashBytes []byte) (*externalapi.DomainHash, error) { - if len(hashBytes) != externalapi.DomainHashSize { - return nil, errors.Errorf("invalid hash size. Want: %d, got: %d", - externalapi.DomainHashSize, len(hashBytes)) - } - var domainHash externalapi.DomainHash - copy(domainHash[:], hashBytes) - return &domainHash, nil -} diff --git a/domain/consensus/utils/hashes/strings.go b/domain/consensus/utils/hashes/strings.go index 022dd94bf..91a901a6c 100644 --- a/domain/consensus/utils/hashes/strings.go +++ b/domain/consensus/utils/hashes/strings.go @@ -1,52 +1,9 @@ package hashes import ( - "encoding/hex" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" ) -// FromString creates a DomainHash from a hash string. The string should be -// the hexadecimal string of a hash, but any missing characters -// result in zero padding at the end of the Hash. -func FromString(hash string) (*externalapi.DomainHash, error) { - ret := new(externalapi.DomainHash) - err := decode(ret, hash) - if err != nil { - return nil, err - } - return ret, nil -} - -// decode decodes the hexadecimal string encoding of a Hash to a destination. -func decode(dst *externalapi.DomainHash, src string) error { - expectedSrcLength := externalapi.DomainHashSize * 2 - // Return error if hash string is too long. - if len(src) != expectedSrcLength { - return errors.Errorf("hash string length is %d, while it should be be %d", - len(src), expectedSrcLength) - } - - // Hex decoder expects the hash to be a multiple of two. When not, pad - // with a leading zero. - var srcBytes []byte - if len(src)%2 == 0 { - srcBytes = []byte(src) - } else { - srcBytes = make([]byte, 1+len(src)) - srcBytes[0] = '0' - copy(srcBytes[1:], src) - } - - // Hex decode the source bytes - _, err := hex.Decode(dst[externalapi.DomainHashSize-hex.DecodedLen(len(srcBytes)):], srcBytes) - if err != nil { - return errors.Wrap(err, "couldn't decode hash hex") - } - return nil -} - // ToStrings converts a slice of hashes into a slice of the corresponding strings func ToStrings(hashes []*externalapi.DomainHash) []string { strings := make([]string, len(hashes)) diff --git a/domain/consensus/utils/hashes/to_big.go b/domain/consensus/utils/hashes/to_big.go index 25077c69a..6eedafed6 100644 --- a/domain/consensus/utils/hashes/to_big.go +++ b/domain/consensus/utils/hashes/to_big.go @@ -1,8 +1,9 @@ package hashes import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "math/big" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) // ToBig converts a externalapi.DomainHash into a big.Int that can be used to @@ -10,7 +11,7 @@ import ( func ToBig(hash *externalapi.DomainHash) *big.Int { // A Hash is in little-endian, but the big package wants the bytes in // big-endian, so reverse them. - buf := hash.Clone() + buf := hash.ByteArray() blen := len(buf) for i := 0; i < blen/2; i++ { buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] diff --git a/domain/consensus/utils/hashes/writers.go b/domain/consensus/utils/hashes/writers.go index 7b5958dda..51b0f4cda 100644 --- a/domain/consensus/utils/hashes/writers.go +++ b/domain/consensus/utils/hashes/writers.go @@ -1,9 +1,10 @@ package hashes import ( + "hash" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" - "hash" ) // HashWriter is used to incrementally hash data without concatenating all of the data to a single buffer @@ -25,8 +26,8 @@ func (h HashWriter) InfallibleWrite(p []byte) { // Finalize returns the resulting hash func (h HashWriter) Finalize() *externalapi.DomainHash { - var sum externalapi.DomainHash + var sum [externalapi.DomainHashSize]byte // This should prevent `Sum` for allocating an output buffer, by using the DomainHash buffer. we still copy because we don't want to rely on that. copy(sum[:], h.Sum(sum[:0])) - return &sum + return externalapi.NewDomainHashFromByteArray(&sum) } diff --git a/domain/consensus/utils/merkle/merkle.go b/domain/consensus/utils/merkle/merkle.go index 9eb6686a3..c53a0ef88 100644 --- a/domain/consensus/utils/merkle/merkle.go +++ b/domain/consensus/utils/merkle/merkle.go @@ -29,8 +29,8 @@ func hashMerkleBranches(left, right *externalapi.DomainHash) *externalapi.Domain // Concatenate the left and right nodes. w := hashes.NewMerkleBranchHashWriter() - w.InfallibleWrite(left[:]) - w.InfallibleWrite(right[:]) + w.InfallibleWrite(left.ByteSlice()) + w.InfallibleWrite(right.ByteSlice()) return w.Finalize() } diff --git a/domain/consensus/utils/multiset/multiset.go b/domain/consensus/utils/multiset/multiset.go index efda18f91..8ba1862aa 100644 --- a/domain/consensus/utils/multiset/multiset.go +++ b/domain/consensus/utils/multiset/multiset.go @@ -4,7 +4,6 @@ import ( "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/pkg/errors" ) @@ -21,13 +20,9 @@ func (m multiset) Remove(data []byte) { } func (m multiset) Hash() *externalapi.DomainHash { - hash, err := hashes.FromBytes(m.ms.Finalize()[:]) - if err != nil { - panic(errors.Errorf("this should never happen unless seckp hash size is different than %d", - externalapi.DomainHashSize)) - } - - return hash + finalizedHash := m.ms.Finalize() + finalizedHashAsByteArray := (*[secp256k1.HashSize]byte)(finalizedHash) + return externalapi.NewDomainHashFromByteArray(finalizedHashAsByteArray) } func (m multiset) Serialize() []byte { diff --git a/domain/consensus/utils/serialization/common.go b/domain/consensus/utils/serialization/common.go index c66e6a5c7..9228ef9c0 100644 --- a/domain/consensus/utils/serialization/common.go +++ b/domain/consensus/utils/serialization/common.go @@ -66,14 +66,14 @@ func WriteElement(w io.Writer, element interface{}) error { return nil case externalapi.DomainHash: - _, err := w.Write(e[:]) + _, err := w.Write(e.ByteSlice()) if err != nil { return err } return nil case *externalapi.DomainHash: - _, err := w.Write(e[:]) + _, err := w.Write(e.ByteSlice()) if err != nil { return err } diff --git a/domain/consensus/utils/transactionid/compare.go b/domain/consensus/utils/transactionid/compare.go index a9d1017db..918c54206 100644 --- a/domain/consensus/utils/transactionid/compare.go +++ b/domain/consensus/utils/transactionid/compare.go @@ -2,28 +2,10 @@ package transactionid import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) -// cmp compares two transaction IDs and returns: -// -// -1 if a < b -// 0 if a == b -// +1 if a > b -// -func cmp(a, b *externalapi.DomainTransactionID) int { - // We compare the transaction IDs backwards because Hash is stored as a little endian byte array. - for i := externalapi.DomainHashSize - 1; i >= 0; i-- { - switch { - case a[i] < b[i]: - return -1 - case a[i] > b[i]: - return 1 - } - } - return 0 -} - // Less returns true iff transaction ID a is less than hash b func Less(a, b *externalapi.DomainTransactionID) bool { - return cmp(a, b) < 0 + return hashes.Less((*externalapi.DomainHash)(a), (*externalapi.DomainHash)(b)) } diff --git a/domain/consensus/utils/transactionid/from_bytes.go b/domain/consensus/utils/transactionid/from_bytes.go index d407f4b88..3a1dacd03 100644 --- a/domain/consensus/utils/transactionid/from_bytes.go +++ b/domain/consensus/utils/transactionid/from_bytes.go @@ -2,16 +2,13 @@ package transactionid import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/pkg/errors" ) // FromBytes creates a DomainTransactionID from the given byte slice func FromBytes(transactionIDBytes []byte) (*externalapi.DomainTransactionID, error) { - if len(transactionIDBytes) != externalapi.DomainHashSize { - return nil, errors.Errorf("invalid hash size. Want: %d, got: %d", - externalapi.DomainHashSize, len(transactionIDBytes)) + hash, err := externalapi.NewDomainHashFromByteSlice(transactionIDBytes) + if err != nil { + return nil, err } - var domainTransactionID externalapi.DomainTransactionID - copy(domainTransactionID[:], transactionIDBytes) - return &domainTransactionID, nil + return (*externalapi.DomainTransactionID)(hash), nil } diff --git a/domain/consensus/utils/transactionid/from_string.go b/domain/consensus/utils/transactionid/from_string.go index 07c1124ef..e5c68d1ab 100644 --- a/domain/consensus/utils/transactionid/from_string.go +++ b/domain/consensus/utils/transactionid/from_string.go @@ -2,11 +2,10 @@ package transactionid import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) // FromString creates a new DomainTransactionID from the given string func FromString(str string) (*externalapi.DomainTransactionID, error) { - hash, err := hashes.FromString(str) + hash, err := externalapi.NewDomainHashFromString(str) return (*externalapi.DomainTransactionID)(hash), err } diff --git a/domain/consensus/utils/txscript/engine_test.go b/domain/consensus/utils/txscript/engine_test.go index 5d0968d28..d79f855d4 100644 --- a/domain/consensus/utils/txscript/engine_test.go +++ b/domain/consensus/utils/txscript/engine_test.go @@ -26,7 +26,7 @@ func TestBadPC(t *testing.T) { inputs := []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc9, 0x97, 0xa5, 0xe5, 0x6e, 0x10, 0x41, 0x02, 0xfa, 0x20, 0x9c, 0x6a, @@ -95,7 +95,7 @@ func TestCheckErrorCondition(t *testing.T) { func() { inputs := []*externalapi.DomainTransactionInput{{ PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc9, 0x97, 0xa5, 0xe5, 0x6e, 0x10, 0x41, 0x02, 0xfa, 0x20, 0x9c, 0x6a, @@ -223,7 +223,7 @@ func TestDisasmPC(t *testing.T) { // tx with almost empty scripts. inputs := []*externalapi.DomainTransactionInput{{ PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc9, 0x97, 0xa5, 0xe5, 0x6e, 0x10, 0x41, 0x02, 0xfa, 0x20, 0x9c, 0x6a, @@ -287,7 +287,7 @@ func TestDisasmScript(t *testing.T) { // tx with almost empty scripts. inputs := []*externalapi.DomainTransactionInput{{ PreviousOutpoint: externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID([32]byte{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0xc9, 0x97, 0xa5, 0xe5, 0x6e, 0x10, 0x41, 0x02, 0xfa, 0x20, 0x9c, 0x6a, diff --git a/domain/consensus/utils/txscript/opcode.go b/domain/consensus/utils/txscript/opcode.go index 3bc115284..9706dca98 100644 --- a/domain/consensus/utils/txscript/opcode.go +++ b/domain/consensus/utils/txscript/opcode.go @@ -10,9 +10,10 @@ import ( "crypto/sha256" "encoding/binary" "fmt" - "golang.org/x/crypto/blake2b" "hash" + "golang.org/x/crypto/blake2b" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/go-secp256k1" @@ -2051,7 +2052,7 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error { } var valid bool - secpHash := secp256k1.Hash(*sigHash) + secpHash := secp256k1.Hash(*sigHash.ByteArray()) if vm.sigCache != nil { valid = vm.sigCache.Exists(secpHash, signature, pubKey) @@ -2245,7 +2246,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { return err } - secpHash := secp256k1.Hash(*sigHash) + secpHash := secp256k1.Hash(*sigHash.ByteArray()) var valid bool if vm.sigCache != nil { valid = vm.sigCache.Exists(secpHash, parsedSig, parsedPubKey) diff --git a/domain/consensus/utils/txscript/sign.go b/domain/consensus/utils/txscript/sign.go index e6a450916..5b8507559 100644 --- a/domain/consensus/utils/txscript/sign.go +++ b/domain/consensus/utils/txscript/sign.go @@ -22,7 +22,7 @@ func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, script []byte, if err != nil { return nil, err } - secpHash := secp256k1.Hash(*hash) + secpHash := secp256k1.Hash(*hash.ByteArray()) signature, err := key.SchnorrSign(&secpHash) if err != nil { return nil, errors.Errorf("cannot sign tx input: %s", err) diff --git a/domain/consensus/utils/utxo/serialization.go b/domain/consensus/utils/utxo/serialization.go index 19613e64b..850e0f9d7 100644 --- a/domain/consensus/utils/utxo/serialization.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -44,7 +44,7 @@ func DeserializeUTXO(utxoBytes []byte) (entry externalapi.UTXOEntry, outpoint *e } func serializeOutpoint(w io.Writer, outpoint *externalapi.DomainOutpoint) error { - _, err := w.Write(outpoint.TransactionID[:]) + _, err := w.Write(outpoint.TransactionID.ByteSlice()) if err != nil { return err } diff --git a/domain/consensus/utils/utxo/serialization_test.go b/domain/consensus/utils/utxo/serialization_test.go index 928033fbf..9ac8d9015 100644 --- a/domain/consensus/utils/utxo/serialization_test.go +++ b/domain/consensus/utils/utxo/serialization_test.go @@ -15,12 +15,12 @@ func Benchmark_serializeUTXO(b *testing.B) { } entry := NewUTXOEntry(5000000000, scriptPublicKey, false, 1432432) outpoint := &externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 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, } @@ -39,12 +39,12 @@ func Test_serializeUTXO(t *testing.T) { } entry := NewUTXOEntry(5000000000, scriptPublicKey, false, 1432432) outpoint := &externalapi.DomainOutpoint{ - TransactionID: externalapi.DomainTransactionID{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 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, } diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 162ef8d23..22362e4e4 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -27,21 +27,21 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). -var genesisHash = externalapi.DomainHash{ +var genesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x8c, 0x74, 0x62, 0xc9, 0xb6, 0xa8, 0xb2, 0x7c, 0x8d, 0x03, 0xa3, 0x7e, 0x45, 0x73, 0x31, 0x77, 0xc7, 0xe1, 0x00, 0xa8, 0xc7, 0x75, 0xe9, 0xaa, 0x31, 0x02, 0xa9, 0x82, 0x9f, 0xad, 0x34, 0xc8, -} +}) // genesisMerkleRoot is the hash of the first transaction in the genesis block // for the main network. -var genesisMerkleRoot = externalapi.DomainHash{ +var genesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x32, 0xea, 0x93, 0x9a, 0x1f, 0x00, 0x50, 0xc3, 0x97, 0x2c, 0x3d, 0xdf, 0x28, 0xb4, 0x8f, 0x1d, 0x75, 0x9f, 0xb1, 0x82, 0x99, 0x79, 0x7a, 0x48, 0xc9, 0xf6, 0x05, 0xc6, 0xae, 0x30, 0x49, 0xf7, -} +}) // genesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the main network. @@ -49,7 +49,7 @@ var genesisBlock = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: genesisMerkleRoot, + HashMerkleRoot: *genesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x1763db5c4a9, @@ -78,21 +78,21 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). -var devnetGenesisHash = externalapi.DomainHash{ +var devnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xee, 0xce, 0x68, 0x63, 0x61, 0xb4, 0xa8, 0x09, 0x5d, 0xa3, 0x91, 0x6c, 0x12, 0x20, 0x27, 0xdd, 0xf8, 0x16, 0x74, 0x8e, 0xd8, 0x7a, 0xfe, 0x2c, 0xb7, 0x98, 0xe6, 0x9d, 0x47, 0x07, 0x02, 0xc5, -} +}) // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. -var devnetGenesisMerkleRoot = externalapi.DomainHash{ +var devnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xdf, 0x52, 0x65, 0x3a, 0x5a, 0xd4, 0x07, 0x4e, 0xad, 0xac, 0xb3, 0xd7, 0xd6, 0x9a, 0xf5, 0xd3, 0x68, 0x05, 0x4d, 0xef, 0xd9, 0x41, 0x28, 0x84, 0xa9, 0x56, 0xdd, 0x68, 0x60, 0x1b, 0x8d, 0x2c, -} +}) // devnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. @@ -100,7 +100,7 @@ var devnetGenesisBlock = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: devnetGenesisMerkleRoot, + HashMerkleRoot: *devnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x1763db5c4a9, @@ -128,21 +128,21 @@ var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). -var simnetGenesisHash = externalapi.DomainHash{ +var simnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xe3, 0xa4, 0x4a, 0xe5, 0xdc, 0x3d, 0x39, 0x6a, 0xc8, 0x5b, 0x1b, 0x95, 0x30, 0x05, 0x7d, 0xb9, 0xd4, 0xfa, 0x30, 0x9a, 0x20, 0x7a, 0x42, 0x54, 0xf8, 0x10, 0x73, 0xc0, 0x15, 0x31, 0xf5, 0x1a, -} +}) // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. -var simnetGenesisMerkleRoot = externalapi.DomainHash{ +var simnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x16, 0x07, 0x15, 0x0f, 0x1b, 0xc0, 0x26, 0x27, 0x42, 0xc5, 0x84, 0x77, 0xdb, 0x58, 0xf7, 0x87, 0xa8, 0xe9, 0x9f, 0x21, 0x73, 0xa0, 0x9d, 0x96, 0x6a, 0x99, 0x55, 0x46, 0x7b, 0xb2, 0x1b, 0x99, -} +}) // simnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. @@ -150,7 +150,7 @@ var simnetGenesisBlock = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: simnetGenesisMerkleRoot, + HashMerkleRoot: *simnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x1763db5c4a9, @@ -176,21 +176,21 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). -var testnetGenesisHash = externalapi.DomainHash{ +var testnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x17, 0xb3, 0x16, 0xd3, 0x4f, 0xb5, 0x2c, 0xc1, 0x22, 0x53, 0x1a, 0xc9, 0xde, 0x79, 0xc3, 0x03, 0x53, 0xa2, 0x1a, 0x0d, 0x00, 0x40, 0x7d, 0x49, 0x66, 0x0c, 0x76, 0xf2, 0x61, 0xe4, 0x9a, 0x23, -} +}) // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for testnet. -var testnetGenesisMerkleRoot = externalapi.DomainHash{ +var testnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xd7, 0x16, 0x4a, 0x38, 0x3b, 0x8a, 0x67, 0xc2, 0x3b, 0x89, 0x12, 0x1c, 0xcb, 0x97, 0x89, 0xe1, 0x12, 0x82, 0x12, 0xc2, 0x69, 0x95, 0x7f, 0x03, 0x29, 0xd1, 0x4f, 0xdd, 0xf1, 0x93, 0xd8, 0x47, -} +}) // testnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for testnet. @@ -198,7 +198,7 @@ var testnetGenesisBlock = externalapi.DomainBlock{ Header: &externalapi.DomainBlockHeader{ Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: testnetGenesisMerkleRoot, + HashMerkleRoot: *testnetGenesisMerkleRoot, AcceptedIDMerkleRoot: externalapi.DomainHash{}, UTXOCommitment: externalapi.DomainHash{}, TimeInMilliseconds: 0x1763db5c4a9, diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index b26e47069..476582f5f 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -208,7 +208,7 @@ var MainnetParams = Params{ // DAG parameters GenesisBlock: &genesisBlock, - GenesisHash: &genesisHash, + GenesisHash: genesisHash, PowMax: mainPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, @@ -265,7 +265,7 @@ var TestnetParams = Params{ // DAG parameters GenesisBlock: &testnetGenesisBlock, - GenesisHash: &testnetGenesisHash, + GenesisHash: testnetGenesisHash, PowMax: testnetPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, @@ -328,7 +328,7 @@ var SimnetParams = Params{ // DAG parameters GenesisBlock: &simnetGenesisBlock, - GenesisHash: &simnetGenesisHash, + GenesisHash: simnetGenesisHash, PowMax: simnetPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, @@ -383,7 +383,7 @@ var DevnetParams = Params{ // DAG parameters GenesisBlock: &devnetGenesisBlock, - GenesisHash: &devnetGenesisHash, + GenesisHash: devnetGenesisHash, PowMax: devnetPowMax, BlockCoinbaseMaturity: 100, SubsidyReductionInterval: 210000, diff --git a/domain/dagconfig/params_test.go b/domain/dagconfig/params_test.go index 3790ed75c..d3f850580 100644 --- a/domain/dagconfig/params_test.go +++ b/domain/dagconfig/params_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) func TestNewHashFromStr(t *testing.T) { @@ -19,9 +18,11 @@ func TestNewHashFromStr(t *testing.T) { }{ {"banana", nil, true}, {"0000000000000000000000000000000000000000000000000000000000000000", - &externalapi.DomainHash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}), + false}, {"0101010101010101010101010101010101010101010101010101010101010101", - &externalapi.DomainHash{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, false}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}), + false}, } for _, test := range tests { @@ -46,7 +47,7 @@ func TestNewHashFromStr(t *testing.T) { // It only differs from the one available in hashes package in that it panics on an error // since it will only be called from tests. func newHashFromStr(hexStr string) *externalapi.DomainHash { - hash, err := hashes.FromString(hexStr) + hash, err := externalapi.NewDomainHashFromString(hexStr) if err != nil { panic(err) } diff --git a/go.sum b/go.sum index ef0ff054b..8df988a29 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -12,6 +13,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -32,8 +34,10 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -42,7 +46,9 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/kaspanet/go-secp256k1 v0.0.3 h1:zvrKddgUm/sZ0capLUZVcn2tKoAvQaXytZYrOzLZWx4= github.com/kaspanet/go-secp256k1 v0.0.3/go.mod h1:cFbxhxKkxqHX5eIwUGKARkph19PehipDPJejWB+H0jM= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -78,6 +84,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -101,9 +108,13 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/common.go b/infrastructure/network/netadapter/server/grpcserver/protowire/common.go index d48dee029..94112ac7d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/common.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/common.go @@ -1,11 +1,11 @@ package protowire import ( + "math" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" - "math" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/util/mstime" @@ -13,7 +13,7 @@ import ( ) func (x *Hash) toDomain() (*externalapi.DomainHash, error) { - return hashes.FromBytes(x.Bytes) + return externalapi.NewDomainHashFromByteSlice(x.Bytes) } func protoHashesToDomain(protoHashes []*Hash) ([]*externalapi.DomainHash, error) { @@ -30,7 +30,7 @@ func protoHashesToDomain(protoHashes []*Hash) ([]*externalapi.DomainHash, error) func domainHashToProto(hash *externalapi.DomainHash) *Hash { return &Hash{ - Bytes: hash[:], + Bytes: hash.ByteSlice(), } } @@ -60,7 +60,7 @@ func protoTransactionIDsToDomain(protoIDs []*TransactionId) ([]*externalapi.Doma func domainTransactionIDToProto(id *externalapi.DomainTransactionID) *TransactionId { return &TransactionId{ - Bytes: id[:], + Bytes: id.ByteSlice(), } } diff --git a/testing/integration/selected_parent_chain_test.go b/testing/integration/selected_parent_chain_test.go index 8b5812d76..9c3c9937e 100644 --- a/testing/integration/selected_parent_chain_test.go +++ b/testing/integration/selected_parent_chain_test.go @@ -1,10 +1,10 @@ package integration import ( - "encoding/hex" + "testing" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" - "testing" ) func TestVirtualSelectedParentChain(t *testing.T) { @@ -26,7 +26,7 @@ func TestVirtualSelectedParentChain(t *testing.T) { // each chain changed notifications contains only one entry // in `added` and nothing in `removed` chain1TipHash := consensushashing.BlockHash(kaspad1.config.NetParams().GenesisBlock) - chain1TipHashHex := hex.EncodeToString(chain1TipHash[:]) + chain1TipHashString := chain1TipHash.String() const blockAmountToMine = 10 for i := 0; i < blockAmountToMine; i++ { minedBlock := mineNextBlock(t, kaspad1) @@ -40,12 +40,12 @@ func TestVirtualSelectedParentChain(t *testing.T) { } minedBlockHash := consensushashing.BlockHash(minedBlock) - minedBlockHashHex := hex.EncodeToString(minedBlockHash[:]) - if minedBlockHashHex != notification.AddedChainBlocks[0].Hash { + minedBlockHashString := minedBlockHash.String() + if minedBlockHashString != notification.AddedChainBlocks[0].Hash { t.Fatalf("Unexpected block hash in AddedChainBlocks. Want: %s, got: %s", - minedBlockHashHex, notification.AddedChainBlocks[0].Hash) + minedBlockHashString, notification.AddedChainBlocks[0].Hash) } - chain1TipHashHex = minedBlockHashHex + chain1TipHashString = minedBlockHashString } // In kaspad2, mine a different chain of `blockAmountToMine` @@ -61,7 +61,7 @@ func TestVirtualSelectedParentChain(t *testing.T) { // between the two nodes chain2Tip := mineNextBlock(t, kaspad2) chain2TipHash := consensushashing.BlockHash(chain2Tip) - chain2TipHashHex := hex.EncodeToString(chain2TipHash[:]) + chain2TipHashString := chain2TipHash.String() // For the first `blockAmountToMine - 1` blocks we don't expect // the chain to change at all @@ -104,7 +104,7 @@ func TestVirtualSelectedParentChain(t *testing.T) { // Get the virtual selected parent chain from the tip of // the first chain - virtualSelectedParentChainFromChain1Tip, err := kaspad1.rpcClient.GetVirtualSelectedParentChainFromBlock(chain1TipHashHex) + virtualSelectedParentChainFromChain1Tip, err := kaspad1.rpcClient.GetVirtualSelectedParentChainFromBlock(chain1TipHashString) if err != nil { t.Fatalf("GetVirtualSelectedParentChainFromBlock failed: %s", err) } @@ -123,8 +123,8 @@ func TestVirtualSelectedParentChain(t *testing.T) { // Make sure that the last block in `added` is the tip // of chain2 lastAddedChainBlock := virtualSelectedParentChainFromChain1Tip.AddedChainBlocks[len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks)-1] - if lastAddedChainBlock.Hash != chain2TipHashHex { + if lastAddedChainBlock.Hash != chain2TipHashString { t.Fatalf("Unexpected last added chain block. Want: %s, got: %s", - chain2TipHashHex, lastAddedChainBlock.Hash) + chain2TipHashString, lastAddedChainBlock.Hash) } } From bd97075e073ea10bc3d22f710a0ccdaaff2080a8 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 24 Dec 2020 16:53:26 +0200 Subject: [PATCH 159/351] Remove the limit to the returned headers from buildMsgBlockHeaders (#1281) * Remove the limit to the returned header hashes from buildMsgBlockHeaders. * Build msgBlockHeaders in batches rather than all at once. --- .../blockrelay/handle_request_headers.go | 48 +++++++------------ .../blockrelay/handle_request_headers_test.go | 15 ------ 2 files changed, 16 insertions(+), 47 deletions(-) delete mode 100644 app/protocol/flows/blockrelay/handle_request_headers_test.go diff --git a/app/protocol/flows/blockrelay/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go index 6600461d8..a512369b3 100644 --- a/app/protocol/flows/blockrelay/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -10,7 +10,6 @@ import ( ) const ibdBatchSize = router.DefaultMaxMessages -const maxHeaders = appmessage.MaxInvPerMsg // RequestIBDBlocksContext is the interface for the context needed for the HandleRequestHeaders flow. type RequestIBDBlocksContext interface { @@ -39,26 +38,35 @@ func (flow *handleRequestBlocksFlow) start() error { return err } - msgHeaders, err := flow.buildMsgBlockHeaders(lowHash, highHash) + blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash) if err != nil { return err } - for offset := 0; offset < len(msgHeaders); offset += ibdBatchSize { + for offset := 0; offset < len(blockHashes); offset += ibdBatchSize { end := offset + ibdBatchSize - if end > len(msgHeaders) { - end = len(msgHeaders) + if end > len(blockHashes) { + end = len(blockHashes) } - blocksToSend := msgHeaders[offset:end] - err = flow.sendHeaders(blocksToSend) + blocksHashesToSend := blockHashes[offset:end] + + msgBlockHeadersToSend := make([]*appmessage.MsgBlockHeader, len(blocksHashesToSend)) + for i, blockHash := range blocksHashesToSend { + header, err := flow.Domain().Consensus().GetBlockHeader(blockHash) + if err != nil { + return err + } + msgBlockHeadersToSend[i] = appmessage.DomainBlockHeaderToBlockHeader(header) + } + err = flow.sendHeaders(msgBlockHeadersToSend) if err != nil { return nil } // Exit the loop and don't wait for the GetNextIBDBlocks message if the last batch was // less than ibdBatchSize. - if len(blocksToSend) < ibdBatchSize { + if len(blocksHashesToSend) < ibdBatchSize { break } @@ -91,30 +99,6 @@ func receiveRequestHeaders(incomingRoute *router.Route) (lowHash *externalapi.Do return msgRequestIBDBlocks.LowHash, msgRequestIBDBlocks.HighHash, nil } -func (flow *handleRequestBlocksFlow) buildMsgBlockHeaders(lowHash *externalapi.DomainHash, - highHash *externalapi.DomainHash) ([]*appmessage.MsgBlockHeader, error) { - - blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash) - if err != nil { - return nil, err - } - - if len(blockHashes) > maxHeaders { - blockHashes = blockHashes[:maxHeaders] - } - - msgBlockHeaders := make([]*appmessage.MsgBlockHeader, len(blockHashes)) - for i, blockHash := range blockHashes { - header, err := flow.Domain().Consensus().GetBlockHeader(blockHash) - if err != nil { - return nil, err - } - msgBlockHeaders[i] = appmessage.DomainBlockHeaderToBlockHeader(header) - } - - return msgBlockHeaders, nil -} - func (flow *handleRequestBlocksFlow) sendHeaders(headers []*appmessage.MsgBlockHeader) error { for _, msgBlockHeader := range headers { err := flow.outgoingRoute.Enqueue(msgBlockHeader) diff --git a/app/protocol/flows/blockrelay/handle_request_headers_test.go b/app/protocol/flows/blockrelay/handle_request_headers_test.go deleted file mode 100644 index 704cad76b..000000000 --- a/app/protocol/flows/blockrelay/handle_request_headers_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package blockrelay - -import ( - "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" - "github.com/kaspanet/kaspad/domain/dagconfig" - "testing" -) - -func TestMaxHeaders(t *testing.T) { - testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { - if params.FinalityDepth() > maxHeaders { - t.Errorf("FinalityDepth() in %s should be lower or equal to appmessage.MaxInvPerMsg", params.Name) - } - }) -} From 9d0f513e49e51adc5709d0c5b20c1abe43e1bff9 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 24 Dec 2020 17:15:44 +0200 Subject: [PATCH 160/351] Implement a simple mechanism to stop a miner from mining while kaspad is not synced (#1284) * Reintroduce isSynced into the GetBlockTemplate response. * Add a warning for when kaspad is not synced. * Rephrase a log. --- app/appmessage/rpc_get_block_template.go | 8 +- app/protocol/manager.go | 5 + app/rpc/rpchandlers/get_block_template.go | 4 +- cmd/kaspaminer/mineloop.go | 4 + .../grpcserver/protowire/messages.pb.go | 1092 +++++++++-------- .../grpcserver/protowire/messages.proto | 1 + .../protowire/rpc_get_block_template.go | 3 +- 7 files changed, 572 insertions(+), 545 deletions(-) diff --git a/app/appmessage/rpc_get_block_template.go b/app/appmessage/rpc_get_block_template.go index 30c909aa7..bd8772a25 100644 --- a/app/appmessage/rpc_get_block_template.go +++ b/app/appmessage/rpc_get_block_template.go @@ -24,6 +24,7 @@ func NewGetBlockTemplateRequestMessage(payAddress string) *GetBlockTemplateReque type GetBlockTemplateResponseMessage struct { baseMessage MsgBlock *MsgBlock + IsSynced bool Error *RPCError } @@ -34,6 +35,9 @@ func (msg *GetBlockTemplateResponseMessage) Command() MessageCommand { } // NewGetBlockTemplateResponseMessage returns a instance of the message -func NewGetBlockTemplateResponseMessage(msgBlock *MsgBlock) *GetBlockTemplateResponseMessage { - return &GetBlockTemplateResponseMessage{MsgBlock: msgBlock} +func NewGetBlockTemplateResponseMessage(msgBlock *MsgBlock, isSynced bool) *GetBlockTemplateResponseMessage { + return &GetBlockTemplateResponseMessage{ + MsgBlock: msgBlock, + IsSynced: isSynced, + } } diff --git a/app/protocol/manager.go b/app/protocol/manager.go index 7ea7d0ceb..0fe0f3a01 100644 --- a/app/protocol/manager.go +++ b/app/protocol/manager.go @@ -67,3 +67,8 @@ func (m *Manager) SetOnBlockAddedToDAGHandler(onBlockAddedToDAGHandler flowconte func (m *Manager) SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMempoolHandler flowcontext.OnTransactionAddedToMempoolHandler) { m.context.SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMempoolHandler) } + +// IsIBDRunning returns true if IBD is currently running +func (m *Manager) IsIBDRunning() bool { + return m.context.IsIBDRunning() +} diff --git a/app/rpc/rpchandlers/get_block_template.go b/app/rpc/rpchandlers/get_block_template.go index ff8429e41..f9936e8ad 100644 --- a/app/rpc/rpchandlers/get_block_template.go +++ b/app/rpc/rpchandlers/get_block_template.go @@ -33,5 +33,7 @@ func HandleGetBlockTemplate(context *rpccontext.Context, _ *router.Router, reque } msgBlock := appmessage.DomainBlockToMsgBlock(templateBlock) - return appmessage.NewGetBlockTemplateResponseMessage(msgBlock), nil + isSynced := !context.ProtocolManager.IsIBDRunning() + + return appmessage.NewGetBlockTemplateResponseMessage(msgBlock, isSynced), nil } diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index ffe554c78..f630d6bce 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -158,6 +158,10 @@ func solveLoop(newTemplateChan chan *appmessage.GetBlockTemplateResponseMessage, if stopOldTemplateSolving != nil { close(stopOldTemplateSolving) } + if !template.IsSynced && !mineWhenNotSynced { + log.Warnf("Kaspad is not synced. Skipping current block template") + continue + } stopOldTemplateSolving = make(chan struct{}) block := appmessage.MsgBlockToDomainBlock(template.MsgBlock) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 20908c403..02c80984a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -3365,6 +3365,7 @@ type GetBlockTemplateResponseMessage struct { unknownFields protoimpl.UnknownFields BlockMessage *BlockMessage `protobuf:"bytes,1,opt,name=blockMessage,proto3" json:"blockMessage,omitempty"` + IsSynced bool `protobuf:"varint,2,opt,name=isSynced,proto3" json:"isSynced,omitempty"` Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } @@ -3407,6 +3408,13 @@ func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { return nil } +func (x *GetBlockTemplateResponseMessage) GetIsSynced() bool { + if x != nil { + return x.IsSynced + } + return false +} + func (x *GetBlockTemplateResponseMessage) GetError() *RPCError { if x != nil { return x.Error @@ -8105,566 +8113,568 @@ var file_messages_proto_rawDesc = []byte{ 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8a, 0x01, + 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 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, 0x4e, 0x0a, 0x1d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, + 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, + 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, + 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, - 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, - 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, - 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 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, - 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, - 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, - 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, - 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, - 0x72, 0x79, 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, 0x21, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, - 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, 0xb5, 0x02, - 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, - 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, - 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, - 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, - 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, - 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, - 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, - 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, 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, 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, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, - 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, + 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, + 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, + 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, + 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, 0x0a, 0x1b, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, + 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, + 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, + 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, + 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, + 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, + 0x72, 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, 0x5e, 0x0a, 0x1f, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, + 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, + 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 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, 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, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, - 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, - 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, - 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, - 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, - 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, - 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, - 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, - 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, - 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, - 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, - 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, - 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, - 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, - 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, + 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, + 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, + 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, + 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, + 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, + 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, + 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, + 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 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, 0x82, 0x01, - 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 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, 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, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, + 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, - 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, + 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, 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 7158fcd02..35b623930 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -344,6 +344,7 @@ message GetBlockTemplateRequestMessage{ message GetBlockTemplateResponseMessage{ BlockMessage blockMessage = 1; + bool isSynced = 2; RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go index d45c3b3af..70127efd7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block_template.go @@ -22,12 +22,13 @@ func (x *KaspadMessage_GetBlockTemplateResponse) toAppMessage() (appmessage.Mess if err != nil { return nil, err } - return appmessage.NewGetBlockTemplateResponseMessage(msgBlock), nil + return appmessage.NewGetBlockTemplateResponseMessage(msgBlock, x.GetBlockTemplateResponse.IsSynced), nil } func (x *KaspadMessage_GetBlockTemplateResponse) fromAppMessage(message *appmessage.GetBlockTemplateResponseMessage) error { x.GetBlockTemplateResponse = &GetBlockTemplateResponseMessage{ BlockMessage: &BlockMessage{}, + IsSynced: message.IsSynced, } return x.GetBlockTemplateResponse.BlockMessage.fromAppMessage(message.MsgBlock) } From 830ddf4735129c4228ca0837609e1dd48b07ae93 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 24 Dec 2020 17:47:03 +0200 Subject: [PATCH 161/351] Fill testConsensus's dagParams (#1283) --- domain/consensus/factory.go | 1 + 1 file changed, 1 insertion(+) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 72b0bdbee..124151d45 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -375,6 +375,7 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator) tstConsensus := &testConsensus{ + dagParams: dagParams, consensus: consensusAsImplementation, testConsensusStateManager: testConsensusStateManager, testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation. From 0dea7663738f3e6fdca51e39d838bfb4a30024cf Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 24 Dec 2020 17:58:28 +0200 Subject: [PATCH 162/351] Fix the stopOldTemplateSolving channel in the miner getting closed twice (#1286) * Fix the stopOldTemplateSolving channel in the miner getting closed twice. * Remove a unused variable. --- cmd/kaspaminer/mineloop.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index f630d6bce..3d67bf67c 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -89,7 +89,7 @@ func mineNextBlock(client *minerClient, miningAddr util.Address, foundBlock chan templatesLoop(client, miningAddr, newTemplateChan, errChan, templateStopChan) }) spawn("solveLoop", func() { - solveLoop(newTemplateChan, foundBlock, mineWhenNotSynced, errChan) + solveLoop(newTemplateChan, foundBlock, mineWhenNotSynced) }) } @@ -151,18 +151,19 @@ func templatesLoop(client *minerClient, miningAddr util.Address, } func solveLoop(newTemplateChan chan *appmessage.GetBlockTemplateResponseMessage, foundBlock chan *externalapi.DomainBlock, - mineWhenNotSynced bool, errChan chan error) { + mineWhenNotSynced bool) { var stopOldTemplateSolving chan struct{} for template := range newTemplateChan { - if stopOldTemplateSolving != nil { - close(stopOldTemplateSolving) - } if !template.IsSynced && !mineWhenNotSynced { log.Warnf("Kaspad is not synced. Skipping current block template") continue } + if stopOldTemplateSolving != nil { + close(stopOldTemplateSolving) + } + stopOldTemplateSolving = make(chan struct{}) block := appmessage.MsgBlockToDomainBlock(template.MsgBlock) From 8aecf961bcb08ff3af1c72554c7dee1ccbdd4e1b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 24 Dec 2020 18:12:46 +0200 Subject: [PATCH 163/351] Red inclusion (#1275) * Accept red blocks transactions * Add comments to TestTransactionAcceptance * Fix tests * Remove fetchUTXOSetIfMissing * Remove redundant dependency * Fix comments --- app/protocol/flows/blockrelay/ibd.go | 38 +--- .../model/externalapi/transaction.go | 12 +- .../transaction_equal_clone_test.go | 120 ++++++++-- domain/consensus/model/ghostdag.go | 1 + .../calculate_past_utxo.go | 30 +-- .../resolve_block_status_test.go | 212 ++++++++++++++++++ .../ghostdagmanager/ghostdag_data.go | 10 + util/address.go | 3 +- 8 files changed, 345 insertions(+), 81 deletions(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index b697a8af4..34f994b44 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -59,8 +59,8 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain } if !isValid { - log.Infof("The suggested pruning point is incompatible to this node DAG, so stopping IBD with this" + - " peer") + log.Infof("The suggested pruning point %s is incompatible to this node DAG, so stopping IBD with this"+ + " peer", msgIBDRootHash.Hash) return nil } @@ -91,40 +91,6 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain return nil } -func (flow *handleRelayInvsFlow) fetchUTXOSetIfMissing() (bool, error) { - err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHash()) - if err != nil { - return false, err - } - - message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) - if err != nil { - return false, err - } - - msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHash) - if !ok { - return false, protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) - } - - isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) - if err != nil { - return false, err - } - - if !isValid { - return false, nil - } - - found, err := flow.fetchMissingUTXOSet(msgIBDRootHash.Hash) - if err != nil { - return false, err - } - - return found, nil -} - func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) error { log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 0dec46d5a..781da21bf 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -117,12 +117,12 @@ func (tx *DomainTransaction) Equal(other *DomainTransaction) bool { return false } - if tx.Fee != other.Fee { - return false + if tx.Fee != 0 && other.Fee != 0 && tx.Fee != other.Fee { + panic(errors.New("identical transactions should always have the same fee")) } - if tx.Mass != other.Mass { - return false + if tx.Mass != 0 && other.Mass != 0 && tx.Mass != other.Mass { + panic(errors.New("identical transactions should always have the same mass")) } if tx.ID != nil && other.ID != nil && !tx.ID.Equal(other.ID) { @@ -163,8 +163,8 @@ func (input *DomainTransactionInput) Equal(other *DomainTransactionInput) bool { return false } - if !input.UTXOEntry.Equal(other.UTXOEntry) { - return false + if input.UTXOEntry != nil && other.UTXOEntry != nil && !input.UTXOEntry.Equal(other.UTXOEntry) { + panic(errors.New("identical inputs should always have the same UTXO entry")) } return true diff --git a/domain/consensus/model/externalapi/transaction_equal_clone_test.go b/domain/consensus/model/externalapi/transaction_equal_clone_test.go index 43f3d3d8d..48065b0fa 100644 --- a/domain/consensus/model/externalapi/transaction_equal_clone_test.go +++ b/domain/consensus/model/externalapi/transaction_equal_clone_test.go @@ -25,6 +25,7 @@ type testDomainTransactionStruct struct { type transactionInputToCompare struct { tx *externalapi.DomainTransactionInput expectedResult bool + expectsPanic bool } type testDomainTransactionInputStruct struct { @@ -291,7 +292,7 @@ func initTestTransactionToCompare() []*transactionToCompare { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), }, - expectedResult: false, + expectedResult: true, }, { tx: &externalapi.DomainTransaction{ 2, //Changed @@ -317,7 +318,7 @@ func initTestTransactionToCompare() []*transactionToCompare { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), - }, //6 + }, expectedResult: false, }, { tx: &externalapi.DomainTransaction{ @@ -344,8 +345,8 @@ func initTestTransactionToCompare() []*transactionToCompare { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), - }, //7 - expectedResult: false, + }, + expectsPanic: true, }, { tx: &externalapi.DomainTransaction{ 1, @@ -463,8 +464,8 @@ func initTestTransactionToCompare() []*transactionToCompare { []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, - uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3, 4}, true, 2)}}, + uint64(0xFFFFFFF0), // Changed sequence + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), []byte{1, 2}}, {uint64(0xFFFF), []byte{1, 3}}}, @@ -485,6 +486,35 @@ func initTestTransactionToCompare() []*transactionToCompare { }, expectedResult: false, }, + { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 2, // Changed + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + []byte{0x01}, + 0, + 1, + externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), + }, + expectedResult: false, + }, } return testTx } @@ -583,7 +613,7 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, - 0, + 1, 1, externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -606,7 +636,7 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, - 0, + 1, 1, nil, }, @@ -624,11 +654,29 @@ func initTestDomainTransactionForEqual() []testDomainTransactionStruct { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), []byte{0x01}, - 0, + 1, 1, nil, }, expectedResult: true, + }, { + tx: &externalapi.DomainTransaction{ + 1, + []*externalapi.DomainTransactionInput{}, + []*externalapi.DomainTransactionOutput{}, + 1, + externalapi.DomainSubnetworkID{0x01}, + 1, + *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + []byte{0x01}, + 2, // Changed fee + 1, + nil, + }, + expectsPanic: true, }}, }, } @@ -661,7 +709,15 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, false, 2), // Changed }, - expectedResult: false, + expectsPanic: true, + }, { + tx: &externalapi.DomainTransactionInput{ + externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + nil, // Changed + }, + expectedResult: true, }, { tx: &externalapi.DomainTransactionInput{ externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, @@ -682,7 +738,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { tx: &externalapi.DomainTransactionInput{ externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, - uint64(0xFFFFFFF0), // Changed + uint64(0xFFFFFFFF), utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), }, expectedResult: false, @@ -690,7 +746,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { tx: &externalapi.DomainTransactionInput{ externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, - uint64(0xFFFFFFF0), // Changed + uint64(0xFFFFFFFF), utxo.NewUTXOEntry(2 /* Changed */, []byte{0, 1, 2, 3}, true, 2), // Changed }, expectedResult: false, @@ -698,7 +754,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { tx: &externalapi.DomainTransactionInput{ externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, - uint64(0xFFFFFFF0), // Changed + uint64(0xFFFFFFFF), utxo.NewUTXOEntry(3 /* Changed */, []byte{0, 1, 2, 3}, true, 3), // Changed }, expectedResult: false, @@ -852,7 +908,7 @@ func TestDomainTransaction_Equal(t *testing.T) { r := recover() panicked := r != nil if panicked != subTest.expectsPanic { - t.Fatalf("panicked expected to be %t but got %t", subTest.expectsPanic, panicked) + t.Fatalf("Test #%d:%d: panicked expected to be %t but got %t: %s", i, j, subTest.expectsPanic, panicked, r) } }() result1 := test.baseTx.Equal(subTest.tx) @@ -865,7 +921,7 @@ func TestDomainTransaction_Equal(t *testing.T) { r := recover() panicked := r != nil if panicked != subTest.expectsPanic { - t.Fatalf("panicked expected to be %t but got %t", subTest.expectsPanic, panicked) + t.Fatalf("Test #%d:%d: panicked expected to be %t but got %t: %s", i, j, subTest.expectsPanic, panicked, r) } }() result2 := subTest.tx.Equal(test.baseTx) @@ -896,14 +952,32 @@ func TestDomainTransactionInput_Equal(t *testing.T) { txTests := initTestDomainTransactionInputForEqual() for i, test := range txTests { for j, subTest := range test.transactionInputToCompareTo { - result1 := test.baseTx.Equal(subTest.tx) - if result1 != subTest.expectedResult { - t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) - } - result2 := subTest.tx.Equal(test.baseTx) - if result2 != subTest.expectedResult { - t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) - } + func() { + defer func() { + r := recover() + panicked := r != nil + if panicked != subTest.expectsPanic { + t.Fatalf("Test #%d:%d: panicked expected to be %t but got %t: %s", i, j, subTest.expectsPanic, panicked, r) + } + }() + result1 := test.baseTx.Equal(subTest.tx) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + }() + func() { + defer func() { + r := recover() + panicked := r != nil + if panicked != subTest.expectsPanic { + t.Fatalf("Test #%d:%d: panicked expected to be %t but got %t: %s", i, j, subTest.expectsPanic, panicked, r) + } + }() + result2 := subTest.tx.Equal(test.baseTx) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + }() } } } diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go index d4967df71..efe5be5c9 100644 --- a/domain/consensus/model/ghostdag.go +++ b/domain/consensus/model/ghostdag.go @@ -13,6 +13,7 @@ type BlockGHOSTDAGData interface { SelectedParent() *externalapi.DomainHash MergeSetBlues() []*externalapi.DomainHash MergeSetReds() []*externalapi.DomainHash + MergeSet() []*externalapi.DomainHash BluesAnticoneSizes() map[externalapi.DomainHash]KType } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 3b6c3c419..407449dc5 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -37,7 +37,7 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * } log.Tracef("Applying blue blocks to the selected parent past UTXO of block %s", blockHash) - acceptanceData, utxoDiff, err := csm.applyBlueBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData) + acceptanceData, utxoDiff, err := csm.applyMergeSetBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err } @@ -107,14 +107,14 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH return accumulatedDiff, nil } -func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainHash, +func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.DomainHash, selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) ( externalapi.AcceptanceData, model.MutableUTXODiff, error) { - log.Tracef("applyBlueBlocks start for block %s", blockHash) - defer log.Tracef("applyBlueBlocks end for block %s", blockHash) + log.Tracef("applyMergeSetBlocks start for block %s", blockHash) + defer log.Tracef("applyMergeSetBlocks end for block %s", blockHash) - blueBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSetBlues()) + mergeSetBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSet()) if err != nil { return nil, nil, err } @@ -125,26 +125,26 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH } log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime) - multiblockAcceptanceData := make(externalapi.AcceptanceData, len(blueBlocks)) + multiblockAcceptanceData := make(externalapi.AcceptanceData, len(mergeSetBlocks)) accumulatedUTXODiff := selectedParentPastUTXODiff accumulatedMass := uint64(0) - for i, blueBlock := range blueBlocks { - blueBlockHash := consensushashing.BlockHash(blueBlock) - log.Tracef("Applying blue block %s", blueBlockHash) + for i, mergeSetBlock := range mergeSetBlocks { + mergeSetBlockHash := consensushashing.BlockHash(mergeSetBlock) + log.Tracef("Applying merge set block %s", mergeSetBlockHash) blockAcceptanceData := &externalapi.BlockAcceptanceData{ - BlockHash: blueBlockHash, - TransactionAcceptanceData: make([]*externalapi.TransactionAcceptanceData, len(blueBlock.Transactions)), + BlockHash: mergeSetBlockHash, + TransactionAcceptanceData: make([]*externalapi.TransactionAcceptanceData, len(mergeSetBlock.Transactions)), } isSelectedParent := i == 0 - log.Tracef("Is blue block %s the selected parent: %t", blueBlockHash, isSelectedParent) + log.Tracef("Is merge set block %s the selected parent: %t", mergeSetBlockHash, isSelectedParent) - for j, transaction := range blueBlock.Transactions { + for j, transaction := range mergeSetBlock.Transactions { var isAccepted bool transactionID := consensushashing.TransactionID(transaction) log.Tracef("Attempting to accept transaction %s in block %s", - transactionID, blueBlockHash) + transactionID, mergeSetBlockHash) isAccepted, accumulatedMass, err = csm.maybeAcceptTransaction(transaction, blockHash, isSelectedParent, accumulatedUTXODiff, accumulatedMass, selectedParentMedianTime, ghostdagData.BlueScore()) @@ -152,7 +152,7 @@ func (csm *consensusStateManager) applyBlueBlocks(blockHash *externalapi.DomainH return nil, nil, err } log.Tracef("Transaction %s in block %s isAccepted: %t, fee: %d", - transactionID, blueBlockHash, isAccepted, transaction.Fee) + transactionID, mergeSetBlockHash, isAccepted, transaction.Fee) blockAcceptanceData.TransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{ Transaction: transaction, diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 77f038e27..9b5511fd5 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -2,6 +2,9 @@ package consensusstatemanager_test import ( "errors" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "testing" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -151,6 +154,215 @@ func TestDoubleSpends(t *testing.T) { }) } +// TestTransactionAcceptance checks that blue blocks transactions are favoured above +// red blocks transactions, and that the block reward is paid only for blue blocks. +func TestTransactionAcceptance(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.BlockCoinbaseMaturity = 0 + + factory := consensus.NewFactory() + testConsensus, teardown, err := factory.NewTestConsensus(params, "TestTransactionAcceptance") + if err != nil { + t.Fatalf("Error setting up testConsensus: %+v", err) + } + defer teardown(false) + + fundingBlock1Hash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating fundingBlock1: %+v", err) + } + + fundingBlock2Hash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{fundingBlock1Hash}, nil, nil) + if err != nil { + t.Fatalf("Error creating fundingBlock2: %+v", err) + } + + // Generate fundingBlock3 to pay for fundingBlock2 + fundingBlock3Hash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{fundingBlock2Hash}, nil, nil) + if err != nil { + t.Fatalf("Error creating fundingBlock3: %+v", err) + } + + // Add a chain of K blocks above fundingBlock3 so we'll + // be able to mine a red block on top of it. + tipHash := fundingBlock3Hash + for i := model.KType(0); i < params.K; i++ { + var err error + tipHash, _, err = testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating fundingBlock1: %+v", err) + } + } + + fundingBlock2, err := testConsensus.GetBlock(fundingBlock2Hash) + if err != nil { + t.Fatalf("Error getting fundingBlock: %+v", err) + } + + fundingTransaction1 := fundingBlock2.Transactions[transactionhelper.CoinbaseTransactionIndex] + + fundingBlock3, err := testConsensus.GetBlock(fundingBlock3Hash) + if err != nil { + t.Fatalf("Error getting fundingBlock: %+v", err) + } + + fundingTransaction2 := fundingBlock3.Transactions[transactionhelper.CoinbaseTransactionIndex] + + spendingTransaction1, err := testutils.CreateTransaction(fundingTransaction1) + if err != nil { + t.Fatalf("Error creating spendingTransaction1: %+v", err) + } + + spendingTransaction2, err := testutils.CreateTransaction(fundingTransaction2) + if err != nil { + t.Fatalf("Error creating spendingTransaction1: %+v", err) + } + + redHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{fundingBlock3Hash}, nil, + []*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2}) + if err != nil { + t.Fatalf("Error creating redBlock: %+v", err) + } + + blueScriptPublicKey := []byte{1} + blueHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, &externalapi.DomainCoinbaseData{ + ScriptPublicKey: blueScriptPublicKey, + ExtraData: nil, + }, + []*externalapi.DomainTransaction{spendingTransaction1}) + if err != nil { + t.Fatalf("Error creating blue: %+v", err) + } + + // Mining two blocks so tipHash will definitely be the selected tip. + tipHash, _, err = testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("Error creating tip: %+v", err) + } + + finalTipSelectedParentScriptPublicKey := []byte{3} + finalTipSelectedParentHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, + &externalapi.DomainCoinbaseData{ + ScriptPublicKey: finalTipSelectedParentScriptPublicKey, + ExtraData: nil, + }, nil) + if err != nil { + t.Fatalf("Error creating tip: %+v", err) + } + + finalTipHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{finalTipSelectedParentHash, redHash, blueHash}, nil, + nil) + if err != nil { + t.Fatalf("Error creating finalTip: %+v", err) + } + + acceptanceData, err := testConsensus.AcceptanceDataStore().Get(testConsensus.DatabaseContext(), finalTipHash) + if err != nil { + t.Fatalf("Error getting acceptance data: %+v", err) + } + + finalTipSelectedParent, err := testConsensus.GetBlock(finalTipSelectedParentHash) + if err != nil { + t.Fatalf("Error getting finalTipSelectedParent: %+v", err) + } + + blue, err := testConsensus.GetBlock(blueHash) + if err != nil { + t.Fatalf("Error getting blue: %+v", err) + } + + red, err := testConsensus.GetBlock(redHash) + if err != nil { + t.Fatalf("Error getting red: %+v", err) + } + + // We expect spendingTransaction1 to be accepted by the blue block and not by the red one, because + // blue blocks in the merge set should always be ordered before red blocks in the merge set. + // We also expect spendingTransaction2 to be accepted by the red because nothing conflicts it. + expectedAcceptanceData := externalapi.AcceptanceData{ + { + BlockHash: finalTipSelectedParentHash, + TransactionAcceptanceData: []*externalapi.TransactionAcceptanceData{ + { + Transaction: finalTipSelectedParent.Transactions[0], + Fee: 0, + IsAccepted: true, + }, + }, + }, + { + BlockHash: blueHash, + TransactionAcceptanceData: []*externalapi.TransactionAcceptanceData{ + { + Transaction: blue.Transactions[0], + Fee: 0, + IsAccepted: false, + }, + { + Transaction: spendingTransaction1, + Fee: 1, + IsAccepted: true, + }, + }, + }, + { + BlockHash: redHash, + TransactionAcceptanceData: []*externalapi.TransactionAcceptanceData{ + { + Transaction: red.Transactions[0], + Fee: 0, + IsAccepted: false, + }, + { + Transaction: spendingTransaction1, + Fee: 0, + IsAccepted: false, + }, + { + Transaction: spendingTransaction2, + Fee: 1, + IsAccepted: true, + }, + }, + }, + } + + if !acceptanceData.Equal(expectedAcceptanceData) { + t.Fatalf("The acceptance data is not the expected acceptance data") + } + + finalTip, err := testConsensus.GetBlock(finalTipHash) + if err != nil { + t.Fatalf("Error getting finalTip: %+v", err) + } + + // We expect the coinbase transaction to pay reward for the selected parent, the + // blue block, and not for the red block. + expectedCoinbase := &externalapi.DomainTransaction{ + Version: constants.TransactionVersion, + Inputs: nil, + Outputs: []*externalapi.DomainTransactionOutput{ + { + Value: 50 * constants.SompiPerKaspa, + ScriptPublicKey: finalTipSelectedParentScriptPublicKey, + }, + { + Value: 50*constants.SompiPerKaspa + 1, // testutils.CreateTransaction pays a fee of 1 sompi + ScriptPublicKey: blueScriptPublicKey, + }, + }, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDCoinbase, + Gas: 0, + PayloadHash: finalTip.Transactions[0].PayloadHash, + Payload: finalTip.Transactions[0].Payload, + } + if !finalTip.Transactions[transactionhelper.CoinbaseTransactionIndex].Equal(expectedCoinbase) { + t.Fatalf("Unexpected coinbase transaction") + } + }) +} + func TestResolveBlockStatusSanity(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { consensus, teardown, err := consensus.NewFactory().NewTestConsensus(params, "TestResolveBlockStatusSanity") diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go index a488542c0..49fc39090 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go @@ -57,3 +57,13 @@ func (bgd *blockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash { func (bgd *blockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]model.KType { return bgd.bluesAnticoneSizes } + +func (bgd *blockGHOSTDAGData) MergeSet() []*externalapi.DomainHash { + mergeSet := make([]*externalapi.DomainHash, len(bgd.mergeSetBlues)+len(bgd.mergeSetReds)) + copy(mergeSet, bgd.mergeSetBlues) + if len(bgd.mergeSetReds) > 0 { + copy(mergeSet[len(bgd.mergeSetBlues):], bgd.mergeSetReds) + } + + return mergeSet +} diff --git a/util/address.go b/util/address.go index 9ac4a0a37..5162cfe1c 100644 --- a/util/address.go +++ b/util/address.go @@ -135,7 +135,8 @@ func DecodeAddress(addr string, expectedPrefix Bech32Prefix) (Address, error) { return nil, errors.Errorf("decoded address's prefix could not be parsed: %s", err) } if expectedPrefix != Bech32PrefixUnknown && expectedPrefix != prefix { - return nil, errors.Errorf("decoded address is of wrong network: %s", err) + return nil, errors.Errorf("decoded address is of wrong network. Expected %s but got %s", expectedPrefix, + prefix) } // Switch on decoded length to determine the type. From a231ec72148de4cf660d1664f5987b635627a0ed Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 27 Dec 2020 16:37:09 +0200 Subject: [PATCH 164/351] Make only one transaction in validateAndInsertBlock (#1292) --- .../processes/blockprocessor/validateandinsertblock.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 049388553..0c57e4173 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -66,13 +66,6 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, return nil, err } - // Block validations passed, save whatever DAG data was - // collected so far - err = bp.commitAllChanges() - if err != nil { - return nil, err - } - var oldHeadersSelectedTip *externalapi.DomainHash isGenesis := blockHash.Equal(bp.genesisHash) if !isGenesis { From 12f1c3dfab8581e1101d0839ac013173a869c042 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 27 Dec 2020 17:03:21 +0200 Subject: [PATCH 165/351] Fix a crash in GetMissingBlockBodyHashes (#1289) * Remove the limit on the amount of hashes returned from antiPastHashesBetween. * Guard against requests with a non-existing block hash. * Move missing-block-hash guards to consensus.go. * Ban a peer that doesn't send us all the requested headers during IBD. * Extract blockHeap.ToSlice. * Re-request headers in requestHeaders if we didn't receive the highHash. --- .../blockrelay/handle_request_headers.go | 7 +- app/protocol/flows/blockrelay/ibd.go | 29 ++++++-- domain/consensus/consensus.go | 73 ++++++++++++++++++- domain/consensus/model/block_heap.go | 1 + .../consensus/model/externalapi/consensus.go | 4 +- .../interface_processes_pruningmanager.go | 2 +- .../model/interface_processes_syncmanager.go | 2 +- .../dagtraversalmanager/block_heap.go | 10 +++ .../pruningmanager/pruningmanager.go | 8 +- .../processes/syncmanager/antipast.go | 58 +++++++-------- .../processes/syncmanager/syncmanager.go | 6 +- 11 files changed, 145 insertions(+), 55 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go index a512369b3..175f098e0 100644 --- a/app/protocol/flows/blockrelay/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -38,7 +38,12 @@ func (flow *handleRequestBlocksFlow) start() error { return err } - blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash) + // GetHashesBetween is a relatively heavy operation so we limit it. + // We expect that if the other peer did not receive all the headers + // they requested, they'd re-request a block locator and re-request + // headers with a higher lowHash + const maxBlueScoreDifference = 1 << 12 + blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference) if err != nil { return err } diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 34f994b44..71d8c00ae 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -92,14 +92,29 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain } func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) error { - log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) - highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) - if err != nil { - return err - } - log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) + highHashReceived := false + for !highHashReceived { + log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) + highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) + if err != nil { + return err + } + log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) - return flow.downloadHeaders(highestSharedBlockHash, highHash) + err = flow.downloadHeaders(highestSharedBlockHash, highHash) + if err != nil { + return err + } + + // We're finished once highHash has been inserted into the DAG + blockInfo, err := flow.Domain().Consensus().GetBlockInfo(highHash) + if err != nil { + return err + } + highHashReceived = blockInfo.Exists + log.Debugf("Headers downloaded from peer %s. Are further headers required: %t", flow.peer, !highHashReceived) + } + return nil } func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(highHash *externalapi.DomainHash) ( diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 644594313..9bd22421b 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -95,6 +95,11 @@ func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.Do s.lock.Lock() defer s.lock.Unlock() + err := s.validateBlockHashExists(blockHash) + if err != nil { + return nil, err + } + return s.blockStore.Block(s.databaseContext, blockHash) } @@ -102,6 +107,11 @@ func (s *consensus) GetBlockHeader(blockHash *externalapi.DomainHash) (*external s.lock.Lock() defer s.lock.Unlock() + err := s.validateBlockHashExists(blockHash) + if err != nil { + return nil, err + } + return s.blockHeaderStore.BlockHeader(s.databaseContext, blockHash) } @@ -145,20 +155,41 @@ func (s *consensus) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (e s.lock.Lock() defer s.lock.Unlock() + err := s.validateBlockHashExists(blockHash) + if err != nil { + return nil, err + } + return s.acceptanceDataStore.Get(s.databaseContext, blockHash) } -func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { +func (s *consensus) GetHashesBetween(lowHash, highHash *externalapi.DomainHash, + maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { + s.lock.Lock() defer s.lock.Unlock() - return s.syncManager.GetHashesBetween(lowHash, highHash) + err := s.validateBlockHashExists(lowHash) + if err != nil { + return nil, err + } + err = s.validateBlockHashExists(highHash) + if err != nil { + return nil, err + } + + return s.syncManager.GetHashesBetween(lowHash, highHash, maxBlueScoreDifference) } func (s *consensus) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { s.lock.Lock() defer s.lock.Unlock() + err := s.validateBlockHashExists(highHash) + if err != nil { + return nil, err + } + return s.syncManager.GetMissingBlockBodyHashes(highHash) } @@ -249,6 +280,15 @@ func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash s.lock.Lock() defer s.lock.Unlock() + err := s.validateBlockHashExists(lowHash) + if err != nil { + return nil, err + } + err = s.validateBlockHashExists(highHash) + if err != nil { + return nil, err + } + return s.syncManager.CreateBlockLocator(lowHash, highHash, limit) } @@ -256,6 +296,10 @@ func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.Bloc s.lock.Lock() defer s.lock.Unlock() + if len(blockLocator) == 0 { + return nil, nil, errors.Errorf("empty block locator") + } + return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator) } @@ -266,13 +310,34 @@ func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { return s.syncManager.GetSyncInfo() } -func (s *consensus) IsValidPruningPoint(block *externalapi.DomainHash) (bool, error) { - return s.pruningManager.IsValidPruningPoint(block) +func (s *consensus) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) { + err := s.validateBlockHashExists(blockHash) + if err != nil { + return false, err + } + + return s.pruningManager.IsValidPruningPoint(blockHash) } func (s *consensus) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { s.lock.Lock() defer s.lock.Unlock() + err := s.validateBlockHashExists(blockHash) + if err != nil { + return nil, err + } + return s.consensusStateManager.GetVirtualSelectedParentChainFromBlock(blockHash) } + +func (s *consensus) validateBlockHashExists(blockHash *externalapi.DomainHash) error { + exists, err := s.blockStatusStore.Exists(s.databaseContext, blockHash) + if err != nil { + return err + } + if !exists { + return errors.Errorf("block %s does not exists", blockHash) + } + return nil +} diff --git a/domain/consensus/model/block_heap.go b/domain/consensus/model/block_heap.go index a59e06193..46643d820 100644 --- a/domain/consensus/model/block_heap.go +++ b/domain/consensus/model/block_heap.go @@ -7,4 +7,5 @@ type BlockHeap interface { Push(blockHash *externalapi.DomainHash) error Pop() *externalapi.DomainHash Len() int + ToSlice() []*externalapi.DomainHash } diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 0806fb2dd..7df5b99e7 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -11,7 +11,7 @@ type Consensus interface { GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error) GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error) - GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error) + GetHashesBetween(lowHash, highHash *DomainHash, maxBlueScoreDifference uint64) ([]*DomainHash, error) GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error) PruningPoint() (*DomainHash, error) @@ -22,6 +22,6 @@ type Consensus interface { GetSyncInfo() (*SyncInfo, error) Tips() ([]*DomainHash, error) GetVirtualInfo() (*VirtualInfo, error) - IsValidPruningPoint(block *DomainHash) (bool, error) + IsValidPruningPoint(blockHash *DomainHash) (bool, error) GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) } diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index 72c4d76dc..de060f3fa 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -5,5 +5,5 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // PruningManager resolves and manages the current pruning point type PruningManager interface { UpdatePruningPointByVirtual() error - IsValidPruningPoint(block *externalapi.DomainHash) (bool, error) + IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) } diff --git a/domain/consensus/model/interface_processes_syncmanager.go b/domain/consensus/model/interface_processes_syncmanager.go index 165659c53..925497066 100644 --- a/domain/consensus/model/interface_processes_syncmanager.go +++ b/domain/consensus/model/interface_processes_syncmanager.go @@ -4,7 +4,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // SyncManager exposes functions to support sync between kaspad nodes type SyncManager interface { - GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) + GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) 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) diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go index def48f16e..a305e97f2 100644 --- a/domain/consensus/processes/dagtraversalmanager/block_heap.go +++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go @@ -114,6 +114,16 @@ func (bh *blockHeap) Len() int { return bh.impl.Len() } +// ToSlice copies this heap to a slice +func (bh *blockHeap) ToSlice() []*externalapi.DomainHash { + length := bh.Len() + hashes := make([]*externalapi.DomainHash, length) + for i := 0; i < length; i++ { + hashes[i] = bh.Pop() + } + return hashes +} + // sizedUpBlockHeap represents a mutable heap of Blocks, sorted by their blueWork+hash, capped by a specific size. type sizedUpBlockHeap struct { impl upHeap diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 7cf73adda..5c77d961d 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -292,8 +292,8 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread return false, nil } -func (pm *pruningManager) IsValidPruningPoint(block *externalapi.DomainHash) (bool, error) { - if *pm.genesisHash == *block { +func (pm *pruningManager) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) { + if *pm.genesisHash == *blockHash { return true, nil } @@ -308,7 +308,7 @@ func (pm *pruningManager) IsValidPruningPoint(block *externalapi.DomainHash) (bo return false, err } - isInSelectedParentChainOfHeadersSelectedTip, err := pm.dagTopologyManager.IsInSelectedParentChainOf(block, + isInSelectedParentChainOfHeadersSelectedTip, err := pm.dagTopologyManager.IsInSelectedParentChainOf(blockHash, headersSelectedTip) if err != nil { return false, err @@ -318,7 +318,7 @@ func (pm *pruningManager) IsValidPruningPoint(block *externalapi.DomainHash) (bo return false, nil } - ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, block) + ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, blockHash) if err != nil { return false, err } diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index feb33c4d3..da67ff663 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -6,12 +6,12 @@ import ( "github.com/pkg/errors" ) -const maxHashesInAntiPastHashesBetween = 1 << 17 - // antiPastHashesBetween returns the hashes of the blocks between the // lowHash's antiPast and highHash's antiPast, or up to -// maxHashesInAntiPastHashesBetween. -func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { +// `maxBlueScoreDifference`, if non-zero. +func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.DomainHash, + maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { + lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) if err != nil { return nil, err @@ -25,21 +25,23 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma lowBlockGHOSTDAGData.BlueScore(), highBlockGHOSTDAGData.BlueScore()) } - // In order to get no more then maxHashesInAntiPastHashesBetween - // 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. - // That stop point becomes the new highHash. - // Using blueScore as an approximation is considered to be - // fairly accurate because we presume that most DAG blocks are - // blue. - 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 + if maxBlueScoreDifference != 0 { + // In order to get no more then maxBlueScoreDifference + // 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 <= maxBlueScoreDifference. + // That stop point becomes the new highHash. + // Using blueScore as an approximation is considered to be + // fairly accurate because we presume that most DAG blocks are + // blue. + for highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore()+1 > maxBlueScoreDifference { + highHash = highBlockGHOSTDAGData.SelectedParent() + var err error + highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHash) + if err != nil { + return nil, err + } } } @@ -47,7 +49,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma // NOT in the lowHash's past (excluding itself) into an up-heap // (a heap sorted by blueScore from lowest to greatest). visited := hashset.New() - candidateHashes := sm.dagTraversalManager.NewUpHeap() + hashesUpHeap := sm.dagTraversalManager.NewUpHeap() queue := sm.dagTraversalManager.NewDownHeap() err = queue.Push(highHash) if err != nil { @@ -72,7 +74,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma if isCurrentAncestorOfLowHash { continue } - err = candidateHashes.Push(current) + err = hashesUpHeap.Push(current) if err != nil { return nil, err } @@ -88,17 +90,7 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma } } - // Pop candidateHashes into a slice. Since candidateHashes is - // an up-heap, it's guaranteed to be ordered from low to high - hashesLength := maxHashesInAntiPastHashesBetween - if candidateHashes.Len() < hashesLength { - hashesLength = candidateHashes.Len() - } - hashes := make([]*externalapi.DomainHash, hashesLength) - for i := 0; i < hashesLength; i++ { - hashes[i] = candidateHashes.Pop() - } - return hashes, nil + return hashesUpHeap.ToSlice(), nil } func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { @@ -134,7 +126,7 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) lowHash, highHash) } - hashesBetween, err := sm.antiPastHashesBetween(lowHash, highHash) + hashesBetween, err := sm.antiPastHashesBetween(lowHash, highHash, 0) if err != nil { return nil, err } diff --git a/domain/consensus/processes/syncmanager/syncmanager.go b/domain/consensus/processes/syncmanager/syncmanager.go index 1cc7264ed..a81faa58b 100644 --- a/domain/consensus/processes/syncmanager/syncmanager.go +++ b/domain/consensus/processes/syncmanager/syncmanager.go @@ -54,11 +54,13 @@ func New( } } -func (sm *syncManager) GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { +func (sm *syncManager) GetHashesBetween(lowHash, highHash *externalapi.DomainHash, + maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "GetHashesBetween") defer onEnd() - return sm.antiPastHashesBetween(lowHash, highHash) + return sm.antiPastHashesBetween(lowHash, highHash, maxBlueScoreDifference) } func (sm *syncManager) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { From 50e74bf412d8d8eb6a6db05d3874ba35f9d9131a Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 27 Dec 2020 17:57:43 +0200 Subject: [PATCH 166/351] Add BlueScore to BlockVerboseData. (#1294) --- .../grpcserver/protowire/messages.pb.go | 657 +++++++++--------- .../grpcserver/protowire/messages.proto | 1 + .../grpcserver/protowire/rpc_get_block.go | 2 + 3 files changed, 336 insertions(+), 324 deletions(-) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 02c80984a..8b106454f 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -4841,6 +4841,7 @@ type BlockVerboseData struct { ParentHashes []string `protobuf:"bytes,12,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` SelectedParentHash string `protobuf:"bytes,13,opt,name=selectedParentHash,proto3" json:"selectedParentHash,omitempty"` TransactionIDs []string `protobuf:"bytes,14,rep,name=transactionIDs,proto3" json:"transactionIDs,omitempty"` + BlueScore uint64 `protobuf:"varint,15,opt,name=blueScore,proto3" json:"blueScore,omitempty"` } func (x *BlockVerboseData) Reset() { @@ -4973,6 +4974,13 @@ func (x *BlockVerboseData) GetTransactionIDs() []string { return nil } +func (x *BlockVerboseData) GetBlueScore() uint64 { + if x != nil { + return x.BlueScore + } + return 0 +} + type TransactionVerboseData struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -8305,7 +8313,7 @@ var file_messages_proto_rawDesc = []byte{ 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, + 0x22, 0xb7, 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, @@ -8338,343 +8346,344 @@ var file_messages_proto_rawDesc = []byte{ 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, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x1c, 0x0a, 0x09, + 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x8f, 0x04, 0x0a, 0x16, 0x54, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 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, 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, + 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, 0x54, + 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 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, - 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, + 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, 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, - 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, + 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, 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, 0x22, + 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, + 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, + 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, + 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, + 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, + 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, + 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, + 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, + 0x69, 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, + 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, + 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, - 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, - 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, - 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, - 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, - 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, - 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, - 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, - 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, - 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, - 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, - 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, - 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, - 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x32, 0x50, - 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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, 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, + 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 35b623930..6c80fc2f2 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -494,6 +494,7 @@ message BlockVerboseData{ repeated string parentHashes = 12; string selectedParentHash = 13; repeated string transactionIDs = 14; + uint64 blueScore = 15; } message TransactionVerboseData{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go index 5eda5e824..7b22c32bc 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go @@ -85,6 +85,7 @@ func (x *BlockVerboseData) toAppMessage() (*appmessage.BlockVerboseData, error) Difficulty: x.Difficulty, ParentHashes: x.ParentHashes, SelectedParentHash: x.SelectedParentHash, + BlueScore: x.BlueScore, }, nil } @@ -113,6 +114,7 @@ func (x *BlockVerboseData) fromAppMessage(message *appmessage.BlockVerboseData) Difficulty: message.Difficulty, ParentHashes: message.ParentHashes, SelectedParentHash: message.SelectedParentHash, + BlueScore: message.BlueScore, } return nil } From cfe013eca700a64f2c9e041321890b2b5027a898 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 27 Dec 2020 18:23:51 +0200 Subject: [PATCH 167/351] Add IsHeaderOnly field to BlockVerboseData (#1295) --- app/appmessage/rpc_get_block.go | 1 + app/rpc/rpccontext/verbosedata.go | 45 +- app/rpc/rpchandlers/get_block.go | 4 +- .../grpcserver/protowire/messages.pb.go | 673 +++++++++--------- .../grpcserver/protowire/messages.proto | 3 +- .../grpcserver/protowire/rpc_get_block.go | 2 + 6 files changed, 375 insertions(+), 353 deletions(-) diff --git a/app/appmessage/rpc_get_block.go b/app/appmessage/rpc_get_block.go index 91403402b..be5269607 100644 --- a/app/appmessage/rpc_get_block.go +++ b/app/appmessage/rpc_get_block.go @@ -59,6 +59,7 @@ type BlockVerboseData struct { ParentHashes []string SelectedParentHash string BlueScore uint64 + IsHeaderOnly bool } // TransactionVerboseData holds verbose data about a transaction diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 1828dbf61..b18738d7f 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -24,9 +24,8 @@ import ( // BuildBlockVerboseData builds a BlockVerboseData from the given block. // This method must be called with the DAG lock held for reads -func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { - hash := consensushashing.BlockHash(block) - blockHeader := block.Header +func (ctx *Context) BuildBlockVerboseData(blockHeader *externalapi.DomainBlockHeader, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { + hash := consensushashing.HeaderHash(blockHeader) blockInfo, err := ctx.Domain.Consensus().GetBlockInfo(hash) if err != nil { @@ -45,25 +44,33 @@ func (ctx *Context) BuildBlockVerboseData(block *externalapi.DomainBlock, includ Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits, ctx.Config.ActiveNetParams), BlueScore: blockInfo.BlueScore, + IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly, } - txIDs := make([]string, len(block.Transactions)) - for i, tx := range block.Transactions { - txIDs[i] = consensushashing.TransactionID(tx).String() - } - result.TxIDs = txIDs - - if includeTransactionVerboseData { - transactionVerboseData := make([]*appmessage.TransactionVerboseData, len(block.Transactions)) - for i, tx := range block.Transactions { - txID := consensushashing.TransactionID(tx).String() - data, err := ctx.BuildTransactionVerboseData(tx, txID, blockHeader, hash.String()) - if err != nil { - return nil, err - } - transactionVerboseData[i] = data + if blockInfo.BlockStatus != externalapi.StatusHeaderOnly { + block, err := ctx.Domain.Consensus().GetBlock(hash) + if err != nil { + return nil, err + } + + txIDs := make([]string, len(block.Transactions)) + for i, tx := range block.Transactions { + txIDs[i] = consensushashing.TransactionID(tx).String() + } + result.TxIDs = txIDs + + if includeTransactionVerboseData { + transactionVerboseData := make([]*appmessage.TransactionVerboseData, len(block.Transactions)) + for i, tx := range block.Transactions { + txID := consensushashing.TransactionID(tx).String() + data, err := ctx.BuildTransactionVerboseData(tx, txID, blockHeader, hash.String()) + if err != nil { + return nil, err + } + transactionVerboseData[i] = data + } + result.TransactionVerboseData = transactionVerboseData } - result.TransactionVerboseData = transactionVerboseData } return result, nil diff --git a/app/rpc/rpchandlers/get_block.go b/app/rpc/rpchandlers/get_block.go index c2de8b106..1d358deea 100644 --- a/app/rpc/rpchandlers/get_block.go +++ b/app/rpc/rpchandlers/get_block.go @@ -19,7 +19,7 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme return errorMessage, nil } - block, err := context.Domain.Consensus().GetBlock(hash) + header, err := context.Domain.Consensus().GetBlockHeader(hash) if err != nil { errorMessage := &appmessage.GetBlockResponseMessage{} errorMessage.Error = appmessage.RPCErrorf("Block %s not found", hash) @@ -28,7 +28,7 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme response := appmessage.NewGetBlockResponseMessage() - blockVerboseData, err := context.BuildBlockVerboseData(block, getBlockRequest.IncludeTransactionVerboseData) + blockVerboseData, err := context.BuildBlockVerboseData(header, getBlockRequest.IncludeTransactionVerboseData) if err != nil { return nil, err } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 8b106454f..99a7a979b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -4841,7 +4841,8 @@ type BlockVerboseData struct { ParentHashes []string `protobuf:"bytes,12,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` SelectedParentHash string `protobuf:"bytes,13,opt,name=selectedParentHash,proto3" json:"selectedParentHash,omitempty"` TransactionIDs []string `protobuf:"bytes,14,rep,name=transactionIDs,proto3" json:"transactionIDs,omitempty"` - BlueScore uint64 `protobuf:"varint,15,opt,name=blueScore,proto3" json:"blueScore,omitempty"` + IsHeaderOnly bool `protobuf:"varint,15,opt,name=isHeaderOnly,proto3" json:"isHeaderOnly,omitempty"` + BlueScore uint64 `protobuf:"varint,16,opt,name=blueScore,proto3" json:"blueScore,omitempty"` } func (x *BlockVerboseData) Reset() { @@ -4974,6 +4975,13 @@ func (x *BlockVerboseData) GetTransactionIDs() []string { return nil } +func (x *BlockVerboseData) GetIsHeaderOnly() bool { + if x != nil { + return x.IsHeaderOnly + } + return false +} + func (x *BlockVerboseData) GetBlueScore() uint64 { if x != nil { return x.BlueScore @@ -8313,7 +8321,7 @@ var file_messages_proto_rawDesc = []byte{ 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, 0xb7, 0x04, 0x0a, 0x10, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, + 0x22, 0xdb, 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, @@ -8346,344 +8354,347 @@ var file_messages_proto_rawDesc = []byte{ 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, 0x12, 0x1c, 0x0a, 0x09, - 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x22, 0x0a, 0x0c, + 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, + 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 0x12, 0x61, 0x0a, 0x19, 0x74, 0x72, 0x61, + 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, 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, + 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, 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, 0x54, - 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 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, 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, + 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 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, + 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, 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, + 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, 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, 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, 0x22, - 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, - 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, - 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, - 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, - 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, - 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, - 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, - 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, 0x63, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, - 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, - 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, - 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, - 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, - 0x69, 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, - 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, + 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, + 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, + 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, + 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, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, + 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, + 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, + 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, + 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, + 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, + 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, + 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, - 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 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, 0x82, 0x01, 0x0a, 0x38, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 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, + 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 6c80fc2f2..3f696e14b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -494,7 +494,8 @@ message BlockVerboseData{ repeated string parentHashes = 12; string selectedParentHash = 13; repeated string transactionIDs = 14; - uint64 blueScore = 15; + bool isHeaderOnly = 15; + uint64 blueScore = 16; } message TransactionVerboseData{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go index 7b22c32bc..9ec0133c1 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go @@ -85,6 +85,7 @@ func (x *BlockVerboseData) toAppMessage() (*appmessage.BlockVerboseData, error) Difficulty: x.Difficulty, ParentHashes: x.ParentHashes, SelectedParentHash: x.SelectedParentHash, + IsHeaderOnly: x.IsHeaderOnly, BlueScore: x.BlueScore, }, nil } @@ -114,6 +115,7 @@ func (x *BlockVerboseData) fromAppMessage(message *appmessage.BlockVerboseData) Difficulty: message.Difficulty, ParentHashes: message.ParentHashes, SelectedParentHash: message.SelectedParentHash, + IsHeaderOnly: message.IsHeaderOnly, BlueScore: message.BlueScore, } return nil From b0251fe1a6dbbeb89ae531749c4bf03cee436241 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 28 Dec 2020 10:08:36 +0200 Subject: [PATCH 168/351] Add missing lock to IsValidPruningPoint. (#1296) --- domain/consensus/consensus.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 9bd22421b..97bd4e97c 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -311,6 +311,9 @@ func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { } func (s *consensus) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) { + s.lock.Lock() + defer s.lock.Unlock() + err := s.validateBlockHashExists(blockHash) if err != nil { return false, err From c7c8b25c09ceb3cb384d1d29a50374f0f7e43826 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 28 Dec 2020 12:53:11 +0200 Subject: [PATCH 169/351] Set stream max message size and increase the max message size to 1GB (#1300) --- app/protocol/flows/blockrelay/ibd.go | 1 + .../network/netadapter/server/grpcserver/grpc_server.go | 2 +- .../network/netadapter/server/grpcserver/p2pserver.go | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 71d8c00ae..1d4dfb71d 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -53,6 +53,7 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain } if blockInfo.BlockStatus == externalapi.StatusHeaderOnly { + log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", msgIBDRootHash.Hash) isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) if err != nil { return err diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go index 1b19c0ac4..2cf4407b2 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go @@ -18,7 +18,7 @@ type gRPCServer struct { } // MaxMessageSize is the max size allowed for a message -const MaxMessageSize = 1024 * 1024 * 10 // 10MB +const MaxMessageSize = 1024 * 1024 * 1024 // 1GB // newGRPCServer creates a gRPC server func newGRPCServer(listeningAddresses []string) *gRPCServer { diff --git a/infrastructure/network/netadapter/server/grpcserver/p2pserver.go b/infrastructure/network/netadapter/server/grpcserver/p2pserver.go index 73dfbcd26..7add4fdfd 100644 --- a/infrastructure/network/netadapter/server/grpcserver/p2pserver.go +++ b/infrastructure/network/netadapter/server/grpcserver/p2pserver.go @@ -47,7 +47,8 @@ func (p *p2pServer) Connect(address string) (server.Connection, error) { } client := protowire.NewP2PClient(gRPCClientConnection) - stream, err := client.MessageStream(context.Background(), grpc.UseCompressor(gzip.Name)) + stream, err := client.MessageStream(context.Background(), grpc.UseCompressor(gzip.Name), + grpc.MaxCallRecvMsgSize(MaxMessageSize), grpc.MaxCallSendMsgSize(MaxMessageSize)) if err != nil { return nil, errors.Wrapf(err, "error getting client stream for %s", address) } From af1b8c8490e7624b85d28388e9bc682d9d06b30f Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 28 Dec 2020 16:04:00 +0200 Subject: [PATCH 170/351] Move version initializiation to init function to prevent race conditions (#1299) --- version/version.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/version/version.go b/version/version.go index cd730c4fa..da43a4ed4 100644 --- a/version/version.go +++ b/version/version.go @@ -21,8 +21,7 @@ var appBuild string var version = "" // string used for memoization of version -// Version returns the application version as a properly formed string -func Version() string { +func init() { if version == "" { // Start with the major, minor, and patch versions. version = fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch) @@ -35,7 +34,10 @@ func Version() string { version = fmt.Sprintf("%s-%s", version, appBuild) } } +} +// Version returns the application version as a properly formed string +func Version() string { return version } From 7e379028f38c264d71e555600fef765295c9881c Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 28 Dec 2020 16:22:00 +0200 Subject: [PATCH 171/351] Log the time it takes to delete blocks and save the utxo set for pruning point (#1307) --- .../consensus/processes/pruningmanager/pruningmanager.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 5c77d961d..f595745a2 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -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/utils/utxoserialization" + "github.com/kaspanet/kaspad/infrastructure/logger" ) // pruningManager resolves and manages the current pruning point @@ -184,6 +185,9 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { } func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.deletePastBlocks") + defer onEnd() + // Go over all P.Past and P.AC that's not in V.Past queue := pm.dagTraversalManager.NewDownHeap() @@ -261,6 +265,9 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) } func (pm *pruningManager) savePruningPoint(blockHash *externalapi.DomainHash) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.savePruningPoint") + defer onEnd() + utxoIter, err := pm.consensusStateManager.RestorePastUTXOSetIterator(blockHash) if err != nil { return err From 4aafe8a6308cbc9cdf26f66e0ee69c7d929bb691 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 29 Dec 2020 09:02:28 +0200 Subject: [PATCH 172/351] Fix a crashed caused by orphans whose validation failed. (#1297) --- app/protocol/flowcontext/orphans.go | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 773e9064a..247fe333d 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -88,15 +88,17 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*Uno } } if canBeUnorphaned { - blockInsertionResult, err := f.unorphanBlock(orphanHash) + blockInsertionResult, unorphaningSucceeded, err := f.unorphanBlock(orphanHash) if err != nil { return nil, err } - unorphaningResults = append(unorphaningResults, &UnorphaningResult{ - block: orphanBlock, - blockInsertionResult: blockInsertionResult, - }) - processQueue = f.addChildOrphansToProcessQueue(&orphanHash, processQueue) + if unorphaningSucceeded { + unorphaningResults = append(unorphaningResults, &UnorphaningResult{ + block: orphanBlock, + blockInsertionResult: blockInsertionResult, + }) + processQueue = f.addChildOrphansToProcessQueue(&orphanHash, processQueue) + } } } @@ -139,10 +141,10 @@ func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) return childOrphans } -func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externalapi.BlockInsertionResult, error) { +func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externalapi.BlockInsertionResult, bool, error) { orphanBlock, ok := f.orphans[orphanHash] if !ok { - return nil, errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash) + return nil, false, errors.Errorf("attempted to unorphan a non-orphan block %s", orphanHash) } delete(f.orphans, orphanHash) @@ -150,11 +152,11 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { log.Warnf("Validation failed for orphan block %s: %s", orphanHash, err) - return nil, nil + return nil, false, nil } - return nil, err + return nil, false, err } log.Infof("Unorphaned block %s", orphanHash) - return blockInsertionResult, nil + return blockInsertionResult, true, nil } From 5f226328363b3273e02469b5432d0cc91fc8862d Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 29 Dec 2020 09:28:02 +0200 Subject: [PATCH 173/351] Use sync rate for getBlockTemplate's isSynced (#1311) * Use sync rate for getBlockTemplate's isSynced * Fix a typo Co-authored-by: Mike Zak --- app/protocol/flowcontext/blocks.go | 2 + app/protocol/flowcontext/flow_context.go | 7 ++ app/protocol/flowcontext/orphans.go | 1 + app/protocol/flowcontext/sync_rate.go | 78 +++++++++++++++++++++++ app/protocol/manager.go | 7 +- app/rpc/rpchandlers/get_block_template.go | 5 +- 6 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 app/protocol/flowcontext/sync_rate.go diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 4458b1a9d..6a9a8d6b1 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -23,6 +23,8 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, hash := consensushashing.BlockHash(block) log.Debugf("OnNewBlock start for block %s", hash) defer log.Debugf("OnNewBlock end for block %s", hash) + + f.updateRecentBlockAddedTimesWithLastBlock() unorphaningResults, err := f.UnorphanBlocks(block) if err != nil { return err diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index 08406621e..1846148fd 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -1,6 +1,7 @@ package flowcontext import ( + "github.com/kaspanet/kaspad/util/mstime" "sync" "time" @@ -35,6 +36,11 @@ type FlowContext struct { addressManager *addressmanager.AddressManager connectionManager *connmanager.ConnectionManager + recentBlockAddedTimes []int64 + recentBlockAddedTimesMutex sync.Mutex + + timeStarted int64 + onBlockAddedToDAGHandler OnBlockAddedToDAGHandler onTransactionAddedToMempoolHandler OnTransactionAddedToMempoolHandler @@ -69,6 +75,7 @@ func New(cfg *config.Config, domain domain.Domain, addressManager *addressmanage peers: make(map[id.ID]*peerpkg.Peer), transactionsToRebroadcast: make(map[externalapi.DomainTransactionID]*externalapi.DomainTransaction), orphans: make(map[externalapi.DomainHash]*externalapi.DomainBlock), + timeStarted: mstime.Now().UnixMilliseconds(), } } diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 247fe333d..620748cf7 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -156,6 +156,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa } return nil, false, err } + f.updateRecentBlockAddedTimesWithLastBlock() log.Infof("Unorphaned block %s", orphanHash) return blockInsertionResult, true, nil diff --git a/app/protocol/flowcontext/sync_rate.go b/app/protocol/flowcontext/sync_rate.go new file mode 100644 index 000000000..f581c520a --- /dev/null +++ b/app/protocol/flowcontext/sync_rate.go @@ -0,0 +1,78 @@ +package flowcontext + +import "github.com/kaspanet/kaspad/util/mstime" + +const ( + syncRateWindowInMilliSeconds = 60_000 + syncRateMaxDeviation = 0.05 + maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 300_000 +) + +func (f *FlowContext) updateRecentBlockAddedTimesWithLastBlock() { + f.recentBlockAddedTimesMutex.Lock() + defer f.recentBlockAddedTimesMutex.Unlock() + + f.removeOldBlockTimes() + f.recentBlockAddedTimes = append(f.recentBlockAddedTimes, mstime.Now().UnixMilliseconds()) +} + +// removeOldBlockTimes removes from recentBlockAddedTimes block times +// older than syncRateWindowInMilliSeconds. +// This function is not safe for concurrent use. +func (f *FlowContext) removeOldBlockTimes() { + now := mstime.Now().UnixMilliseconds() + mostRecentBlockToKeep := 0 + for i, blockAddedTime := range f.recentBlockAddedTimes { + if now-syncRateWindowInMilliSeconds < blockAddedTime { + mostRecentBlockToKeep = i + break + } + } + f.recentBlockAddedTimes = f.recentBlockAddedTimes[mostRecentBlockToKeep:] +} + +func (f *FlowContext) isSyncRateBelowMinimum() bool { + f.recentBlockAddedTimesMutex.Lock() + defer f.recentBlockAddedTimesMutex.Unlock() + + f.removeOldBlockTimes() + + now := mstime.Now().UnixMilliseconds() + timeSinceStart := now - f.timeStarted + if timeSinceStart <= syncRateWindowInMilliSeconds { + return false + } + + expectedBlocks := float64(syncRateWindowInMilliSeconds) / float64(f.cfg.NetParams().TargetTimePerBlock.Milliseconds()) + return 1-float64(len(f.recentBlockAddedTimes))/expectedBlocks > syncRateMaxDeviation +} + +// ShouldMine returns whether it's ok to use block template from this node +// for mining purposes. +func (f *FlowContext) ShouldMine() (bool, error) { + if f.isSyncRateBelowMinimum() { + log.Debugf("The sync rate is below the minimum, so ShouldMine returns true") + return true, nil + } + + if f.IsIBDRunning() { + log.Debugf("IBD is running, so ShouldMine returns false") + return false, nil + } + + virtualSelectedParent, err := f.domain.Consensus().GetVirtualSelectedParent() + if err != nil { + return false, err + } + + now := mstime.Now().UnixMilliseconds() + if now-virtualSelectedParent.Header.TimeInMilliseconds < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { + log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true", + virtualSelectedParent.Header.TimeInMilliseconds) + return true, nil + } + + log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false", + virtualSelectedParent.Header.TimeInMilliseconds) + return false, nil +} diff --git a/app/protocol/manager.go b/app/protocol/manager.go index 0fe0f3a01..59a9b5267 100644 --- a/app/protocol/manager.go +++ b/app/protocol/manager.go @@ -68,7 +68,8 @@ func (m *Manager) SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMemp m.context.SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMempoolHandler) } -// IsIBDRunning returns true if IBD is currently running -func (m *Manager) IsIBDRunning() bool { - return m.context.IsIBDRunning() +// ShouldMine returns whether it's ok to use block template from this node +// for mining purposes. +func (m *Manager) ShouldMine() (bool, error) { + return m.context.ShouldMine() } diff --git a/app/rpc/rpchandlers/get_block_template.go b/app/rpc/rpchandlers/get_block_template.go index f9936e8ad..c1fc0354a 100644 --- a/app/rpc/rpchandlers/get_block_template.go +++ b/app/rpc/rpchandlers/get_block_template.go @@ -33,7 +33,10 @@ func HandleGetBlockTemplate(context *rpccontext.Context, _ *router.Router, reque } msgBlock := appmessage.DomainBlockToMsgBlock(templateBlock) - isSynced := !context.ProtocolManager.IsIBDRunning() + isSynced, err := context.ProtocolManager.ShouldMine() + if err != nil { + return nil, err + } return appmessage.NewGetBlockTemplateResponseMessage(msgBlock, isSynced), nil } From d91afbfe3b184f4ab372e4f2e21d73db3348024c Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 29 Dec 2020 10:32:28 +0200 Subject: [PATCH 174/351] Change most Tracef to Debugf (#1302) * Change most Tracef to Debugf * Remove diff from log --- app/protocol/flowcontext/blocks.go | 4 +- app/protocol/flowcontext/orphans.go | 4 +- .../blockprocessor/validateandinsertblock.go | 8 ++-- .../processes/blockprocessor/validateblock.go | 4 +- .../add_block_to_virtual.go | 48 +++++++++---------- .../calculate_past_utxo.go | 32 ++++++------- .../check_finality_violation.go | 14 +++--- .../consensusstatemanager/multisets.go | 8 ++-- .../pick_virtual_parents.go | 16 +++---- .../resolve_block_status.go | 38 +++++++-------- .../update_pruning_utxo_set.go | 4 +- .../consensusstatemanager/update_virtual.go | 32 ++++++------- .../consensusstatemanager/utxo_diffs.go | 24 +++++----- .../verify_and_build_utxo.go | 18 +++---- .../finalitymanager/finality_manager.go | 22 ++++----- .../server/grpcserver/connection_loops.go | 5 +- 16 files changed, 140 insertions(+), 141 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 6a9a8d6b1..1ab87e81e 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -42,11 +42,11 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, for i, newBlock := range newBlocks { blocklogger.LogBlock(block) - log.Tracef("OnNewBlock: passing block %s transactions to mining manager", hash) + log.Debugf("OnNewBlock: passing block %s transactions to mining manager", hash) _ = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) if f.onBlockAddedToDAGHandler != nil { - log.Tracef("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash) + log.Debugf("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash) blockInsertionResult = newBlockInsertionResults[i] err := f.onBlockAddedToDAGHandler(newBlock, blockInsertionResult) if err != nil { diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 620748cf7..9c563ba2e 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -70,7 +70,7 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*Uno orphanHash, processQueue = processQueue[0], processQueue[1:] orphanBlock := f.orphans[orphanHash] - log.Tracef("Considering to unorphan block %s with parents %s", + log.Debugf("Considering to unorphan block %s with parents %s", orphanHash, orphanBlock.Header.ParentHashes) canBeUnorphaned := true @@ -80,7 +80,7 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*Uno return nil, err } if !orphanBlockParentInfo.Exists || orphanBlockParentInfo.BlockStatus == externalapi.StatusHeaderOnly { - log.Tracef("Cannot unorphan block %s. It's missing at "+ + log.Debugf("Cannot unorphan block %s. It's missing at "+ "least the following parent: %s", orphanHash, orphanBlockParentHash) canBeUnorphaned = false diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 0c57e4173..b95cf82ef 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -33,7 +33,7 @@ func (bp *blockProcessor) setBlockStatusAfterBlockValidation(block *externalapi. return errors.Errorf("block %s that is not the pruning point is not expected to be valid "+ "before adding to to the consensus state manager", blockHash) } - log.Tracef("Block %s is the pruning point and has status %s, so leaving its status untouched", + log.Debugf("Block %s is the pruning point and has status %s, so leaving its status untouched", blockHash, status) return nil } @@ -41,11 +41,11 @@ func (bp *blockProcessor) setBlockStatusAfterBlockValidation(block *externalapi. isHeaderOnlyBlock := isHeaderOnlyBlock(block) if isHeaderOnlyBlock { - log.Tracef("Block %s is a header-only block so setting its status as %s", + log.Debugf("Block %s is a header-only block so setting its status as %s", blockHash, externalapi.StatusHeaderOnly) bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) } else { - log.Tracef("Block %s has body so setting its status as %s", + log.Debugf("Block %s has body so setting its status as %s", blockHash, externalapi.StatusUTXOPendingVerification) bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification) } @@ -247,7 +247,7 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock return err } } else { - log.Tracef("Skipping ValidateBodyInContext for block %s because it's header only", blockHash) + log.Debugf("Skipping ValidateBodyInContext for block %s because it's header only", blockHash) } return nil diff --git a/domain/consensus/processes/blockprocessor/validateblock.go b/domain/consensus/processes/blockprocessor/validateblock.go index 405c8e503..8d2d163b6 100644 --- a/domain/consensus/processes/blockprocessor/validateblock.go +++ b/domain/consensus/processes/blockprocessor/validateblock.go @@ -27,10 +27,10 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, isPrunin } if !hasValidatedHeader { - log.Tracef("Staging block %s header", blockHash) + log.Debugf("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) + log.Debugf("Block %s header is already known, so no need to stage it", blockHash) } // If any validation until (included) proof-of-work fails, simply diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 01df31a28..ef9e6cc83 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -9,10 +9,10 @@ import ( // current virtual. This process may result in a new virtual block // getting created 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.Debugf("AddBlock start for block %s", blockHash) + defer log.Debugf("AddBlock end for block %s", blockHash) - log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash) + log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash) isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash) if err != nil { return nil, err @@ -22,7 +22,7 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (* // 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 "+ + log.Debugf("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 { @@ -35,7 +35,7 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (* } if !isViolatingFinality { - log.Tracef("Block %s doesn't violate finality. Resolving its block status", blockHash) + log.Debugf("Block %s doesn't violate finality. Resolving its block status", blockHash) blockStatus, err := csm.resolveBlockStatus(blockHash) if err != nil { return nil, err @@ -48,14 +48,14 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (* "therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification) } - log.Tracef("Adding block %s to the DAG tips", blockHash) + log.Debugf("Adding block %s to the DAG tips", blockHash) newTips, err := csm.addTip(blockHash) if err != nil { return nil, err } - log.Tracef("After adding %s, the new tips are %s", blockHash, newTips) + log.Debugf("After adding %s, the new tips are %s", blockHash, newTips) - log.Tracef("Updating the virtual with the new tips") + log.Debugf("Updating the virtual with the new tips") selectedParentChainChanges, err := csm.updateVirtual(blockHash, newTips) if err != nil { return nil, err @@ -65,11 +65,11 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (* } 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) + log.Debugf("isCandidateToBeNextVirtualSelectedParent start for block %s", blockHash) + defer log.Debugf("isCandidateToBeNextVirtualSelectedParent end for block %s", blockHash) if blockHash.Equal(csm.genesisHash) { - log.Tracef("Block %s is the genesis block, therefore it is "+ + log.Debugf("Block %s is the genesis block, therefore it is "+ "the selected parent by definition", blockHash) return true, nil } @@ -79,40 +79,40 @@ func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(block return false, err } - log.Tracef("Selecting the next selected parent between "+ + log.Debugf("Selecting the next selected parent between "+ "the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent()) nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(virtualGhostdagData.SelectedParent(), blockHash) if err != nil { return false, err } - log.Tracef("The next selected parent is: %s", nextVirtualSelectedParent) + log.Debugf("The next selected parent is: %s", nextVirtualSelectedParent) return blockHash.Equal(nextVirtualSelectedParent), nil } func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (newTips []*externalapi.DomainHash, err error) { - log.Tracef("addTip start for new tip %s", newTipHash) - defer log.Tracef("addTip end for new tip %s", newTipHash) + log.Debugf("addTip start for new tip %s", newTipHash) + defer log.Debugf("addTip end for new tip %s", newTipHash) - log.Tracef("Calculating the new tips for new tip %s", newTipHash) + log.Debugf("Calculating the new tips for new tip %s", newTipHash) newTips, err = csm.calculateNewTips(newTipHash) if err != nil { return nil, err } - log.Tracef("The new tips are: %s", newTips) + log.Debugf("The new tips are: %s", newTips) csm.consensusStateStore.StageTips(newTips) - log.Tracef("Staged the new tips %s", newTips) + log.Debugf("Staged the new tips %s", newTips) return newTips, nil } func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - log.Tracef("calculateNewTips start for new tip %s", newTipHash) - defer log.Tracef("calculateNewTips end for new tip %s", newTipHash) + log.Debugf("calculateNewTips start for new tip %s", newTipHash) + defer log.Debugf("calculateNewTips end for new tip %s", newTipHash) if newTipHash.Equal(csm.genesisHash) { - log.Tracef("The new tip is the genesis block, therefore it is the only tip by definition") + log.Debugf("The new tip is the genesis block, therefore it is the only tip by definition") return []*externalapi.DomainHash{newTipHash}, nil } @@ -120,13 +120,13 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai if err != nil { return nil, err } - log.Tracef("The current tips are: %s", currentTips) + log.Debugf("The current tips are: %s", currentTips) newTipParents, err := csm.dagTopologyManager.Parents(newTipHash) if err != nil { return nil, err } - log.Tracef("The parents of the new tip are: %s", newTipParents) + log.Debugf("The parents of the new tip are: %s", newTipParents) newTips := []*externalapi.DomainHash{newTipHash} @@ -142,7 +142,7 @@ func (csm *consensusStateManager) calculateNewTips(newTipHash *externalapi.Domai newTips = append(newTips, currentTip) } } - log.Tracef("The calculated new tips are: %s", newTips) + log.Debugf("The calculated new tips are: %s", newTips) return newTips, nil } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 407449dc5..7824377e6 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -15,11 +15,11 @@ import ( func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( model.UTXODiff, externalapi.AcceptanceData, model.Multiset, error) { - log.Tracef("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) - defer log.Tracef("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) + log.Debugf("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) + defer log.Debugf("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) if blockHash.Equal(csm.genesisHash) { - log.Tracef("Block %s is the genesis. By definition, "+ + log.Debugf("Block %s is the genesis. By definition, "+ "it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash) return utxo.NewUTXODiff(), externalapi.AcceptanceData{}, multiset.New(), nil } @@ -29,53 +29,53 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * return nil, nil, nil, err } - log.Tracef("Restoring the past UTXO of block %s with selectedParent %s", + log.Debugf("Restoring the past UTXO of block %s with selectedParent %s", blockHash, blockGHOSTDAGData.SelectedParent()) selectedParentPastUTXO, err := csm.restorePastUTXO(blockGHOSTDAGData.SelectedParent()) if err != nil { return nil, nil, nil, err } - log.Tracef("Applying blue blocks to the selected parent past UTXO of block %s", blockHash) + log.Debugf("Applying blue blocks to the selected parent past UTXO of block %s", blockHash) acceptanceData, utxoDiff, err := csm.applyMergeSetBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err } - log.Tracef("Calculating the multiset of %s", blockHash) + log.Debugf("Calculating the multiset of %s", blockHash) multiset, err := csm.calculateMultiset(acceptanceData, blockGHOSTDAGData) if err != nil { return nil, nil, nil, err } - log.Tracef("The multiset of block %s resolved to: %s", blockHash, multiset.Hash()) + log.Debugf("The multiset of block %s resolved to: %s", blockHash, multiset.Hash()) return utxoDiff.ToImmutable(), acceptanceData, multiset, nil } func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainHash) (model.MutableUTXODiff, error) { - log.Tracef("restorePastUTXO start for block %s", blockHash) - defer log.Tracef("restorePastUTXO end for block %s", blockHash) + log.Debugf("restorePastUTXO start for block %s", blockHash) + defer log.Debugf("restorePastUTXO end for block %s", blockHash) var err error - log.Tracef("Collecting UTXO diffs for block %s", blockHash) + log.Debugf("Collecting UTXO diffs for block %s", blockHash) var utxoDiffs []model.UTXODiff nextBlockHash := blockHash for { - log.Tracef("Collecting UTXO diff for block %s", nextBlockHash) + log.Debugf("Collecting UTXO diff for block %s", nextBlockHash) utxoDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, nextBlockHash) if err != nil { return nil, err } utxoDiffs = append(utxoDiffs, utxoDiff) - log.Tracef("Collected UTXO diff for block %s: %s", nextBlockHash, utxoDiff) + log.Debugf("Collected UTXO diff for block %s: %s", nextBlockHash, utxoDiff) exists, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, nextBlockHash) if err != nil { return nil, err } if !exists { - log.Tracef("Block %s does not have a UTXO diff child, "+ + log.Debugf("Block %s does not have a UTXO diff child, "+ "meaning we reached the virtual. Returning the collected "+ "UTXO diffs: %s", nextBlockHash, utxoDiffs) break @@ -86,7 +86,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH return nil, err } if nextBlockHash == nil { - log.Tracef("Block %s does not have a UTXO diff child, "+ + log.Debugf("Block %s does not have a UTXO diff child, "+ "meaning we reached the virtual. Returning the collected "+ "UTXO diffs: %s", nextBlockHash, utxoDiffs) break @@ -94,7 +94,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH } // apply the diffs in reverse order - log.Tracef("Applying the collected UTXO diffs for block %s in reverse order", blockHash) + log.Debugf("Applying the collected UTXO diffs for block %s in reverse order", blockHash) accumulatedDiff := utxo.NewMutableUTXODiff() for i := len(utxoDiffs) - 1; i >= 0; i-- { err = accumulatedDiff.WithDiffInPlace(utxoDiffs[i]) @@ -111,7 +111,7 @@ func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.Dom selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) ( externalapi.AcceptanceData, model.MutableUTXODiff, error) { - log.Tracef("applyMergeSetBlocks start for block %s", blockHash) + log.Debugf("applyMergeSetBlocks start for block %s", blockHash) defer log.Tracef("applyMergeSetBlocks end for block %s", blockHash) mergeSetBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSet()) diff --git a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go index 4451c5cee..0ecea0242 100644 --- a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go +++ b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go @@ -5,11 +5,11 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.DomainHash) (isViolatingFinality bool, shouldSendNotification bool, err error) { - log.Tracef("isViolatingFinality start for block %s", blockHash) - defer log.Tracef("isViolatingFinality end for block %s", blockHash) + log.Debugf("isViolatingFinality start for block %s", blockHash) + defer log.Debugf("isViolatingFinality end for block %s", blockHash) if blockHash.Equal(csm.genesisHash) { - log.Tracef("Block %s is the genesis block, "+ + log.Debugf("Block %s is the genesis block, "+ "and does not violate finality by definition", blockHash) return false, false, nil } @@ -19,7 +19,7 @@ func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.Dom if err != nil { return false, false, err } - log.Tracef("The virtual finality point is: %s", virtualFinalityPoint) + log.Debugf("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 @@ -30,7 +30,7 @@ func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.Dom if err != nil { return false, false, err } - log.Tracef("The pruning point is: %s", pruningPoint) + log.Debugf("The pruning point is: %s", pruningPoint) isFinalityPointInPastOfPruningPoint, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, pruningPoint) if err != nil { @@ -40,7 +40,7 @@ func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.Dom if !isFinalityPointInPastOfPruningPoint { finalityPoint = virtualFinalityPoint } else { - log.Tracef("The virtual finality point is %s in the past of the pruning point, so finality is validated "+ + log.Debugf("The virtual finality point is %s in the past of the pruning point, so finality is validated "+ "using the pruning point", virtualFinalityPoint) finalityPoint = pruningPoint } @@ -60,7 +60,7 @@ func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.Dom // of the finality point. return true, false, nil } - log.Tracef("Block %s does not violate finality", blockHash) + log.Debugf("Block %s does not violate finality", blockHash) return false, false, nil } diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index a0c74d3b7..644e4f687 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -12,11 +12,11 @@ import ( func (csm *consensusStateManager) calculateMultiset( acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) { - log.Tracef("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) - defer log.Tracef("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) + log.Debugf("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) + defer log.Debugf("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) if blockGHOSTDAGData.SelectedParent() == nil { - log.Tracef("Selected parent is nil, which could only happen for the genesis. " + + log.Debugf("Selected parent is nil, which could only happen for the genesis. " + "The genesis, by definition, has an empty multiset") return multiset.New(), nil } @@ -25,7 +25,7 @@ func (csm *consensusStateManager) calculateMultiset( if err != nil { return nil, err } - log.Tracef("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent(), ms.Hash()) + log.Debugf("The multiset for the selected parent %s is: %s", blockGHOSTDAGData.SelectedParent(), ms.Hash()) for _, blockAcceptanceData := range acceptanceData { for i, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 3746f2422..fc0d93031 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -9,10 +9,10 @@ import ( ) func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - log.Tracef("pickVirtualParents start for tips: %s", tips) - defer log.Tracef("pickVirtualParents end for tips: %s", tips) + log.Debugf("pickVirtualParents start for tips: %s", tips) + defer log.Debugf("pickVirtualParents end for tips: %s", tips) - log.Tracef("Pushing all tips into a DownHeap") + log.Debugf("Pushing all tips into a DownHeap") candidatesHeap := csm.dagTraversalManager.NewDownHeap() for _, tip := range tips { err := candidatesHeap.Push(tip) @@ -29,7 +29,7 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH if err != nil { return nil, err } - log.Tracef("The selected parent of the virtual is: %s", virtualSelectedParent) + log.Debugf("The selected parent of the virtual is: %s", virtualSelectedParent) selectedVirtualParents := hashset.NewFromSlice(virtualSelectedParent) @@ -38,17 +38,17 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH for candidatesHeap.Len() > 0 && uint64(len(selectedVirtualParents)) < uint64(csm.maxBlockParents) { candidate := candidatesHeap.Pop() - log.Tracef("Attempting to add %s to the virtual parents", candidate) - log.Tracef("The current merge set size is %d", mergeSetSize) + log.Debugf("Attempting to add %s to the virtual parents", candidate) + log.Debugf("The current merge set size is %d", mergeSetSize) mergeSetIncrease, err := csm.mergeSetIncrease(candidate, selectedVirtualParents) if err != nil { return nil, err } - log.Tracef("The merge set would increase by %d with block %s", mergeSetIncrease, candidate) + log.Debugf("The merge set would increase by %d with block %s", mergeSetIncrease, candidate) if mergeSetSize+mergeSetIncrease > csm.mergeSetSizeLimit { - log.Tracef("Cannot add block %s since that would violate the merge set size limit", candidate) + log.Debugf("Cannot add block %s since that would violate the merge set size limit", candidate) continue } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 8123aa690..fef69c2af 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -8,39 +8,39 @@ import ( ) func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { - log.Tracef("resolveBlockStatus start for block %s", blockHash) - defer log.Tracef("resolveBlockStatus end for block %s", blockHash) + log.Debugf("resolveBlockStatus start for block %s", blockHash) + defer log.Debugf("resolveBlockStatus end for block %s", blockHash) - log.Tracef("Getting a list of all blocks in the selected "+ + log.Debugf("Getting a list of all blocks in the selected "+ "parent chain of %s that have no yet resolved their status", blockHash) unverifiedBlocks, err := csm.getUnverifiedChainBlocks(blockHash) if err != nil { return 0, err } - log.Tracef("Got %d unverified blocks in the selected parent "+ + log.Debugf("Got %d unverified blocks in the selected parent "+ "chain of %s: %s", len(unverifiedBlocks), blockHash, unverifiedBlocks) // If there's no unverified blocks in the given block's chain - this means the given block already has a // UTXO-verified status, and therefore it should be retrieved from the store and returned if len(unverifiedBlocks) == 0 { - log.Tracef("There are not unverified blocks in %s's selected parent chain. "+ + log.Debugf("There are not unverified blocks in %s's selected parent chain. "+ "This means that the block already has a UTXO-verified status.", blockHash) status, err := csm.blockStatusStore.Get(csm.databaseContext, blockHash) if err != nil { return 0, err } - log.Tracef("Block %s's status resolved to: %s", blockHash, status) + log.Debugf("Block %s's status resolved to: %s", blockHash, status) return status, nil } - log.Tracef("Finding the status of the selected parent of %s", blockHash) + log.Debugf("Finding the status of the selected parent of %s", blockHash) selectedParentStatus, err := csm.findSelectedParentStatus(unverifiedBlocks) if err != nil { return 0, err } - log.Tracef("The status of the selected parent of %s is: %s", blockHash, selectedParentStatus) + log.Debugf("The status of the selected parent of %s is: %s", blockHash, selectedParentStatus) - log.Tracef("Resolving the unverified blocks' status in reverse order (past to present)") + log.Debugf("Resolving the unverified blocks' status in reverse order (past to present)") var blockStatus externalapi.BlockStatus for i := len(unverifiedBlocks) - 1; i >= 0; i-- { unverifiedBlockHash := unverifiedBlocks[i] @@ -66,12 +66,12 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*externalapi.DomainHash) ( externalapi.BlockStatus, error) { - log.Tracef("findSelectedParentStatus start") - defer log.Tracef("findSelectedParentStatus end") + log.Debugf("findSelectedParentStatus start") + defer log.Debugf("findSelectedParentStatus end") lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1] if lastUnverifiedBlock.Equal(csm.genesisHash) { - log.Tracef("the most recent unverified block is the genesis block, "+ + log.Debugf("the most recent unverified block is the genesis block, "+ "which by definition has status: %s", externalapi.StatusUTXOValid) return externalapi.StatusUTXOValid, nil } @@ -85,24 +85,24 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e func (csm *consensusStateManager) getUnverifiedChainBlocks( blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - log.Tracef("getUnverifiedChainBlocks start for block %s", blockHash) - defer log.Tracef("getUnverifiedChainBlocks end for block %s", blockHash) + log.Debugf("getUnverifiedChainBlocks start for block %s", blockHash) + defer log.Debugf("getUnverifiedChainBlocks end for block %s", blockHash) var unverifiedBlocks []*externalapi.DomainHash currentHash := blockHash for { - log.Tracef("Getting status for block %s", currentHash) + log.Debugf("Getting status for block %s", currentHash) currentBlockStatus, err := csm.blockStatusStore.Get(csm.databaseContext, currentHash) if err != nil { return nil, err } if currentBlockStatus != externalapi.StatusUTXOPendingVerification { - log.Tracef("Block %s has status %s. Returning all the "+ + log.Debugf("Block %s has status %s. Returning all the "+ "unverified blocks prior to it: %s", currentHash, currentBlockStatus, unverifiedBlocks) return unverifiedBlocks, nil } - log.Tracef("Block %s is unverified. Adding it to the unverified block collection", currentHash) + log.Debugf("Block %s is unverified. Adding it to the unverified block collection", currentHash) unverifiedBlocks = append(unverifiedBlocks, currentHash) currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, currentHash) @@ -111,7 +111,7 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks( } if currentBlockGHOSTDAGData.SelectedParent() == nil { - log.Tracef("Genesis block reached. Returning all the "+ + log.Debugf("Genesis block reached. Returning all the "+ "unverified blocks prior to it: %s", unverifiedBlocks) return unverifiedBlocks, nil } @@ -121,7 +121,7 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks( } func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { - log.Tracef("resolveSingleBlockStatus start for block %s", blockHash) + log.Debugf("resolveSingleBlockStatus start for block %s", blockHash) defer log.Tracef("resolveSingleBlockStatus end for block %s", blockHash) log.Tracef("Calculating pastUTXO and acceptance data and multiset for block %s", blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index f0a0d195b..61f5d2552 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -27,8 +27,8 @@ func (csm *consensusStateManager) UpdatePruningPoint(newPruningPoint *externalap } func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { - log.Tracef("updatePruningPoint start") - defer log.Tracef("updatePruningPoint end") + log.Debugf("updatePruningPoint start") + defer log.Debugf("updatePruningPoint end") newPruningPointHash := consensushashing.BlockHash(newPruningPoint) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 9d50dc8e5..aa56d6848 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -8,10 +8,10 @@ import ( 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.Debugf("updateVirtual start for block %s", newBlockHash) + defer log.Debugf("updateVirtual end for block %s", newBlockHash) - log.Tracef("Saving a reference to the GHOSTDAG data of the old virtual") + log.Debugf("Saving a reference to the GHOSTDAG data of the old virtual") var oldVirtualSelectedParent *externalapi.DomainHash if !newBlockHash.Equal(csm.genesisHash) { oldVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) @@ -21,49 +21,49 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain oldVirtualSelectedParent = oldVirtualGHOSTDAGData.SelectedParent() } - log.Tracef("Picking virtual parents from the tips: %s", tips) + log.Debugf("Picking virtual parents from the tips: %s", tips) virtualParents, err := csm.pickVirtualParents(tips) if err != nil { return nil, err } - log.Tracef("Picked virtual parents: %s", virtualParents) + log.Debugf("Picked virtual parents: %s", virtualParents) err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, virtualParents) if err != nil { return nil, err } - log.Tracef("Set new parents for the virtual block hash") + log.Debugf("Set new parents for the virtual block hash") err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash) if err != nil { return nil, err } - log.Tracef("Calculating past UTXO, acceptance data, and multiset for the new virtual block") + log.Debugf("Calculating past UTXO, acceptance data, and multiset for the new virtual block") virtualUTXODiff, virtualAcceptanceData, virtualMultiset, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash) if err != nil { return nil, err } - log.Tracef("Staging new acceptance data for the virtual block") + log.Debugf("Staging new acceptance data for the virtual block") csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) - log.Tracef("Staging new multiset for the virtual block") + log.Debugf("Staging new multiset for the virtual block") csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) - log.Tracef("Staging new UTXO diff for the virtual block") + log.Debugf("Staging new UTXO diff for the virtual block") err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) if err != nil { return nil, err } - log.Tracef("Updating the virtual diff parents after adding %s to the DAG", newBlockHash) + log.Debugf("Updating the virtual diff parents after adding %s to the DAG", newBlockHash) err = csm.updateVirtualDiffParents(virtualUTXODiff) if err != nil { return nil, err } - log.Tracef("Calculating selected parent chain changes") + log.Debugf("Calculating selected parent chain changes") var selectedParentChainChanges *externalapi.SelectedParentChainChanges if !newBlockHash.Equal(csm.genesisHash) { newVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash) @@ -81,8 +81,8 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain } func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff model.UTXODiff) error { - log.Tracef("updateVirtualDiffParents start") - defer log.Tracef("updateVirtualDiffParents end") + log.Debugf("updateVirtualDiffParents start") + defer log.Debugf("updateVirtualDiffParents end") virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { @@ -90,7 +90,7 @@ func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff model } for _, virtualDiffParent := range virtualDiffParents { - log.Tracef("Calculating new UTXO diff for virtual diff parent %s", virtualDiffParent) + log.Debugf("Calculating new UTXO diff for virtual diff parent %s", virtualDiffParent) virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { return err @@ -100,7 +100,7 @@ func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff model return err } - log.Tracef("Staging new UTXO diff for virtual diff parent %s: %s", virtualDiffParent, newDiff) + log.Debugf("Staging new UTXO diff for virtual diff parent %s", virtualDiffParent) err = csm.stageDiff(virtualDiffParent, newDiff, nil) if err != nil { return err diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go index 4ba8d5325..5fb0807f0 100644 --- a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go +++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go @@ -9,24 +9,24 @@ import ( func (csm *consensusStateManager) stageDiff(blockHash *externalapi.DomainHash, utxoDiff model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { - log.Tracef("stageDiff start for block %s", blockHash) - defer log.Tracef("stageDiff end for block %s", blockHash) + log.Debugf("stageDiff start for block %s", blockHash) + defer log.Debugf("stageDiff end for block %s", blockHash) - log.Tracef("Staging block %s as the diff child of %s", utxoDiffChild, blockHash) + log.Debugf("Staging block %s as the diff child of %s", utxoDiffChild, blockHash) csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild) if utxoDiffChild == nil { - log.Tracef("Adding block %s to the virtual diff parents", blockHash) + log.Debugf("Adding block %s to the virtual diff parents", blockHash) return csm.addToVirtualDiffParents(blockHash) } - log.Tracef("Removing block %s from the virtual diff parents", blockHash) + log.Debugf("Removing block %s from the virtual diff parents", blockHash) return csm.removeFromVirtualDiffParents(blockHash) } func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi.DomainHash) error { - log.Tracef("addToVirtualDiffParents start for block %s", blockHash) - defer log.Tracef("addToVirtualDiffParents end for block %s", blockHash) + log.Debugf("addToVirtualDiffParents start for block %s", blockHash) + defer log.Debugf("addToVirtualDiffParents end for block %s", blockHash) var oldVirtualDiffParents []*externalapi.DomainHash if !blockHash.Equal(csm.genesisHash) { @@ -46,19 +46,19 @@ func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi } if isInVirtualDiffParents { - log.Tracef("Block %s is already a virtual diff parent, so there's no need to add it", blockHash) + log.Debugf("Block %s is already a virtual diff parent, so there's no need to add it", blockHash) return nil } newVirtualDiffParents := append([]*externalapi.DomainHash{blockHash}, oldVirtualDiffParents...) - log.Tracef("Staging virtual diff parents after adding %s to it", blockHash) + log.Debugf("Staging virtual diff parents after adding %s to it", blockHash) csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) return nil } func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *externalapi.DomainHash) error { - log.Tracef("removeFromVirtualDiffParents start for block %s", blockHash) - defer log.Tracef("removeFromVirtualDiffParents end for block %s", blockHash) + log.Debugf("removeFromVirtualDiffParents start for block %s", blockHash) + defer log.Debugf("removeFromVirtualDiffParents end for block %s", blockHash) oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { @@ -77,7 +77,7 @@ func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *extern "have a length of %d but got length of %d", len(oldVirtualDiffParents)-1, len(newVirtualDiffParents)) } - log.Tracef("Staging virtual diff parents after removing %s from it", blockHash) + log.Debugf("Staging virtual diff parents after removing %s from it", blockHash) csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) return nil } diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index b4ecd098e..7dd6b2991 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -20,33 +20,33 @@ import ( func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blockHash *externalapi.DomainHash, pastUTXODiff model.UTXODiff, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) error { - log.Tracef("verifyUTXO start for block %s", blockHash) - defer log.Tracef("verifyUTXO end for block %s", blockHash) + log.Debugf("verifyUTXO start for block %s", blockHash) + defer log.Debugf("verifyUTXO end for block %s", blockHash) - log.Tracef("Validating UTXO commitment for block %s", blockHash) + log.Debugf("Validating UTXO commitment for block %s", blockHash) err := csm.validateUTXOCommitment(block, blockHash, multiset) if err != nil { return err } - log.Tracef("UTXO commitment validation passed for block %s", blockHash) + log.Debugf("UTXO commitment validation passed for block %s", blockHash) - log.Tracef("Validating acceptedIDMerkleRoot for block %s", blockHash) + log.Debugf("Validating acceptedIDMerkleRoot for block %s", blockHash) err = csm.validateAcceptedIDMerkleRoot(block, blockHash, acceptanceData) if err != nil { return err } - log.Tracef("AcceptedIDMerkleRoot validation passed for block %s", blockHash) + log.Debugf("AcceptedIDMerkleRoot validation passed for block %s", blockHash) coinbaseTransaction := block.Transactions[0] - log.Tracef("Validating coinbase transaction %s for block %s", + log.Debugf("Validating coinbase transaction %s for block %s", consensushashing.TransactionID(coinbaseTransaction), blockHash) err = csm.validateCoinbaseTransaction(blockHash, coinbaseTransaction) if err != nil { return err } - log.Tracef("Coinbase transaction validation passed for block %s", blockHash) + log.Debugf("Coinbase transaction validation passed for block %s", blockHash) - log.Tracef("Validating transactions against past UTXO for block %s", blockHash) + log.Debugf("Validating transactions against past UTXO for block %s", blockHash) err = csm.validateBlockTransactionsAgainstPastUTXO(block, pastUTXODiff) if err != nil { return err diff --git a/domain/consensus/processes/finalitymanager/finality_manager.go b/domain/consensus/processes/finalitymanager/finality_manager.go index 67cf5b811..c383dcf20 100644 --- a/domain/consensus/processes/finalitymanager/finality_manager.go +++ b/domain/consensus/processes/finalitymanager/finality_manager.go @@ -36,27 +36,27 @@ func New(databaseContext model.DBReader, } func (fm *finalityManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) { - log.Tracef("virtualFinalityPoint start") - defer log.Tracef("virtualFinalityPoint end") + log.Debugf("virtualFinalityPoint start") + defer log.Debugf("virtualFinalityPoint end") virtualFinalityPoint, err := fm.calculateFinalityPoint(model.VirtualBlockHash) if err != nil { return nil, err } - log.Tracef("The current virtual finality block is: %s", virtualFinalityPoint) + log.Debugf("The current virtual finality block is: %s", virtualFinalityPoint) return virtualFinalityPoint, nil } func (fm *finalityManager) FinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - log.Tracef("FinalityPoint start") - defer log.Tracef("FinalityPoint end") + log.Debugf("FinalityPoint start") + defer log.Debugf("FinalityPoint end") if blockHash.Equal(model.VirtualBlockHash) { return fm.VirtualFinalityPoint() } finalityPoint, err := fm.finalityStore.FinalityPoint(fm.databaseContext, blockHash) if err != nil { - log.Tracef("%s finality point not found in store - calculating", blockHash) + log.Debugf("%s finality point not found in store - calculating", blockHash) if errors.Is(err, database.ErrNotFound) { return fm.calculateAndStageFinalityPoint(blockHash) } @@ -75,15 +75,15 @@ func (fm *finalityManager) calculateAndStageFinalityPoint(blockHash *externalapi } func (fm *finalityManager) calculateFinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - log.Tracef("calculateFinalityPoint start") - defer log.Tracef("calculateFinalityPoint end") + log.Debugf("calculateFinalityPoint start") + defer log.Debugf("calculateFinalityPoint end") ghostdagData, err := fm.ghostdagDataStore.Get(fm.databaseContext, blockHash) if err != nil { return nil, err } if ghostdagData.BlueScore() < fm.finalityDepth { - log.Tracef("%s blue score lower then finality depth - returning genesis as finality point", blockHash) + log.Debugf("%s blue score lower then finality depth - returning genesis as finality point", blockHash) return fm.genesisHash, nil } @@ -97,7 +97,7 @@ func (fm *finalityManager) calculateFinalityPoint(blockHash *externalapi.DomainH return nil, err } requiredBlueScore := ghostdagData.BlueScore() - fm.finalityDepth - log.Tracef("%s's finality point is the one having the highest blue score lower then %d", blockHash, requiredBlueScore) + log.Debugf("%s's finality point is the one having the highest blue score lower then %d", blockHash, requiredBlueScore) var next *externalapi.DomainHash for { @@ -110,7 +110,7 @@ func (fm *finalityManager) calculateFinalityPoint(blockHash *externalapi.DomainH return nil, err } if nextGHOSTDAGData.BlueScore() >= requiredBlueScore { - log.Tracef("%s's finality point is %s", blockHash, current) + log.Debugf("%s's finality point is %s", blockHash, current) return current, nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/connection_loops.go b/infrastructure/network/netadapter/server/grpcserver/connection_loops.go index d55a8da65..7cc40c0e0 100644 --- a/infrastructure/network/netadapter/server/grpcserver/connection_loops.go +++ b/infrastructure/network/netadapter/server/grpcserver/connection_loops.go @@ -1,15 +1,14 @@ package grpcserver import ( + "github.com/davecgh/go-spew/spew" + "github.com/kaspanet/kaspad/infrastructure/logger" "io" "time" routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" - "github.com/davecgh/go-spew/spew" - "github.com/kaspanet/kaspad/infrastructure/logger" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver/protowire" ) From 48278bd1c0aa1abedd2eda6d3e9efad89cbcf955 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 29 Dec 2020 10:36:18 +0200 Subject: [PATCH 175/351] Slightly improve the performance of antiPastHashesBetween. (#1312) --- .../flows/blockrelay/handle_request_headers.go | 2 +- domain/consensus/processes/syncmanager/antipast.go | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go index 175f098e0..0559bba60 100644 --- a/app/protocol/flows/blockrelay/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -42,7 +42,7 @@ func (flow *handleRequestBlocksFlow) start() error { // We expect that if the other peer did not receive all the headers // they requested, they'd re-request a block locator and re-request // headers with a higher lowHash - const maxBlueScoreDifference = 1 << 12 + const maxBlueScoreDifference = 1 << 10 blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference) if err != nil { return err diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index da67ff663..44c85968e 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -35,13 +35,19 @@ 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 highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore()+1 > maxBlueScoreDifference { - highHash = highBlockGHOSTDAGData.SelectedParent() - var err error + iterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, lowHash) + if err != nil { + return nil, err + } + for iterator.Next() { + highHash = iterator.Get() highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHash) if err != nil { return nil, err } + if highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore()+1 > maxBlueScoreDifference { + break + } } } From 02d5fb29cf653ffcba33f16afe1c62d23665d3b4 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 29 Dec 2020 12:07:05 +0200 Subject: [PATCH 176/351] Fix notifyVirtualSelectedParentBlueScoreChanged to show the selected tip blue score instead of the virtual's (#1309) * Fix notifyVirtualSelectedParentBlueScoreChanged to show the selected tip blue score instead of the virtual's * Fix ShouldMine() to fetch selected tip header --- app/protocol/flowcontext/sync_rate.go | 11 ++++++++--- app/rpc/manager.go | 10 ++++++++-- app/rpc/rpchandlers/get_selected_tip_hash.go | 4 +--- domain/consensus/consensus.go | 4 ++-- domain/consensus/finality_test.go | 16 ++++++++-------- domain/consensus/model/externalapi/consensus.go | 2 +- .../virtual_selected_parent_blue_score_test.go | 4 ++-- 7 files changed, 30 insertions(+), 21 deletions(-) diff --git a/app/protocol/flowcontext/sync_rate.go b/app/protocol/flowcontext/sync_rate.go index f581c520a..b96036c60 100644 --- a/app/protocol/flowcontext/sync_rate.go +++ b/app/protocol/flowcontext/sync_rate.go @@ -65,14 +65,19 @@ func (f *FlowContext) ShouldMine() (bool, error) { return false, err } + virtualSelectedParentHeader, err := f.domain.Consensus().GetBlockHeader(virtualSelectedParent) + if err != nil { + return false, err + } + now := mstime.Now().UnixMilliseconds() - if now-virtualSelectedParent.Header.TimeInMilliseconds < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { + if now-virtualSelectedParentHeader.TimeInMilliseconds < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true", - virtualSelectedParent.Header.TimeInMilliseconds) + virtualSelectedParentHeader.TimeInMilliseconds) return true, nil } log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false", - virtualSelectedParent.Header.TimeInMilliseconds) + virtualSelectedParentHeader.TimeInMilliseconds) return false, nil } diff --git a/app/rpc/manager.go b/app/rpc/manager.go index 403061282..1d050ad69 100644 --- a/app/rpc/manager.go +++ b/app/rpc/manager.go @@ -106,11 +106,17 @@ func (m *Manager) notifyVirtualSelectedParentBlueScoreChanged() error { onEnd := logger.LogAndMeasureExecutionTime(log, "RPCManager.NotifyVirtualSelectedParentBlueScoreChanged") defer onEnd() - virtualInfo, err := m.context.Domain.Consensus().GetVirtualInfo() + virtualSelectedParent, err := m.context.Domain.Consensus().GetVirtualSelectedParent() if err != nil { return err } - notification := appmessage.NewVirtualSelectedParentBlueScoreChangedNotificationMessage(virtualInfo.BlueScore) + + blockInfo, err := m.context.Domain.Consensus().GetBlockInfo(virtualSelectedParent) + if err != nil { + return err + } + + notification := appmessage.NewVirtualSelectedParentBlueScoreChangedNotificationMessage(blockInfo.BlueScore) return m.context.NotificationManager.NotifyVirtualSelectedParentBlueScoreChanged(notification) } diff --git a/app/rpc/rpchandlers/get_selected_tip_hash.go b/app/rpc/rpchandlers/get_selected_tip_hash.go index 3831b98d0..8bdf4b8f9 100644 --- a/app/rpc/rpchandlers/get_selected_tip_hash.go +++ b/app/rpc/rpchandlers/get_selected_tip_hash.go @@ -3,7 +3,6 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -14,8 +13,7 @@ func HandleGetSelectedTipHash(context *rpccontext.Context, _ *router.Router, _ a return nil, err } - response := appmessage.NewGetSelectedTipHashResponseMessage( - consensushashing.BlockHash(selectedTip).String()) + response := appmessage.NewGetSelectedTipHashResponseMessage(selectedTip.String()) return response, nil } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 97bd4e97c..7bff7e698 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -229,7 +229,7 @@ func (s *consensus) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.D return s.blockProcessor.ValidateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet) } -func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) { +func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainHash, error) { s.lock.Lock() defer s.lock.Unlock() @@ -237,7 +237,7 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) if err != nil { return nil, err } - return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent()) + return virtualGHOSTDAGData.SelectedParent(), nil } func (s *consensus) Tips() ([]*externalapi.DomainHash, error) { diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index 4fc06b148..a428127c7 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -107,7 +107,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) } - if !consensushashing.BlockHash(selectedTip).Equal(sideChainTipHash) { + if !selectedTip.Equal(sideChainTipHash) { t.Fatalf("Overtaking block in side-chain is not selectedTip") } @@ -145,7 +145,7 @@ func TestFinality(t *testing.T) { if err != nil { t.Fatalf("TestFinality: Failed getting virtual selectedParent: %v", err) } - selectedTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), consensushashing.BlockHash(selectedTip)) + selectedTipGhostDagData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), selectedTip) if err != nil { t.Fatalf("TestFinality: Failed getting the ghost dag data of the selected tip: %v", err) } @@ -329,8 +329,8 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if !consensushashing.BlockHash(virtualSelectedParent).Equal(consensushashing.BlockHash(pointAtBlueKosherizing)) { - t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(pointAtBlueKosherizing), consensushashing.BlockHash(virtualSelectedParent)) + if !virtualSelectedParent.Equal(consensushashing.BlockHash(pointAtBlueKosherizing)) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(pointAtBlueKosherizing), virtualSelectedParent) } // Now let's make the kosherizing block red and try to merge again @@ -346,8 +346,8 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if !consensushashing.BlockHash(virtualSelectedParent).Equal(tip) { - t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, consensushashing.BlockHash(virtualSelectedParent)) + if !virtualSelectedParent.Equal(tip) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", tip, virtualSelectedParent) } virtualGhotDagData, err = consensusReal.GHOSTDAGDataStore().Get(consensusReal.DatabaseContext(), model.VirtualBlockHash) @@ -382,8 +382,8 @@ func TestBoundedMergeDepth(t *testing.T) { t.Fatalf("TestBoundedMergeDepth: Failed getting the virtual selected parent %v", err) } - if !consensushashing.BlockHash(virtualSelectedParent).Equal(consensushashing.BlockHash(transitiveBlueKosherizing)) { - t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(transitiveBlueKosherizing), consensushashing.BlockHash(virtualSelectedParent)) + if !virtualSelectedParent.Equal(consensushashing.BlockHash(transitiveBlueKosherizing)) { + t.Fatalf("TestBoundedMergeDepth: Expected %s to be the selectedTip but found %s instead", consensushashing.BlockHash(transitiveBlueKosherizing), virtualSelectedParent) } // Lets validate the status of all the interesting blocks diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 7df5b99e7..7ac38e21f 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -16,7 +16,7 @@ type Consensus interface { GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error) PruningPoint() (*DomainHash, error) ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error - GetVirtualSelectedParent() (*DomainBlock, error) + GetVirtualSelectedParent() (*DomainHash, error) CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error) GetSyncInfo() (*SyncInfo, error) diff --git a/testing/integration/virtual_selected_parent_blue_score_test.go b/testing/integration/virtual_selected_parent_blue_score_test.go index b005da809..f3ce0969e 100644 --- a/testing/integration/virtual_selected_parent_blue_score_test.go +++ b/testing/integration/virtual_selected_parent_blue_score_test.go @@ -44,9 +44,9 @@ func TestVirtualSelectedParentBlueScore(t *testing.T) { for i := 0; i < blockAmountToMine; i++ { mineNextBlock(t, kaspad) notification := <-onVirtualSelectedParentBlueScoreChangedChan - if notification.VirtualSelectedParentBlueScore != 2+uint64(i) { + if notification.VirtualSelectedParentBlueScore != 1+uint64(i) { t.Fatalf("Unexpected virtual selected parent blue score. Want: %d, got: %d", - 2+uint64(i), notification.VirtualSelectedParentBlueScore) + 1+uint64(i), notification.VirtualSelectedParentBlueScore) } } From c10a0876965099a3241ec8f0da6b586472a902f3 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 29 Dec 2020 12:07:45 +0200 Subject: [PATCH 177/351] Remove virtualDiffParents that aren't in V.Past or in P.Future (#1310) --- .../pruningmanager/pruningmanager.go | 64 ++++++++++++++----- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index f595745a2..dee42b5bf 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -184,6 +184,27 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { return nil } +func (pm *pruningManager) isInPruningFutureOrInVirtualPast(block *externalapi.DomainHash, pruningPoint *externalapi.DomainHash, virtualParents []*externalapi.DomainHash) (bool, error) { + hasPruningPointInPast, err := pm.dagTopologyManager.IsAncestorOf(pruningPoint, block) + if err != nil { + return false, err + } + if hasPruningPointInPast { + return true, nil + } + // Because virtual doesn't have reachability data, we need to check reachability + // using it parents. + isInVirtualPast, err := pm.dagTopologyManager.IsAncestorOfAny(block, virtualParents) + if err != nil { + return false, err + } + if isInVirtualPast { + return true, nil + } + + return false, nil +} + func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) error { onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.deletePastBlocks") defer onEnd() @@ -196,30 +217,21 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) if err != nil { return err } + virtualParents, err := pm.dagTopologyManager.Parents(model.VirtualBlockHash) + if err != nil { + return err + } for _, tip := range dagTips { - hasPruningPointInPast, err := pm.dagTopologyManager.IsAncestorOf(pruningPoint, tip) + isInPruningFutureOrInVirtualPast, err := pm.isInPruningFutureOrInVirtualPast(tip, pruningPoint, virtualParents) if err != nil { return err } - if !hasPruningPointInPast { - virtualParents, err := pm.dagTopologyManager.Parents(model.VirtualBlockHash) + if !isInPruningFutureOrInVirtualPast { + // Add them to the queue so they and their past will be pruned + err := queue.Push(tip) if err != nil { return err } - - // Because virtual doesn't have reachability data, we need to check reachability - // using it parents. - isInVirtualPast, err := pm.dagTopologyManager.IsAncestorOfAny(tip, virtualParents) - if err != nil { - return err - } - if !isInVirtualPast { - // Add them to the queue so they and their past will be pruned - err := queue.Push(tip) - if err != nil { - return err - } - } } } @@ -261,6 +273,24 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) } } } + + // Delete virtual diff parents that are in PruningPoint's Anticone and not in Virtual's Past + virtualDiffParents, err := pm.consensusStateStore.VirtualDiffParents(pm.databaseContext) + if err != nil { + return err + } + validVirtualDiffParents := make([]*externalapi.DomainHash, 0, len(virtualParents)) + for _, parent := range virtualDiffParents { + isInPruningFutureOrInVirtualPast, err := pm.isInPruningFutureOrInVirtualPast(parent, pruningPoint, virtualParents) + if err != nil { + return err + } + if isInPruningFutureOrInVirtualPast { + validVirtualDiffParents = append(validVirtualDiffParents, parent) + } + } + pm.consensusStateStore.StageVirtualDiffParents(validVirtualDiffParents) + return nil } From 49b6cc603856cab283b3ddb62fe8301234bf5aed Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 29 Dec 2020 13:55:17 +0200 Subject: [PATCH 178/351] Add mutable and immutable header interfaces (#1305) * Add mutable and immutable header interfaces * Fix ShouldMine() * Remove false comment * Fix Equal signature * Fix Equal implementation --- app/appmessage/domainconverters.go | 45 +-- app/protocol/blocklogger/blocklogger.go | 2 +- app/protocol/flowcontext/orphans.go | 6 +- app/protocol/flowcontext/sync_rate.go | 6 +- app/rpc/rpccontext/verbosedata.go | 29 +- cmd/kaspaminer/mineloop.go | 10 +- domain/consensus/consensus.go | 2 +- domain/consensus/consensus_test.go | 4 +- .../database/serialization/blockheader.go | 45 +-- .../blockheaderstore/blockheaderstore.go | 26 +- domain/consensus/model/externalapi/block.go | 94 ++----- .../externalapi/block_equal_clone_test.go | 260 +++++++++--------- .../consensus/model/externalapi/consensus.go | 2 +- .../consensus/model/externalapi/equal_test.go | 241 ---------------- ...terface_datastructures_blockheaderstore.go | 6 +- domain/consensus/model/pow/pow.go | 16 +- .../processes/blockbuilder/block_builder.go | 22 +- .../blockbuilder/test_block_builder.go | 23 +- .../blockvalidator/block_body_in_context.go | 6 +- .../blockvalidator/block_body_in_isolation.go | 4 +- .../block_body_in_isolation_test.go | 61 ++-- .../blockvalidator/block_header_in_context.go | 14 +- .../block_header_in_context_test.go | 47 ++-- .../block_header_in_isolation.go | 12 +- .../blockvalidator/header_estimated_size.go | 6 +- .../processes/blockvalidator/proof_of_work.go | 20 +- .../calculate_past_utxo_test.go | 4 +- .../update_pruning_utxo_set.go | 6 +- .../verify_and_build_utxo.go | 8 +- .../difficultymanager/blockwindow.go | 4 +- .../difficultymanager/difficultymanager.go | 2 +- .../difficultymanager_test.go | 40 +-- .../processes/ghostdag2/ghostdagimpl.go | 2 +- .../processes/ghostdagmanager/ghostdag.go | 2 +- .../ghostdagmanager/ghostdag_test.go | 32 ++- .../pastmediantimemanager.go | 4 +- .../pastmediantimemanager_test.go | 8 +- .../utils/blockheader/blockheader.go | 146 ++++++++++ .../utils/blockheader/blockheader_test.go | 205 ++++++++++++++ .../consensus/utils/consensushashing/block.go | 16 +- domain/consensus/utils/mining/solve.go | 9 +- domain/dagconfig/genesis.go | 81 +++--- .../blocktemplatebuilder.go | 2 +- infrastructure/config/network.go | 2 +- testing/integration/mining_test.go | 8 +- 45 files changed, 844 insertions(+), 746 deletions(-) delete mode 100644 domain/consensus/model/externalapi/equal_test.go create mode 100644 domain/consensus/utils/blockheader/blockheader.go create mode 100644 domain/consensus/utils/blockheader/blockheader_test.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 46f52f9af..7496623d4 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -2,6 +2,7 @@ package appmessage import ( "encoding/hex" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" @@ -21,17 +22,17 @@ func DomainBlockToMsgBlock(domainBlock *externalapi.DomainBlock) *MsgBlock { } } -// DomainBlockHeaderToBlockHeader converts an externalapi.DomainBlockHeader to MsgBlockHeader -func DomainBlockHeaderToBlockHeader(domainBlockHeader *externalapi.DomainBlockHeader) *MsgBlockHeader { +// DomainBlockHeaderToBlockHeader converts an externalapi.BlockHeader to MsgBlockHeader +func DomainBlockHeaderToBlockHeader(domainBlockHeader externalapi.BlockHeader) *MsgBlockHeader { return &MsgBlockHeader{ - Version: domainBlockHeader.Version, - ParentHashes: domainBlockHeader.ParentHashes, - HashMerkleRoot: &domainBlockHeader.HashMerkleRoot, - AcceptedIDMerkleRoot: &domainBlockHeader.AcceptedIDMerkleRoot, - UTXOCommitment: &domainBlockHeader.UTXOCommitment, - Timestamp: mstime.UnixMilliseconds(domainBlockHeader.TimeInMilliseconds), - Bits: domainBlockHeader.Bits, - Nonce: domainBlockHeader.Nonce, + Version: domainBlockHeader.Version(), + ParentHashes: domainBlockHeader.ParentHashes(), + HashMerkleRoot: domainBlockHeader.HashMerkleRoot(), + AcceptedIDMerkleRoot: domainBlockHeader.AcceptedIDMerkleRoot(), + UTXOCommitment: domainBlockHeader.UTXOCommitment(), + Timestamp: mstime.UnixMilliseconds(domainBlockHeader.TimeInMilliseconds()), + Bits: domainBlockHeader.Bits(), + Nonce: domainBlockHeader.Nonce(), } } @@ -48,18 +49,18 @@ func MsgBlockToDomainBlock(msgBlock *MsgBlock) *externalapi.DomainBlock { } } -// BlockHeaderToDomainBlockHeader converts a MsgBlockHeader to externalapi.DomainBlockHeader -func BlockHeaderToDomainBlockHeader(blockHeader *MsgBlockHeader) *externalapi.DomainBlockHeader { - return &externalapi.DomainBlockHeader{ - Version: blockHeader.Version, - ParentHashes: blockHeader.ParentHashes, - HashMerkleRoot: *blockHeader.HashMerkleRoot, - AcceptedIDMerkleRoot: *blockHeader.AcceptedIDMerkleRoot, - UTXOCommitment: *blockHeader.UTXOCommitment, - TimeInMilliseconds: blockHeader.Timestamp.UnixMilliseconds(), - Bits: blockHeader.Bits, - Nonce: blockHeader.Nonce, - } +// BlockHeaderToDomainBlockHeader converts a MsgBlockHeader to externalapi.BlockHeader +func BlockHeaderToDomainBlockHeader(blockHeader *MsgBlockHeader) externalapi.BlockHeader { + return blockheader.NewImmutableBlockHeader( + blockHeader.Version, + blockHeader.ParentHashes, + blockHeader.HashMerkleRoot, + blockHeader.AcceptedIDMerkleRoot, + blockHeader.UTXOCommitment, + blockHeader.Timestamp.UnixMilliseconds(), + blockHeader.Bits, + blockHeader.Nonce, + ) } // DomainTransactionToMsgTx converts an externalapi.DomainTransaction into an MsgTx diff --git a/app/protocol/blocklogger/blocklogger.go b/app/protocol/blocklogger/blocklogger.go index 81713aba5..d17001b06 100644 --- a/app/protocol/blocklogger/blocklogger.go +++ b/app/protocol/blocklogger/blocklogger.go @@ -50,7 +50,7 @@ func LogBlock(block *externalapi.DomainBlock) { log.Infof("Processed %d %s in the last %s (%d %s, %s)", receivedLogBlocks, blockStr, tDuration, receivedLogTx, - txStr, mstime.UnixMilliseconds(block.Header.TimeInMilliseconds)) + txStr, mstime.UnixMilliseconds(block.Header.TimeInMilliseconds())) receivedLogBlocks = 0 receivedLogTx = 0 diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 9c563ba2e..f655c4bcf 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -71,10 +71,10 @@ func (f *FlowContext) UnorphanBlocks(rootBlock *externalapi.DomainBlock) ([]*Uno orphanBlock := f.orphans[orphanHash] log.Debugf("Considering to unorphan block %s with parents %s", - orphanHash, orphanBlock.Header.ParentHashes) + orphanHash, orphanBlock.Header.ParentHashes()) canBeUnorphaned := true - for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes { + for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes() { orphanBlockParentInfo, err := f.domain.Consensus().GetBlockInfo(orphanBlockParentHash) if err != nil { return nil, err @@ -131,7 +131,7 @@ func (f *FlowContext) addChildOrphansToProcessQueue(blockHash *externalapi.Domai func (f *FlowContext) findChildOrphansOfBlock(blockHash *externalapi.DomainHash) []externalapi.DomainHash { var childOrphans []externalapi.DomainHash for orphanHash, orphanBlock := range f.orphans { - for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes { + for _, orphanBlockParentHash := range orphanBlock.Header.ParentHashes() { if orphanBlockParentHash.Equal(blockHash) { childOrphans = append(childOrphans, orphanHash) break diff --git a/app/protocol/flowcontext/sync_rate.go b/app/protocol/flowcontext/sync_rate.go index b96036c60..b7c0f2d2d 100644 --- a/app/protocol/flowcontext/sync_rate.go +++ b/app/protocol/flowcontext/sync_rate.go @@ -71,13 +71,13 @@ func (f *FlowContext) ShouldMine() (bool, error) { } now := mstime.Now().UnixMilliseconds() - if now-virtualSelectedParentHeader.TimeInMilliseconds < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { + if now-virtualSelectedParentHeader.TimeInMilliseconds() < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true", - virtualSelectedParentHeader.TimeInMilliseconds) + virtualSelectedParentHeader.TimeInMilliseconds()) return true, nil } log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false", - virtualSelectedParentHeader.TimeInMilliseconds) + virtualSelectedParentHeader.TimeInMilliseconds()) return false, nil } diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index b18738d7f..574e9ee9e 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -23,8 +23,7 @@ import ( ) // BuildBlockVerboseData builds a BlockVerboseData from the given block. -// This method must be called with the DAG lock held for reads -func (ctx *Context) BuildBlockVerboseData(blockHeader *externalapi.DomainBlockHeader, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { +func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { hash := consensushashing.HeaderHash(blockHeader) blockInfo, err := ctx.Domain.Consensus().GetBlockInfo(hash) @@ -33,16 +32,16 @@ func (ctx *Context) BuildBlockVerboseData(blockHeader *externalapi.DomainBlockHe } result := &appmessage.BlockVerboseData{ Hash: hash.String(), - Version: blockHeader.Version, - VersionHex: fmt.Sprintf("%08x", blockHeader.Version), - HashMerkleRoot: blockHeader.HashMerkleRoot.String(), - AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot.String(), - UTXOCommitment: blockHeader.UTXOCommitment.String(), - ParentHashes: hashes.ToStrings(blockHeader.ParentHashes), - Nonce: blockHeader.Nonce, - Time: blockHeader.TimeInMilliseconds, - Bits: strconv.FormatInt(int64(blockHeader.Bits), 16), - Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits, ctx.Config.ActiveNetParams), + Version: blockHeader.Version(), + VersionHex: fmt.Sprintf("%08x", blockHeader.Version()), + HashMerkleRoot: blockHeader.HashMerkleRoot().String(), + AcceptedIDMerkleRoot: blockHeader.AcceptedIDMerkleRoot().String(), + UTXOCommitment: blockHeader.UTXOCommitment().String(), + ParentHashes: hashes.ToStrings(blockHeader.ParentHashes()), + Nonce: blockHeader.Nonce(), + Time: blockHeader.TimeInMilliseconds(), + Bits: strconv.FormatInt(int64(blockHeader.Bits()), 16), + Difficulty: ctx.GetDifficultyRatio(blockHeader.Bits(), ctx.Config.ActiveNetParams), BlueScore: blockInfo.BlueScore, IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly, } @@ -97,7 +96,7 @@ func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) fl // BuildTransactionVerboseData builds a TransactionVerboseData from // the given parameters func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransaction, txID string, - blockHeader *externalapi.DomainBlockHeader, blockHash string) ( + blockHeader externalapi.BlockHeader, blockHash string) ( *appmessage.TransactionVerboseData, error) { var payloadHash string @@ -120,8 +119,8 @@ func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransactio } if blockHeader != nil { - txReply.Time = uint64(blockHeader.TimeInMilliseconds) - txReply.BlockTime = uint64(blockHeader.TimeInMilliseconds) + txReply.Time = uint64(blockHeader.TimeInMilliseconds()) + txReply.BlockTime = uint64(blockHeader.TimeInMilliseconds()) txReply.BlockHash = blockHash } diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 3d67bf67c..96d244d55 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -95,7 +95,7 @@ func mineNextBlock(client *minerClient, miningAddr util.Address, foundBlock chan func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error { blockHash := consensushashing.BlockHash(block) - log.Infof("Found block %s with parents %s. Submitting to %s", blockHash, block.Header.ParentHashes, client.Address()) + log.Infof("Found block %s with parents %s. Submitting to %s", blockHash, block.Header.ParentHashes(), client.Address()) err := client.SubmitBlock(block) if err != nil { @@ -105,16 +105,18 @@ func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error } func solveBlock(block *externalapi.DomainBlock, stopChan chan struct{}, foundBlock chan *externalapi.DomainBlock) { - targetDifficulty := util.CompactToBig(block.Header.Bits) + targetDifficulty := util.CompactToBig(block.Header.Bits()) + headerForMining := block.Header.ToMutable() initialNonce := random.Uint64() for i := initialNonce; i != initialNonce-1; i++ { select { case <-stopChan: return default: - block.Header.Nonce = i + headerForMining.SetNonce(i) atomic.AddUint64(&hashesTried, 1) - if pow.CheckProofOfWorkWithTarget(block.Header, targetDifficulty) { + if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { + block.Header = headerForMining.ToImmutable() foundBlock <- block return } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 7bff7e698..8a01b263a 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -103,7 +103,7 @@ func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.Do return s.blockStore.Block(s.databaseContext, blockHash) } -func (s *consensus) GetBlockHeader(blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { +func (s *consensus) GetBlockHeader(blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) { s.lock.Lock() defer s.lock.Unlock() diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index 021811a18..6632d1244 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -24,7 +24,9 @@ func TestConsensus_GetBlockInfo(t *testing.T) { if err != nil { t.Fatal(err) } - invalidBlock.Header.TimeInMilliseconds = 0 + newHeader := invalidBlock.Header.ToMutable() + newHeader.SetTimeInMilliseconds(0) + invalidBlock.Header = newHeader.ToImmutable() _, 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) diff --git a/domain/consensus/database/serialization/blockheader.go b/domain/consensus/database/serialization/blockheader.go index e8981daa7..5a1bce9ad 100644 --- a/domain/consensus/database/serialization/blockheader.go +++ b/domain/consensus/database/serialization/blockheader.go @@ -2,24 +2,25 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" ) -// DomainBlockHeaderToDbBlockHeader converts DomainBlockHeader to DbBlockHeader -func DomainBlockHeaderToDbBlockHeader(domainBlockHeader *externalapi.DomainBlockHeader) *DbBlockHeader { +// DomainBlockHeaderToDbBlockHeader converts BlockHeader to DbBlockHeader +func DomainBlockHeaderToDbBlockHeader(domainBlockHeader externalapi.BlockHeader) *DbBlockHeader { return &DbBlockHeader{ - Version: domainBlockHeader.Version, - ParentHashes: DomainHashesToDbHashes(domainBlockHeader.ParentHashes), - HashMerkleRoot: DomainHashToDbHash(&domainBlockHeader.HashMerkleRoot), - AcceptedIDMerkleRoot: DomainHashToDbHash(&domainBlockHeader.AcceptedIDMerkleRoot), - UtxoCommitment: DomainHashToDbHash(&domainBlockHeader.UTXOCommitment), - TimeInMilliseconds: domainBlockHeader.TimeInMilliseconds, - Bits: domainBlockHeader.Bits, - Nonce: domainBlockHeader.Nonce, + Version: domainBlockHeader.Version(), + ParentHashes: DomainHashesToDbHashes(domainBlockHeader.ParentHashes()), + HashMerkleRoot: DomainHashToDbHash(domainBlockHeader.HashMerkleRoot()), + AcceptedIDMerkleRoot: DomainHashToDbHash(domainBlockHeader.AcceptedIDMerkleRoot()), + UtxoCommitment: DomainHashToDbHash(domainBlockHeader.UTXOCommitment()), + TimeInMilliseconds: domainBlockHeader.TimeInMilliseconds(), + Bits: domainBlockHeader.Bits(), + Nonce: domainBlockHeader.Nonce(), } } -// DbBlockHeaderToDomainBlockHeader converts DbBlockHeader to DomainBlockHeader -func DbBlockHeaderToDomainBlockHeader(dbBlockHeader *DbBlockHeader) (*externalapi.DomainBlockHeader, error) { +// DbBlockHeaderToDomainBlockHeader converts DbBlockHeader to BlockHeader +func DbBlockHeaderToDomainBlockHeader(dbBlockHeader *DbBlockHeader) (externalapi.BlockHeader, error) { parentHashes, err := DbHashesToDomainHashes(dbBlockHeader.ParentHashes) if err != nil { return nil, err @@ -37,14 +38,14 @@ func DbBlockHeaderToDomainBlockHeader(dbBlockHeader *DbBlockHeader) (*externalap return nil, err } - return &externalapi.DomainBlockHeader{ - Version: dbBlockHeader.Version, - ParentHashes: parentHashes, - HashMerkleRoot: *hashMerkleRoot, - AcceptedIDMerkleRoot: *acceptedIDMerkleRoot, - UTXOCommitment: *utxoCommitment, - TimeInMilliseconds: dbBlockHeader.TimeInMilliseconds, - Bits: dbBlockHeader.Bits, - Nonce: dbBlockHeader.Nonce, - }, nil + return blockheader.NewImmutableBlockHeader( + dbBlockHeader.Version, + parentHashes, + hashMerkleRoot, + acceptedIDMerkleRoot, + utxoCommitment, + dbBlockHeader.TimeInMilliseconds, + dbBlockHeader.Bits, + dbBlockHeader.Nonce, + ), nil } diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index ce80f7078..e0169fecf 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -14,7 +14,7 @@ var countKey = dbkeys.MakeBucket().Key([]byte("block-headers-count")) // blockHeaderStore represents a store of blocks type blockHeaderStore struct { - staging map[externalapi.DomainHash]*externalapi.DomainBlockHeader + staging map[externalapi.DomainHash]externalapi.BlockHeader toDelete map[externalapi.DomainHash]struct{} cache *lrucache.LRUCache count uint64 @@ -23,7 +23,7 @@ type blockHeaderStore struct { // New instantiates a new BlockHeaderStore func New(dbContext model.DBReader, cacheSize int) (model.BlockHeaderStore, error) { blockHeaderStore := &blockHeaderStore{ - staging: make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader), + staging: make(map[externalapi.DomainHash]externalapi.BlockHeader), toDelete: make(map[externalapi.DomainHash]struct{}), cache: lrucache.New(cacheSize), } @@ -57,8 +57,8 @@ func (bhs *blockHeaderStore) initializeCount(dbContext model.DBReader) error { } // Stage stages the given block header for the given blockHash -func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) { - bhs.staging[*blockHash] = blockHeader.Clone() +func (bhs *blockHeaderStore) Stage(blockHash *externalapi.DomainHash, blockHeader externalapi.BlockHeader) { + bhs.staging[*blockHash] = blockHeader } func (bhs *blockHeaderStore) IsStaged() bool { @@ -66,7 +66,7 @@ func (bhs *blockHeaderStore) IsStaged() bool { } func (bhs *blockHeaderStore) Discard() { - bhs.staging = make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader) + bhs.staging = make(map[externalapi.DomainHash]externalapi.BlockHeader) bhs.toDelete = make(map[externalapi.DomainHash]struct{}) } @@ -101,13 +101,13 @@ func (bhs *blockHeaderStore) Commit(dbTx model.DBTransaction) error { } // BlockHeader gets the block header associated with the given blockHash -func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { +func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) { if header, ok := bhs.staging[*blockHash]; ok { - return header.Clone(), nil + return header, nil } if header, ok := bhs.cache.Get(blockHash); ok { - return header.(*externalapi.DomainBlockHeader).Clone(), nil + return header.(externalapi.BlockHeader), nil } headerBytes, err := dbContext.Get(bhs.hashAsKey(blockHash)) @@ -120,7 +120,7 @@ func (bhs *blockHeaderStore) BlockHeader(dbContext model.DBReader, blockHash *ex return nil, err } bhs.cache.Add(blockHash, header) - return header.Clone(), nil + return header, nil } // HasBlock returns whether a block header with a given hash exists in the store. @@ -142,8 +142,8 @@ func (bhs *blockHeaderStore) HasBlockHeader(dbContext model.DBReader, blockHash } // BlockHeaders gets the block headers associated with the given blockHashes -func (bhs *blockHeaderStore) BlockHeaders(dbContext model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) { - headers := make([]*externalapi.DomainBlockHeader, len(blockHashes)) +func (bhs *blockHeaderStore) BlockHeaders(dbContext model.DBReader, blockHashes []*externalapi.DomainHash) ([]externalapi.BlockHeader, error) { + headers := make([]externalapi.BlockHeader, len(blockHashes)) for i, hash := range blockHashes { var err error headers[i], err = bhs.BlockHeader(dbContext, hash) @@ -167,12 +167,12 @@ func (bhs *blockHeaderStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey return bucket.Key(hash.ByteSlice()) } -func (bhs *blockHeaderStore) serializeHeader(header *externalapi.DomainBlockHeader) ([]byte, error) { +func (bhs *blockHeaderStore) serializeHeader(header externalapi.BlockHeader) ([]byte, error) { dbBlockHeader := serialization.DomainBlockHeaderToDbBlockHeader(header) return proto.Marshal(dbBlockHeader) } -func (bhs *blockHeaderStore) deserializeHeader(headerBytes []byte) (*externalapi.DomainBlockHeader, error) { +func (bhs *blockHeaderStore) deserializeHeader(headerBytes []byte) (externalapi.BlockHeader, error) { dbBlockHeader := &serialization.DbBlockHeader{} err := proto.Unmarshal(headerBytes, dbBlockHeader) if err != nil { diff --git a/domain/consensus/model/externalapi/block.go b/domain/consensus/model/externalapi/block.go index 1ff82a4cb..c0244e6a1 100644 --- a/domain/consensus/model/externalapi/block.go +++ b/domain/consensus/model/externalapi/block.go @@ -2,7 +2,7 @@ package externalapi // DomainBlock represents a Kaspa block type DomainBlock struct { - Header *DomainBlockHeader + Header BlockHeader Transactions []*DomainTransaction } @@ -14,14 +14,14 @@ func (block *DomainBlock) Clone() *DomainBlock { } return &DomainBlock{ - Header: block.Header.Clone(), + Header: block.Header, Transactions: transactionClone, } } // If this doesn't compile, it means the type definition has been changed, so it's // an indication to update Equal and Clone accordingly. -var _ = DomainBlock{&DomainBlockHeader{}, []*DomainTransaction{}} +var _ = DomainBlock{nil, []*DomainTransaction{}} // Equal returns whether block equals to other func (block *DomainBlock) Equal(other *DomainBlock) bool { @@ -46,74 +46,30 @@ func (block *DomainBlock) Equal(other *DomainBlock) bool { return true } -// DomainBlockHeader represents the header part of a Kaspa block -type DomainBlockHeader struct { - Version int32 - ParentHashes []*DomainHash - HashMerkleRoot DomainHash - AcceptedIDMerkleRoot DomainHash - UTXOCommitment DomainHash - TimeInMilliseconds int64 - Bits uint32 - Nonce uint64 +// BlockHeader represents an immutable block header. +type BlockHeader interface { + BaseBlockHeader + ToMutable() MutableBlockHeader } -// Clone returns a clone of DomainBlockHeader -func (header *DomainBlockHeader) Clone() *DomainBlockHeader { - return &DomainBlockHeader{ - Version: header.Version, - ParentHashes: CloneHashes(header.ParentHashes), - HashMerkleRoot: header.HashMerkleRoot, - AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot, - UTXOCommitment: header.UTXOCommitment, - TimeInMilliseconds: header.TimeInMilliseconds, - Bits: header.Bits, - Nonce: header.Nonce, - } +// BaseBlockHeader represents the header part of a Kaspa block +type BaseBlockHeader interface { + Version() int32 + ParentHashes() []*DomainHash + HashMerkleRoot() *DomainHash + AcceptedIDMerkleRoot() *DomainHash + UTXOCommitment() *DomainHash + TimeInMilliseconds() int64 + Bits() uint32 + Nonce() uint64 + Equal(other BaseBlockHeader) bool } -// If this doesn't compile, it means the type definition has been changed, so it's -// an indication to update Equal and Clone accordingly. -var _ = &DomainBlockHeader{0, []*DomainHash{}, DomainHash{}, - DomainHash{}, DomainHash{}, 0, 0, 0} - -// Equal returns whether header equals to other -func (header *DomainBlockHeader) Equal(other *DomainBlockHeader) bool { - if header == nil || other == nil { - return header == other - } - - if header.Version != other.Version { - return false - } - - if !HashesEqual(header.ParentHashes, other.ParentHashes) { - return false - } - - if !header.HashMerkleRoot.Equal(&other.HashMerkleRoot) { - return false - } - - if !header.AcceptedIDMerkleRoot.Equal(&other.AcceptedIDMerkleRoot) { - return false - } - - if !header.UTXOCommitment.Equal(&other.UTXOCommitment) { - return false - } - - if header.TimeInMilliseconds != other.TimeInMilliseconds { - return false - } - - if header.Bits != other.Bits { - return false - } - - if header.Nonce != other.Nonce { - return false - } - - return true +// MutableBlockHeader represents a block header that can be mutated, but only +// the fields that are relevant to mining (Nonce and TimeInMilliseconds). +type MutableBlockHeader interface { + BaseBlockHeader + ToImmutable() BlockHeader + SetNonce(nonce uint64) + SetTimeInMilliseconds(timeInMilliseconds int64) } diff --git a/domain/consensus/model/externalapi/block_equal_clone_test.go b/domain/consensus/model/externalapi/block_equal_clone_test.go index 35dd50308..9ef4890c0 100644 --- a/domain/consensus/model/externalapi/block_equal_clone_test.go +++ b/domain/consensus/model/externalapi/block_equal_clone_test.go @@ -1,30 +1,32 @@ -package externalapi +package externalapi_test import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "reflect" "testing" ) type blockToCompare struct { - block *DomainBlock + block *externalapi.DomainBlock expectedResult bool } type TestBlockStruct struct { - baseBlock *DomainBlock + baseBlock *externalapi.DomainBlock blocksToCompareTo []blockToCompare } -func initTestBaseTransactions() []*DomainTransaction { +func initTestBaseTransactions() []*externalapi.DomainTransaction { - testTx := []*DomainTransaction{{ + testTx := []*externalapi.DomainTransaction{{ Version: 1, - Inputs: []*DomainTransactionInput{}, - Outputs: []*DomainTransactionOutput{}, + Inputs: []*externalapi.DomainTransactionInput{}, + Outputs: []*externalapi.DomainTransactionOutput{}, LockTime: 1, - SubnetworkID: DomainSubnetworkID{0x01}, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -32,7 +34,7 @@ func initTestBaseTransactions() []*DomainTransaction { Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -41,16 +43,16 @@ func initTestBaseTransactions() []*DomainTransaction { return testTx } -func initTestAnotherTransactions() []*DomainTransaction { +func initTestAnotherTransactions() []*externalapi.DomainTransaction { - testTx := []*DomainTransaction{{ + testTx := []*externalapi.DomainTransaction{{ Version: 1, - Inputs: []*DomainTransactionInput{}, - Outputs: []*DomainTransactionOutput{}, + Inputs: []*externalapi.DomainTransactionInput{}, + Outputs: []*externalapi.DomainTransactionOutput{}, LockTime: 1, - SubnetworkID: DomainSubnetworkID{0x01}, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -58,7 +60,7 @@ func initTestAnotherTransactions() []*DomainTransaction { Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -67,16 +69,16 @@ func initTestAnotherTransactions() []*DomainTransaction { return testTx } -func initTestTwoTransactions() []*DomainTransaction { +func initTestTwoTransactions() []*externalapi.DomainTransaction { - testTx := []*DomainTransaction{{ + testTx := []*externalapi.DomainTransaction{{ Version: 1, - Inputs: []*DomainTransactionInput{}, - Outputs: []*DomainTransactionOutput{}, + Inputs: []*externalapi.DomainTransactionInput{}, + Outputs: []*externalapi.DomainTransactionOutput{}, LockTime: 1, - SubnetworkID: DomainSubnetworkID{0x01}, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -84,19 +86,19 @@ func initTestTwoTransactions() []*DomainTransaction { Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), }, { Version: 1, - Inputs: []*DomainTransactionInput{}, - Outputs: []*DomainTransactionOutput{}, + Inputs: []*externalapi.DomainTransactionInput{}, + Outputs: []*externalapi.DomainTransactionOutput{}, LockTime: 1, - SubnetworkID: DomainSubnetworkID{0x01}, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, - PayloadHash: *NewDomainHashFromByteArray(&[DomainHashSize]byte{ + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -104,7 +106,7 @@ func initTestTwoTransactions() []*DomainTransaction { Payload: []byte{0x01}, Fee: 0, Mass: 1, - ID: NewDomainTransactionIDFromByteArray(&[DomainHashSize]byte{ + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -113,34 +115,34 @@ func initTestTwoTransactions() []*DomainTransaction { return testTx } -func initTestBlockStructsForClone() []*DomainBlock { +func initTestBlockStructsForClone() []*externalapi.DomainBlock { - tests := []*DomainBlock{ + tests := []*externalapi.DomainBlock{ { - &DomainBlockHeader{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), 4, 5, 6, - }, + ), initTestBaseTransactions(), }, { - &DomainBlockHeader{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + []*externalapi.DomainHash{}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), 4, 5, 6, - }, + ), initTestBaseTransactions(), }, } @@ -158,33 +160,33 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { expectedResult: true, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), 4, 5, 6, - }, + ), initTestBaseTransactions()}, expectedResult: false, }, }, }, { - baseBlock: &DomainBlock{ - &DomainBlockHeader{ + baseBlock: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestBaseTransactions(), }, blocksToCompareTo: []blockToCompare{ @@ -193,155 +195,155 @@ func initTestBlockStructsForEqual() *[]TestBlockStruct { expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestAnotherTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestBaseTransactions(), }, expectedResult: true, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{ - NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), }, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestBaseTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{100})}, // Changed - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100})}, // Changed + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestTwoTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), // Changed - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100}), // Changed + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestBaseTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), // Changed - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100}), // Changed + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 7, - }, + ), initTestBaseTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), // Changed + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100}), // Changed 5, 6, 7, - }, + ), initTestBaseTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 100, // Changed 6, 7, - }, + ), initTestBaseTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 100, // Changed 7, - }, + ), initTestBaseTransactions(), }, expectedResult: false, }, { - block: &DomainBlock{ - &DomainBlockHeader{ + block: &externalapi.DomainBlock{ + blockheader.NewImmutableBlockHeader( 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), 5, 6, 100, // Changed - }, + ), initTestBaseTransactions(), }, expectedResult: false, diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 7ac38e21f..45ea17e59 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -7,7 +7,7 @@ type Consensus interface { ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error GetBlock(blockHash *DomainHash) (*DomainBlock, error) - GetBlockHeader(blockHash *DomainHash) (*DomainBlockHeader, error) + GetBlockHeader(blockHash *DomainHash) (BlockHeader, error) GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error) GetBlockAcceptanceData(blockHash *DomainHash) (AcceptanceData, error) diff --git a/domain/consensus/model/externalapi/equal_test.go b/domain/consensus/model/externalapi/equal_test.go deleted file mode 100644 index cc4797a0c..000000000 --- a/domain/consensus/model/externalapi/equal_test.go +++ /dev/null @@ -1,241 +0,0 @@ -package externalapi - -import ( - "reflect" - "testing" -) - -func TestDomainBlockHeader_Equal(t *testing.T) { - type headerToCompare struct { - header *DomainBlockHeader - expectedResult bool - } - tests := []struct { - baseHeader *DomainBlockHeader - headersToCompareTo []headerToCompare - }{ - { - baseHeader: nil, - headersToCompareTo: []headerToCompare{ - { - header: nil, - expectedResult: true, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - 4, - 5, - 6, - }, - expectedResult: false, - }, - }, - }, - { - baseHeader: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - headersToCompareTo: []headerToCompare{ - { - header: nil, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - expectedResult: true, - }, - { - header: &DomainBlockHeader{ - 100, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - // []*DomainHash{{1}, {2}}, - []*DomainHash{ - NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - NewDomainHashFromByteArray(&[DomainHashSize]byte{2})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{100})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{100}), - 5, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 100, - 6, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 100, - 7, - }, - expectedResult: false, - }, - { - header: &DomainBlockHeader{ - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{1})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{4}), - 5, - 6, - 100, - }, - expectedResult: false, - }, - }, - }, - } - - for i, test := range tests { - for j, subTest := range test.headersToCompareTo { - result1 := test.baseHeader.Equal(subTest.header) - if result1 != subTest.expectedResult { - t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) - } - - result2 := subTest.header.Equal(test.baseHeader) - if result2 != subTest.expectedResult { - t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) - } - } - } -} - -func TestDomainBlockHeader_Clone(t *testing.T) { - headers := []*DomainBlockHeader{ - { - 0, - []*DomainHash{NewDomainHashFromByteArray(&[DomainHashSize]byte{0})}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - 4, - 5, - 6, - }, - { - 0, - []*DomainHash{}, - *NewDomainHashFromByteArray(&[DomainHashSize]byte{1}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{2}), - *NewDomainHashFromByteArray(&[DomainHashSize]byte{3}), - 4, - 5, - 6, - }, - } - - for i, header := range headers { - clone := header.Clone() - if !clone.Equal(header) { - t.Fatalf("Test #%d: clone should be equal to the original", i) - } - - if !reflect.DeepEqual(header, clone) { - t.Fatalf("Test #%d: clone should be equal to the original", i) - } - } -} diff --git a/domain/consensus/model/interface_datastructures_blockheaderstore.go b/domain/consensus/model/interface_datastructures_blockheaderstore.go index 20edf9c08..017ae6287 100644 --- a/domain/consensus/model/interface_datastructures_blockheaderstore.go +++ b/domain/consensus/model/interface_datastructures_blockheaderstore.go @@ -5,11 +5,11 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockHeaderStore represents a store of block headers type BlockHeaderStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) + Stage(blockHash *externalapi.DomainHash, blockHeader externalapi.BlockHeader) IsStaged() bool - BlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) + BlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) HasBlockHeader(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) - BlockHeaders(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) + BlockHeaders(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]externalapi.BlockHeader, error) Delete(blockHash *externalapi.DomainHash) Count() uint64 } diff --git a/domain/consensus/model/pow/pow.go b/domain/consensus/model/pow/pow.go index 323fdb93d..c584cc628 100644 --- a/domain/consensus/model/pow/pow.go +++ b/domain/consensus/model/pow/pow.go @@ -13,7 +13,7 @@ import ( // CheckProofOfWorkWithTarget check's if the block has a valid PoW according to the provided target // it does not check if the difficulty itself is valid or less than the maximum for the appropriate network -func CheckProofOfWorkWithTarget(header *externalapi.DomainBlockHeader, target *big.Int) bool { +func CheckProofOfWorkWithTarget(header externalapi.MutableBlockHeader, target *big.Int) bool { // The block pow must be less than the claimed target powNum := calcPowValue(header) @@ -23,17 +23,19 @@ func CheckProofOfWorkWithTarget(header *externalapi.DomainBlockHeader, target *b // CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field // it does not check if the difficulty itself is valid or less than the maximum for the appropriate network -func CheckProofOfWorkByBits(header *externalapi.DomainBlockHeader) bool { - return CheckProofOfWorkWithTarget(header, util.CompactToBig(header.Bits)) +func CheckProofOfWorkByBits(header externalapi.MutableBlockHeader) bool { + return CheckProofOfWorkWithTarget(header, util.CompactToBig(header.Bits())) } -func calcPowValue(header *externalapi.DomainBlockHeader) *big.Int { +func calcPowValue(header externalapi.MutableBlockHeader) *big.Int { // Zero out the time and nonce. - timestamp, nonce := header.TimeInMilliseconds, header.Nonce - header.TimeInMilliseconds, header.Nonce = 0, 0 + timestamp, nonce := header.TimeInMilliseconds(), header.Nonce() + header.SetTimeInMilliseconds(0) + header.SetNonce(0) prePowHash := consensushashing.HeaderHash(header) - header.TimeInMilliseconds, header.Nonce = timestamp, nonce + header.SetTimeInMilliseconds(timestamp) + header.SetNonce(nonce) // PRE_POW_HASH || TIME || 32 zero byte padding || NONCE writer := hashes.NewPoWHashWriter() diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 78b4bb119..1246e9bd9 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -1,6 +1,7 @@ package blockbuilder import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "sort" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -95,7 +96,7 @@ func (bb *blockBuilder) newBlockCoinbaseTransaction( return bb.coinbaseManager.ExpectedCoinbaseTransaction(model.VirtualBlockHash, coinbaseData) } -func (bb *blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) { +func (bb *blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction) (externalapi.BlockHeader, error) { parentHashes, err := bb.newBlockParentHashes() if err != nil { return nil, err @@ -118,15 +119,16 @@ func (bb *blockBuilder) buildHeader(transactions []*externalapi.DomainTransactio return nil, err } - return &externalapi.DomainBlockHeader{ - Version: constants.BlockVersion, - ParentHashes: parentHashes, - HashMerkleRoot: *hashMerkleRoot, - AcceptedIDMerkleRoot: *acceptedIDMerkleRoot, - UTXOCommitment: *utxoCommitment, - TimeInMilliseconds: timeInMilliseconds, - Bits: bits, - }, nil + return blockheader.NewImmutableBlockHeader( + constants.BlockVersion, + parentHashes, + hashMerkleRoot, + acceptedIDMerkleRoot, + utxoCommitment, + timeInMilliseconds, + bits, + 0, + ), nil } func (bb *blockBuilder) newBlockParentHashes() ([]*externalapi.DomainHash, error) { diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 3e3fa7507..31eeea624 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/infrastructure/logger" @@ -41,7 +42,7 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, transactions []*externalapi.DomainTransaction, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) ( - *externalapi.DomainBlockHeader, error) { + externalapi.BlockHeader, error) { timeInMilliseconds, err := bb.minBlockTime(tempBlockHash) if err != nil { @@ -60,16 +61,16 @@ func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.D utxoCommitment := multiset.Hash() bb.nonceCounter++ - return &externalapi.DomainBlockHeader{ - Version: constants.BlockVersion, - ParentHashes: parentHashes, - HashMerkleRoot: *hashMerkleRoot, - AcceptedIDMerkleRoot: *acceptedIDMerkleRoot, - UTXOCommitment: *utxoCommitment, - TimeInMilliseconds: timeInMilliseconds, - Bits: bits, - Nonce: bb.nonceCounter, - }, nil + return blockheader.NewImmutableBlockHeader( + constants.BlockVersion, + parentHashes, + hashMerkleRoot, + acceptedIDMerkleRoot, + utxoCommitment, + timeInMilliseconds, + bits, + bb.nonceCounter, + ), nil } func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) { diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index d16421e93..ca8c3a74f 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -37,7 +37,7 @@ func (v *blockValidator) checkParentBlockBodiesExist(blockHash *externalapi.Doma if err != nil { return err } - for _, parent := range header.ParentHashes { + for _, parent := range header.ParentHashes() { hasBlock, err := v.blockStore.HasBlock(v.databaseContext, parent) if err != nil { return err @@ -84,7 +84,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi. return err } - blockTime := block.Header.TimeInMilliseconds + blockTime := block.Header.TimeInMilliseconds() ghostdagData, err := v.ghostdagDataStore.Get(v.databaseContext, blockHash) if err != nil { @@ -92,7 +92,7 @@ func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi. } // If it's not genesis - if len(block.Header.ParentHashes) != 0 { + if len(block.Header.ParentHashes()) != 0 { blockTime, err = v.pastMedianTimeManager.PastMedianTime(blockHash) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 4daa95b9f..aa0f6d45c 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -143,10 +143,10 @@ func (v *blockValidator) checkTransactionsInIsolation(block *externalapi.DomainB func (v *blockValidator) checkBlockHashMerkleRoot(block *externalapi.DomainBlock) error { calculatedHashMerkleRoot := merkle.CalculateHashMerkleRoot(block.Transactions) - if !block.Header.HashMerkleRoot.Equal(calculatedHashMerkleRoot) { + if !block.Header.HashMerkleRoot().Equal(calculatedHashMerkleRoot) { return errors.Wrapf(ruleerrors.ErrBadMerkleRoot, "block hash merkle root is invalid - block "+ "header indicates %s, but calculated value is %s", - block.Header.HashMerkleRoot, calculatedHashMerkleRoot) + block.Header.HashMerkleRoot(), calculatedHashMerkleRoot) } return nil } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 929312b9a..6171cd327 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -1,6 +1,7 @@ package blockvalidator_test import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "math" "testing" @@ -119,9 +120,9 @@ func TestCheckBlockSanity(t *testing.T) { } var unOrderedParentsBlock = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 0x10000000, - ParentHashes: []*externalapi.DomainHash{ + Header: blockheader.NewImmutableBlockHeader( + 0x10000000, + []*externalapi.DomainHash{ externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, @@ -135,28 +136,28 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ 0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00, }), }, - HashMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xf8, 0x55, 0x7b, 0xd0, 0xda, 0xf2, 0x06, 0x8b, 0x3b, 0xb1, 0x93, 0x5a, 0x2c, 0x52, 0x43, 0xf0, 0x02, 0xf2, 0xb1, 0x40, 0x81, 0x2c, 0x0c, 0x15, 0x8d, 0x04, 0x3d, 0xe2, 0x23, 0x54, 0x98, 0x88, }), - AcceptedIDMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, }), - UTXOCommitment: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, }), - TimeInMilliseconds: 0x5cd18053000, - Bits: 0x207fffff, - Nonce: 0x1, - }, + 0x5cd18053000, + 0x207fffff, + 0x1, + ), Transactions: []*externalapi.DomainTransaction{ { Version: 1, @@ -393,9 +394,9 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ // exampleValidBlock defines a sample valid block var exampleValidBlock = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 0x10000000, - ParentHashes: []*externalapi.DomainHash{ + Header: blockheader.NewImmutableBlockHeader( + 0x10000000, + []*externalapi.DomainHash{ externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, @@ -409,23 +410,23 @@ var exampleValidBlock = externalapi.DomainBlock{ 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }), }, - HashMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x33, 0x70, 0xa7, 0x40, 0x9f, 0x2d, 0x87, 0xe1, 0x26, 0xaf, 0x0f, 0x5c, 0x7e, 0xc3, 0x84, 0x5e, 0x4f, 0x68, 0x42, 0x0a, 0xbf, 0x90, 0xcd, 0xef, 0x94, 0x9b, 0xe1, 0x9a, 0xf7, 0xdd, 0xb0, 0xb5, }), - AcceptedIDMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3, 0x5d, 0x4e, 0x2c, 0xc9, 0x57, 0x88, 0x30, 0x65, 0x81, 0xb8, 0xa0, 0x68, 0x77, 0xc4, 0x02, 0x1e, 0x3c, 0xb1, 0x16, 0x8f, 0x5f, 0x6b, 0x45, 0x87, }), - UTXOCommitment: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}), - TimeInMilliseconds: 0x17305aa654a, - Bits: 0x207fffff, - Nonce: 1, - }, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}), + 0x17305aa654a, + 0x207fffff, + 1, + ), Transactions: []*externalapi.DomainTransaction{ { Version: 1, @@ -695,9 +696,9 @@ var exampleValidBlock = externalapi.DomainBlock{ // blockWithWrongTxOrder defines invalid block 100,000 of the block DAG. var blockWithWrongTxOrder = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 1, - ParentHashes: []*externalapi.DomainHash{ + Header: blockheader.NewImmutableBlockHeader( + 1, + []*externalapi.DomainHash{ externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, @@ -711,28 +712,28 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }), }, - HashMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xac, 0xa4, 0x21, 0xe1, 0xa6, 0xc3, 0xbe, 0x5d, 0x52, 0x66, 0xf3, 0x0b, 0x21, 0x87, 0xbc, 0xf3, 0xf3, 0x2d, 0xd1, 0x05, 0x64, 0xb5, 0x16, 0x76, 0xe4, 0x66, 0x7d, 0x51, 0x53, 0x18, 0x6d, 0xb1, }), - AcceptedIDMerkleRoot: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, }), - UTXOCommitment: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x00, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, }), - TimeInMilliseconds: 0x5cd16eaa000, - Bits: 0x207fffff, - Nonce: 1, - }, + 0x5cd16eaa000, + 0x207fffff, + 1, + ), Transactions: []*externalapi.DomainTransaction{ { Version: 1, diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 63976e8bf..dccc30b95 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -83,9 +83,9 @@ func (v *blockValidator) hasValidatedHeader(blockHash *externalapi.DomainHash) ( } // checkParentsIncest validates that no parent is an ancestor of another parent -func (v *blockValidator) checkParentsIncest(header *externalapi.DomainBlockHeader) error { - for _, parentA := range header.ParentHashes { - for _, parentB := range header.ParentHashes { +func (v *blockValidator) checkParentsIncest(header externalapi.BlockHeader) error { + for _, parentA := range header.ParentHashes() { + for _, parentB := range header.ParentHashes() { if parentA.Equal(parentB) { continue } @@ -107,8 +107,8 @@ func (v *blockValidator) checkParentsIncest(header *externalapi.DomainBlockHeade return nil } -func (v *blockValidator) validateMedianTime(header *externalapi.DomainBlockHeader) error { - if len(header.ParentHashes) == 0 { +func (v *blockValidator) validateMedianTime(header externalapi.BlockHeader) error { + if len(header.ParentHashes()) == 0 { return nil } @@ -120,9 +120,9 @@ func (v *blockValidator) validateMedianTime(header *externalapi.DomainBlockHeade return err } - if header.TimeInMilliseconds <= pastMedianTime { + if header.TimeInMilliseconds() <= pastMedianTime { return errors.Wrapf(ruleerrors.ErrTimeTooOld, "block timestamp of %d is not after expected %d", - header.TimeInMilliseconds, pastMedianTime) + header.TimeInMilliseconds(), pastMedianTime) } return nil diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index 165b42df9..4791e7e11 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -2,6 +2,7 @@ package blockvalidator_test import ( "errors" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "testing" "github.com/kaspanet/kaspad/domain/consensus" @@ -28,7 +29,9 @@ func TestValidateMedianTime(t *testing.T) { t.Fatalf("BuildBlockWithParents: %+v", err) } - block.Header.TimeInMilliseconds = blockTime + newHeader := block.Header.ToMutable() + newHeader.SetTimeInMilliseconds(blockTime) + block.Header = newHeader.ToImmutable() _, err = tc.ValidateAndInsertBlock(block) if !errors.Is(err, expectedErr) { t.Fatalf("expected error %s but got %+v", expectedErr, err) @@ -62,7 +65,7 @@ func TestValidateMedianTime(t *testing.T) { tip := params.GenesisBlock tipHash := params.GenesisHash - blockTime := tip.Header.TimeInMilliseconds + blockTime := tip.Header.TimeInMilliseconds() for i := 0; i < 100; i++ { blockTime += 1000 @@ -105,16 +108,16 @@ func TestCheckParentsIncest(t *testing.T) { } directParentsRelationBlock := &externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 0, - ParentHashes: []*externalapi.DomainHash{a, b}, - HashMerkleRoot: externalapi.DomainHash{}, - AcceptedIDMerkleRoot: externalapi.DomainHash{}, - UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0, - Bits: 0, - Nonce: 0, - }, + Header: blockheader.NewImmutableBlockHeader( + 0, + []*externalapi.DomainHash{a, b}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), Transactions: nil, } @@ -124,16 +127,16 @@ func TestCheckParentsIncest(t *testing.T) { } indirectParentsRelationBlock := &externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 0, - ParentHashes: []*externalapi.DomainHash{params.GenesisHash, b}, - HashMerkleRoot: externalapi.DomainHash{}, - AcceptedIDMerkleRoot: externalapi.DomainHash{}, - UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0, - Bits: 0, - Nonce: 0, - }, + Header: blockheader.NewImmutableBlockHeader( + 0, + []*externalapi.DomainHash{params.GenesisHash, b}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), Transactions: nil, } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index 31ca02e4c..f6de3184a 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -33,21 +33,21 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain return nil } -func (v *blockValidator) checkParentsLimit(header *externalapi.DomainBlockHeader) error { +func (v *blockValidator) checkParentsLimit(header externalapi.BlockHeader) error { hash := consensushashing.HeaderHash(header) - if len(header.ParentHashes) == 0 && !hash.Equal(v.genesisHash) { + if len(header.ParentHashes()) == 0 && !hash.Equal(v.genesisHash) { return errors.Wrapf(ruleerrors.ErrNoParents, "block has no parents") } - if uint64(len(header.ParentHashes)) > uint64(v.maxBlockParents) { + if uint64(len(header.ParentHashes())) > uint64(v.maxBlockParents) { return errors.Wrapf(ruleerrors.ErrTooManyParents, "block header has %d parents, but the maximum allowed amount "+ - "is %d", len(header.ParentHashes), v.maxBlockParents) + "is %d", len(header.ParentHashes()), v.maxBlockParents) } return nil } -func (v *blockValidator) checkBlockTimestampInIsolation(header *externalapi.DomainBlockHeader) error { - blockTimestamp := header.TimeInMilliseconds +func (v *blockValidator) checkBlockTimestampInIsolation(header externalapi.BlockHeader) error { + blockTimestamp := header.TimeInMilliseconds() now := mstime.Now().UnixMilliseconds() maxCurrentTime := now + int64(v.timestampDeviationTolerance)*v.targetTimePerBlock.Milliseconds() if blockTimestamp > maxCurrentTime { diff --git a/domain/consensus/processes/blockvalidator/header_estimated_size.go b/domain/consensus/processes/blockvalidator/header_estimated_size.go index 428bad743..025197ad5 100644 --- a/domain/consensus/processes/blockvalidator/header_estimated_size.go +++ b/domain/consensus/processes/blockvalidator/header_estimated_size.go @@ -7,12 +7,12 @@ import ( // headerEstimatedSerializedSize is the estimated size of a block header in some // serialization. This has to be deterministic, but not necessarily accurate, since // it's only used to check block size limit violation. -func (v *blockValidator) headerEstimatedSerializedSize(header *externalapi.DomainBlockHeader) uint64 { +func (v *blockValidator) headerEstimatedSerializedSize(header externalapi.BlockHeader) uint64 { size := uint64(0) size += 4 // Version (int32) - size += 8 // number of parents (uint64) - size += uint64(externalapi.DomainHashSize * len(header.ParentHashes)) // parents + size += 8 // number of parents (uint64) + size += uint64(externalapi.DomainHashSize * len(header.ParentHashes())) // parents size += externalapi.DomainHashSize // HashMerkleRoot size += externalapi.DomainHashSize // AcceptedIDMerkleRoot diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index 08b4548f9..fa96c528e 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -39,7 +39,7 @@ func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficult return err } - err = v.dagTopologyManager.SetParents(blockHash, header.ParentHashes) + err = v.dagTopologyManager.SetParents(blockHash, header.ParentHashes()) if err != nil { return err } @@ -65,8 +65,8 @@ func (v *blockValidator) validateDifficulty(blockHash *externalapi.DomainHash) e if err != nil { return err } - if header.Bits != expectedBits { - return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block difficulty of %d is not the expected value of %d", header.Bits, expectedBits) + if header.Bits() != expectedBits { + return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block difficulty of %d is not the expected value of %d", header.Bits(), expectedBits) } return nil @@ -79,9 +79,9 @@ func (v *blockValidator) validateDifficulty(blockHash *externalapi.DomainHash) e // The flags modify the behavior of this function as follows: // - BFNoPoWCheck: The check to ensure the block hash is less than the target // difficulty is not performed. -func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) error { +func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error { // The target difficulty must be larger than zero. - target := util.CompactToBig(header.Bits) + target := util.CompactToBig(header.Bits()) if target.Sign() <= 0 { return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block target difficulty of %064x is too low", target) @@ -95,7 +95,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) // The block pow must be valid unless the flag to avoid proof of work checks is set. if !v.skipPoW { - valid := pow.CheckProofOfWorkWithTarget(header, target) + valid := pow.CheckProofOfWorkWithTarget(header.ToMutable(), target) if !valid { return errors.Wrap(ruleerrors.ErrInvalidPoW, "block has invalid proof of work") } @@ -103,9 +103,9 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader) return nil } -func (v *blockValidator) checkParentHeadersExist(header *externalapi.DomainBlockHeader) error { +func (v *blockValidator) checkParentHeadersExist(header externalapi.BlockHeader) error { missingParentHashes := []*externalapi.DomainHash{} - for _, parent := range header.ParentHashes { + for _, parent := range header.ParentHashes() { parentHeaderExists, err := v.blockHeaderStore.HasBlockHeader(v.databaseContext, parent) if err != nil { return err @@ -131,7 +131,7 @@ func (v *blockValidator) checkParentHeadersExist(header *externalapi.DomainBlock return nil } -func (v *blockValidator) checkPruningPointViolation(header *externalapi.DomainBlockHeader) error { +func (v *blockValidator) checkPruningPointViolation(header externalapi.BlockHeader) error { // check if the pruning point is on past of at least one parent of the header's parents. hasPruningPoint, err := v.pruningStore.HasPruningPoint(v.databaseContext) @@ -149,7 +149,7 @@ func (v *blockValidator) checkPruningPointViolation(header *externalapi.DomainBl return err } - isAncestorOfAny, err := v.dagTopologyManager.IsAncestorOfAny(pruningPoint, header.ParentHashes) + isAncestorOfAny, err := v.dagTopologyManager.IsAncestorOfAny(pruningPoint, header.ParentHashes()) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index ed38040db..db0b64817 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -104,10 +104,10 @@ func checkBlockUTXOCommitment(t *testing.T, consensus testapi.TestConsensus, blo utxoCommitment := ms.Hash() // Make sure that the two commitments are equal - if *utxoCommitment != block.Header.UTXOCommitment { + if !utxoCommitment.Equal(block.Header.UTXOCommitment()) { t.Fatalf("TestUTXOCommitment: calculated UTXO commitment for block %s and "+ "actual UTXO commitment don't match. Want: %s, got: %s", blockName, - utxoCommitment, block.Header.UTXOCommitment) + utxoCommitment, block.Header.UTXOCommitment()) } } diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index 61f5d2552..12f02844b 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -62,11 +62,11 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap return err } log.Debugf("The UTXO commitment of the pruning point: %s", - newPruningPointHeader.UTXOCommitment) + newPruningPointHeader.UTXOCommitment()) - if !newPruningPointHeader.UTXOCommitment.Equal(utxoSetMultiSet.Hash()) { + if !newPruningPointHeader.UTXOCommitment().Equal(utxoSetMultiSet.Hash()) { return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+ - "point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash()) + "point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment(), *utxoSetMultiSet.Hash()) } log.Debugf("The new pruning point UTXO commitment validation passed") diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index 7dd6b2991..b3d0b63c0 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -103,10 +103,10 @@ func (csm *consensusStateManager) validateAcceptedIDMerkleRoot(block *externalap defer log.Tracef("validateAcceptedIDMerkleRoot end for block %s", blockHash) calculatedAcceptedIDMerkleRoot := calculateAcceptedIDMerkleRoot(acceptanceData) - if !block.Header.AcceptedIDMerkleRoot.Equal(calculatedAcceptedIDMerkleRoot) { + if !block.Header.AcceptedIDMerkleRoot().Equal(calculatedAcceptedIDMerkleRoot) { return errors.Wrapf(ruleerrors.ErrBadMerkleRoot, "block %s accepted ID merkle root is invalid - block "+ "header indicates %s, but calculated value is %s", - blockHash, &block.Header.UTXOCommitment, calculatedAcceptedIDMerkleRoot) + blockHash, block.Header.UTXOCommitment(), calculatedAcceptedIDMerkleRoot) } return nil @@ -119,9 +119,9 @@ func (csm *consensusStateManager) validateUTXOCommitment( defer log.Tracef("validateUTXOCommitment end for block %s", blockHash) multisetHash := multiset.Hash() - if !block.Header.UTXOCommitment.Equal(multisetHash) { + if !block.Header.UTXOCommitment().Equal(multisetHash) { return errors.Wrapf(ruleerrors.ErrBadUTXOCommitment, "block %s UTXO commitment is invalid - block "+ - "header indicates %s, but calculated value is %s", blockHash, &block.Header.UTXOCommitment, multisetHash) + "header indicates %s, but calculated value is %s", blockHash, block.Header.UTXOCommitment(), multisetHash) } return nil diff --git a/domain/consensus/processes/difficultymanager/blockwindow.go b/domain/consensus/processes/difficultymanager/blockwindow.go index 2fd458258..3f795f140 100644 --- a/domain/consensus/processes/difficultymanager/blockwindow.go +++ b/domain/consensus/processes/difficultymanager/blockwindow.go @@ -23,8 +23,8 @@ func (dm *difficultyManager) getDifficultyBlock(blockHash *externalapi.DomainHas return difficultyBlock{}, err } return difficultyBlock{ - timeInMilliseconds: header.TimeInMilliseconds, - Bits: header.Bits, + timeInMilliseconds: header.TimeInMilliseconds(), + Bits: header.Bits(), }, nil } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index 3d75318c0..87939a8da 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -59,7 +59,7 @@ func (dm *difficultyManager) genesisBits() (uint32, error) { return 0, err } - return header.Bits, nil + return header.Bits(), nil } // RequiredDifficulty returns the difficulty required for some block diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index eef999e2a..46e9b8cfd 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -25,7 +25,7 @@ func TestDifficulty(t *testing.T) { // a bit less then an hour of timestamps. // To prevent rejected blocks due to timestamps in the future, the following safeguard makes sure // the genesis block is at least 1 hour in the past. - if params.GenesisBlock.Header.TimeInMilliseconds > mstime.ToMSTime(time.Now().Add(-time.Hour)).UnixMilliseconds() { + if params.GenesisBlock.Header.TimeInMilliseconds() > mstime.ToMSTime(time.Now().Add(-time.Hour)).UnixMilliseconds() { t.Fatalf("TestDifficulty requires the GenesisBlock to be at least 1 hour old to pass") } @@ -51,7 +51,7 @@ func TestDifficulty(t *testing.T) { t.Fatalf("BlockHeader: %+v", err) } - blockTime = header.TimeInMilliseconds + params.TargetTimePerBlock.Milliseconds() + blockTime = header.TimeInMilliseconds() + params.TargetTimePerBlock.Milliseconds() } block, _, err := tc.BuildBlockWithParents(parents, nil, nil) @@ -59,7 +59,9 @@ func TestDifficulty(t *testing.T) { t.Fatalf("BuildBlockWithParents: %+v", err) } - block.Header.TimeInMilliseconds = blockTime + newHeader := block.Header.ToMutable() + newHeader.SetTimeInMilliseconds(blockTime) + block.Header = newHeader.ToImmutable() _, err = tc.ValidateAndInsertBlock(block) if err != nil { t.Fatalf("ValidateAndInsertBlock: %+v", err) @@ -99,31 +101,31 @@ func TestDifficulty(t *testing.T) { tip := params.GenesisBlock for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ { tip, tipHash = addBlock(0, tipHash) - if tip.Header.Bits != params.GenesisBlock.Header.Bits { + if tip.Header.Bits() != params.GenesisBlock.Header.Bits() { t.Fatalf("As long as the bluest parent's blue score is less then the difficulty adjustment " + "window size, the difficulty should be the same as genesis'") } } for i := 0; i < params.DifficultyAdjustmentWindowSize+100; i++ { tip, tipHash = addBlock(0, tipHash) - if tip.Header.Bits != params.GenesisBlock.Header.Bits { + if tip.Header.Bits() != params.GenesisBlock.Header.Bits() { t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change") } } blockInThePast, tipHash := addBlockWithMinimumTime(tipHash) - if blockInThePast.Header.Bits != tip.Header.Bits { + if blockInThePast.Header.Bits() != tip.Header.Bits() { t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent") } tip = blockInThePast tip, tipHash = addBlock(0, tipHash) - if tip.Header.Bits != blockInThePast.Header.Bits { + if tip.Header.Bits() != blockInThePast.Header.Bits() { t.Fatalf("The difficulty should only change when blockInThePast is in the past of a block bluest parent") } tip, tipHash = addBlock(0, tipHash) - if compareBits(tip.Header.Bits, blockInThePast.Header.Bits) >= 0 { + if compareBits(tip.Header.Bits(), blockInThePast.Header.Bits()) >= 0 { t.Fatalf("tip.bits should be smaller than blockInThePast.bits because blockInThePast increased the " + "block rate, so the difficulty should increase as well") } @@ -136,8 +138,8 @@ func TestDifficulty(t *testing.T) { expectedBits = uint32(0x207f83df) } - if tip.Header.Bits != expectedBits { - t.Errorf("tip.bits was expected to be %x but got %x", expectedBits, tip.Header.Bits) + if tip.Header.Bits() != expectedBits { + t.Errorf("tip.bits was expected to be %x but got %x", expectedBits, tip.Header.Bits()) } // Increase block rate to increase difficulty @@ -154,38 +156,38 @@ func TestDifficulty(t *testing.T) { t.Fatalf("BlockHeader: %+v", err) } - if compareBits(tip.Header.Bits, selectedParentHeader.Bits) > 0 { + if compareBits(tip.Header.Bits(), selectedParentHeader.Bits()) > 0 { t.Fatalf("Because we're increasing the block rate, the difficulty can't decrease") } } // Add blocks until difficulty stabilizes - lastBits := tip.Header.Bits + lastBits := tip.Header.Bits() sameBitsCount := 0 for sameBitsCount < params.DifficultyAdjustmentWindowSize+1 { tip, tipHash = addBlock(0, tipHash) - if tip.Header.Bits == lastBits { + if tip.Header.Bits() == lastBits { sameBitsCount++ } else { - lastBits = tip.Header.Bits + lastBits = tip.Header.Bits() sameBitsCount = 0 } } - slowBlockTime := tip.Header.TimeInMilliseconds + params.TargetTimePerBlock.Milliseconds() + 1000 + slowBlockTime := tip.Header.TimeInMilliseconds() + params.TargetTimePerBlock.Milliseconds() + 1000 slowBlock, tipHash := addBlock(slowBlockTime, tipHash) - if slowBlock.Header.Bits != tip.Header.Bits { + if slowBlock.Header.Bits() != tip.Header.Bits() { t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent") } tip = slowBlock tip, tipHash = addBlock(0, tipHash) - if tip.Header.Bits != slowBlock.Header.Bits { + if tip.Header.Bits() != slowBlock.Header.Bits() { t.Fatalf("The difficulty should only change when slowBlock is in the past of a block bluest parent") } tip, tipHash = addBlock(0, tipHash) - if compareBits(tip.Header.Bits, slowBlock.Header.Bits) <= 0 { + if compareBits(tip.Header.Bits(), slowBlock.Header.Bits()) <= 0 { t.Fatalf("tip.bits should be smaller than slowBlock.bits because slowBlock decreased the block" + " rate, so the difficulty should decrease as well") } @@ -203,7 +205,7 @@ func TestDifficulty(t *testing.T) { } tipWithRedPast, _ := addBlock(0, redChainTipHash, blueTipHash) tipWithoutRedPast, _ := addBlock(0, blueTipHash) - if tipWithoutRedPast.Header.Bits != tipWithRedPast.Header.Bits { + if tipWithoutRedPast.Header.Bits() != tipWithRedPast.Header.Bits() { t.Fatalf("tipWithoutRedPast.bits should be the same as tipWithRedPast.bits because red blocks" + " shouldn't affect the difficulty") } diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index 05a3030f7..23773708b 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -113,7 +113,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error if err != nil { return err } - myWork.Add(myWork, util.CalcWork(header.Bits)) + myWork.Add(myWork, util.CalcWork(header.Bits())) } e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil) diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index f82fceb36..6eb056b6a 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -88,7 +88,7 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { if err != nil { return err } - newBlockData.blueWork.Add(newBlockData.blueWork, util.CalcWork(header.Bits)) + newBlockData.blueWork.Add(newBlockData.blueWork, util.CalcWork(header.Bits())) } } else { // Genesis's blue score is defined to be 0. diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index a05a6a29b..9bc5dc8fa 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -2,6 +2,8 @@ package ghostdagmanager_test import ( "encoding/json" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "math/big" "os" "path/filepath" @@ -65,12 +67,12 @@ func TestGHOSTDAG(t *testing.T) { } blockHeadersStore := &blockHeadersStore{ - dagMap: make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader), + dagMap: make(map[externalapi.DomainHash]externalapi.BlockHeader), } blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil) genesisHeader := params.GenesisBlock.Header - genesisWork := util.CalcWork(genesisHeader.Bits) + genesisWork := util.CalcWork(genesisHeader.Bits()) var testsCounter int err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { @@ -108,10 +110,16 @@ func TestGHOSTDAG(t *testing.T) { blockID := StringToDomainHash(testBlockData.ID) dagTopology.parentsMap[*blockID] = StringToDomainHashSlice(testBlockData.Parents) - blockHeadersStore.dagMap[*blockID] = &externalapi.DomainBlockHeader{ - ParentHashes: StringToDomainHashSlice(testBlockData.Parents), - Bits: genesisHeader.Bits, - } + blockHeadersStore.dagMap[*blockID] = blockheader.NewImmutableBlockHeader( + constants.BlockVersion, + StringToDomainHashSlice(testBlockData.Parents), + nil, + nil, + nil, + 0, + genesisHeader.Bits(), + 0, + ) err := g.GHOSTDAG(blockID) if err != nil { @@ -154,7 +162,7 @@ func TestGHOSTDAG(t *testing.T) { dagTopology.parentsMap[genesisHash] = nil ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis - blockHeadersStore.dagMap = make(map[externalapi.DomainHash]*externalapi.DomainBlockHeader) + blockHeadersStore.dagMap = make(map[externalapi.DomainHash]externalapi.BlockHeader) blockHeadersStore.dagMap[genesisHash] = genesisHeader } @@ -299,20 +307,20 @@ func (dt *DAGTopologyManagerImpl) SetParents(blockHash *externalapi.DomainHash, } type blockHeadersStore struct { - dagMap map[externalapi.DomainHash]*externalapi.DomainBlockHeader + dagMap map[externalapi.DomainHash]externalapi.BlockHeader } func (b *blockHeadersStore) Discard() { panic("unimplemented") } func (b *blockHeadersStore) Commit(_ model.DBTransaction) error { panic("unimplemented") } -func (b *blockHeadersStore) Stage(blockHash *externalapi.DomainHash, blockHeader *externalapi.DomainBlockHeader) { +func (b *blockHeadersStore) Stage(blockHash *externalapi.DomainHash, blockHeader externalapi.BlockHeader) { b.dagMap[*blockHash] = blockHeader } func (b *blockHeadersStore) IsStaged() bool { panic("unimplemented") } -func (b *blockHeadersStore) BlockHeader(_ model.DBReader, blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error) { +func (b *blockHeadersStore) BlockHeader(_ model.DBReader, blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) { header, ok := b.dagMap[*blockHash] if ok { return header, nil @@ -325,8 +333,8 @@ func (b *blockHeadersStore) HasBlockHeader(_ model.DBReader, blockHash *external return ok, nil } -func (b *blockHeadersStore) BlockHeaders(_ model.DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlockHeader, error) { - res := make([]*externalapi.DomainBlockHeader, 0, len(blockHashes)) +func (b *blockHeadersStore) BlockHeaders(_ model.DBReader, blockHashes []*externalapi.DomainHash) ([]externalapi.BlockHeader, error) { + res := make([]externalapi.BlockHeader, 0, len(blockHashes)) for _, hash := range blockHashes { header, err := b.BlockHeader(nil, hash) if err != nil { diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go index fc496bbf3..a8b3e94bf 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go @@ -54,7 +54,7 @@ func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainH return 0, err } - return header.TimeInMilliseconds, nil + return header.TimeInMilliseconds(), nil } window, err := pmtm.dagTraversalManager.BlueWindow(selectedParentHash, 2*pmtm.timestampDeviationTolerance-1) @@ -76,7 +76,7 @@ func (pmtm *pastMedianTimeManager) windowMedianTimestamp(window []*externalapi.D if err != nil { return 0, err } - timestamps[i] = blockHeader.TimeInMilliseconds + timestamps[i] = blockHeader.TimeInMilliseconds() } sort.Slice(timestamps, func(i, j int) bool { diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index 938bfe887..c7769750f 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -22,7 +22,7 @@ func TestPastMedianTime(t *testing.T) { numBlocks := uint32(300) blockHashes := make([]*externalapi.DomainHash, numBlocks) blockHashes[0] = params.GenesisHash - blockTime := params.GenesisBlock.Header.TimeInMilliseconds + blockTime := params.GenesisBlock.Header.TimeInMilliseconds() for i := uint32(1); i < numBlocks; i++ { blockTime += 1000 block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{blockHashes[i-1]}, nil, nil) @@ -30,7 +30,9 @@ func TestPastMedianTime(t *testing.T) { t.Fatalf("BuildBlockWithParents: %s", err) } - block.Header.TimeInMilliseconds = blockTime + newHeader := block.Header.ToMutable() + newHeader.SetTimeInMilliseconds(blockTime) + block.Header = newHeader.ToImmutable() _, err = tc.ValidateAndInsertBlock(block) if err != nil { t.Fatalf("ValidateAndInsertBlock: %+v", err) @@ -68,7 +70,7 @@ func TestPastMedianTime(t *testing.T) { } millisecondsSinceGenesis := pastMedianTime - - params.GenesisBlock.Header.TimeInMilliseconds + params.GenesisBlock.Header.TimeInMilliseconds() if millisecondsSinceGenesis != test.expectedMillisecondsSinceGenesis { t.Errorf("TestCalcPastMedianTime: expected past median time of block %v to be %v milliseconds "+ diff --git a/domain/consensus/utils/blockheader/blockheader.go b/domain/consensus/utils/blockheader/blockheader.go new file mode 100644 index 000000000..0ad3776c5 --- /dev/null +++ b/domain/consensus/utils/blockheader/blockheader.go @@ -0,0 +1,146 @@ +package blockheader + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +type blockHeader struct { + version int32 + parentHashes []*externalapi.DomainHash + hashMerkleRoot *externalapi.DomainHash + acceptedIDMerkleRoot *externalapi.DomainHash + utxoCommitment *externalapi.DomainHash + timeInMilliseconds int64 + bits uint32 + nonce uint64 +} + +func (bh *blockHeader) ToImmutable() externalapi.BlockHeader { + return bh.clone() +} + +func (bh *blockHeader) SetNonce(nonce uint64) { + bh.nonce = nonce +} + +func (bh *blockHeader) SetTimeInMilliseconds(timeInMilliseconds int64) { + bh.timeInMilliseconds = timeInMilliseconds +} + +func (bh *blockHeader) Version() int32 { + return bh.version +} + +func (bh *blockHeader) ParentHashes() []*externalapi.DomainHash { + return bh.parentHashes +} + +func (bh *blockHeader) HashMerkleRoot() *externalapi.DomainHash { + return bh.hashMerkleRoot +} + +func (bh *blockHeader) AcceptedIDMerkleRoot() *externalapi.DomainHash { + return bh.acceptedIDMerkleRoot +} + +func (bh *blockHeader) UTXOCommitment() *externalapi.DomainHash { + return bh.utxoCommitment +} + +func (bh *blockHeader) TimeInMilliseconds() int64 { + return bh.timeInMilliseconds +} + +func (bh *blockHeader) Bits() uint32 { + return bh.bits +} + +func (bh *blockHeader) Nonce() uint64 { + return bh.nonce +} + +func (bh *blockHeader) Equal(other externalapi.BaseBlockHeader) bool { + if bh == nil || other == nil { + return bh == other + } + + // If only the underlying value of other is nil it'll + // make `other == nil` return false, so we check it + // explicitly. + downcastedOther := other.(*blockHeader) + if bh == nil || downcastedOther == nil { + return bh == downcastedOther + } + + if bh.version != other.Version() { + return false + } + + if !externalapi.HashesEqual(bh.parentHashes, other.ParentHashes()) { + return false + } + + if !bh.hashMerkleRoot.Equal(other.HashMerkleRoot()) { + return false + } + + if !bh.acceptedIDMerkleRoot.Equal(other.AcceptedIDMerkleRoot()) { + return false + } + + if !bh.utxoCommitment.Equal(other.UTXOCommitment()) { + return false + } + + if bh.timeInMilliseconds != other.TimeInMilliseconds() { + return false + } + + if bh.bits != other.Bits() { + return false + } + + if bh.nonce != other.Nonce() { + return false + } + + return true +} + +func (bh *blockHeader) clone() *blockHeader { + return &blockHeader{ + version: bh.version, + parentHashes: externalapi.CloneHashes(bh.parentHashes), + hashMerkleRoot: bh.hashMerkleRoot, + acceptedIDMerkleRoot: bh.acceptedIDMerkleRoot, + utxoCommitment: bh.utxoCommitment, + timeInMilliseconds: bh.timeInMilliseconds, + bits: bh.bits, + nonce: bh.nonce, + } +} + +func (bh *blockHeader) ToMutable() externalapi.MutableBlockHeader { + return bh.clone() +} + +// NewImmutableBlockHeader returns a new immutable header +func NewImmutableBlockHeader( + version int32, + parentHashes []*externalapi.DomainHash, + hashMerkleRoot *externalapi.DomainHash, + acceptedIDMerkleRoot *externalapi.DomainHash, + utxoCommitment *externalapi.DomainHash, + timeInMilliseconds int64, + bits uint32, + nonce uint64, +) externalapi.BlockHeader { + return &blockHeader{ + version: version, + parentHashes: parentHashes, + hashMerkleRoot: hashMerkleRoot, + acceptedIDMerkleRoot: acceptedIDMerkleRoot, + utxoCommitment: utxoCommitment, + timeInMilliseconds: timeInMilliseconds, + bits: bits, + nonce: nonce, + } +} diff --git a/domain/consensus/utils/blockheader/blockheader_test.go b/domain/consensus/utils/blockheader/blockheader_test.go new file mode 100644 index 000000000..02524a871 --- /dev/null +++ b/domain/consensus/utils/blockheader/blockheader_test.go @@ -0,0 +1,205 @@ +package blockheader + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "testing" +) + +func TestDomainBlockHeader_Equal(t *testing.T) { + type headerToCompare struct { + header *blockHeader + expectedResult bool + } + tests := []struct { + baseHeader *blockHeader + headersToCompareTo []headerToCompare + }{ + { + baseHeader: nil, + headersToCompareTo: []headerToCompare{ + { + header: nil, + expectedResult: true, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + 4, + 5, + 6, + }, + expectedResult: false, + }, + }, + }, + { + baseHeader: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + headersToCompareTo: []headerToCompare{ + { + header: nil, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + expectedResult: true, + }, + { + header: &blockHeader{ + 100, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + // []*externalapi.DomainHash{{1}, {2}}, + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{100}), + 5, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 100, + 6, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 100, + 7, + }, + expectedResult: false, + }, + { + header: &blockHeader{ + 0, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}), + 5, + 6, + 100, + }, + expectedResult: false, + }, + }, + }, + } + + for i, test := range tests { + for j, subTest := range test.headersToCompareTo { + result1 := test.baseHeader.Equal(subTest.header) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + + result2 := subTest.header.Equal(test.baseHeader) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} diff --git a/domain/consensus/utils/consensushashing/block.go b/domain/consensus/utils/consensushashing/block.go index 83c5d5ede..ea6b1026c 100644 --- a/domain/consensus/utils/consensushashing/block.go +++ b/domain/consensus/utils/consensushashing/block.go @@ -16,7 +16,7 @@ func BlockHash(block *externalapi.DomainBlock) *externalapi.DomainHash { } // HeaderHash returns the given header's hash -func HeaderHash(header *externalapi.DomainBlockHeader) *externalapi.DomainHash { +func HeaderHash(header externalapi.BaseBlockHeader) *externalapi.DomainHash { // Encode the header and hash everything prior to the number of // transactions. writer := hashes.NewBlockHashWriter() @@ -31,18 +31,18 @@ func HeaderHash(header *externalapi.DomainBlockHeader) *externalapi.DomainHash { return writer.Finalize() } -func serializeHeader(w io.Writer, header *externalapi.DomainBlockHeader) error { - timestamp := header.TimeInMilliseconds +func serializeHeader(w io.Writer, header externalapi.BaseBlockHeader) error { + timestamp := header.TimeInMilliseconds() - numParents := len(header.ParentHashes) - if err := serialization.WriteElements(w, header.Version, uint64(numParents)); err != nil { + numParents := len(header.ParentHashes()) + if err := serialization.WriteElements(w, header.Version(), uint64(numParents)); err != nil { return err } - for _, hash := range header.ParentHashes { + for _, hash := range header.ParentHashes() { if err := serialization.WriteElement(w, hash); err != nil { return err } } - return serialization.WriteElements(w, &header.HashMerkleRoot, &header.AcceptedIDMerkleRoot, &header.UTXOCommitment, timestamp, - header.Bits, header.Nonce) + return serialization.WriteElements(w, header.HashMerkleRoot(), header.AcceptedIDMerkleRoot(), header.UTXOCommitment(), timestamp, + header.Bits(), header.Nonce()) } diff --git a/domain/consensus/utils/mining/solve.go b/domain/consensus/utils/mining/solve.go index f5274f7b0..2188f8a3c 100644 --- a/domain/consensus/utils/mining/solve.go +++ b/domain/consensus/utils/mining/solve.go @@ -12,11 +12,12 @@ import ( // SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) { - targetDifficulty := utilsMath.CompactToBig(block.Header.Bits) - + targetDifficulty := utilsMath.CompactToBig(block.Header.Bits()) + headerForMining := block.Header.ToMutable() for i := rd.Uint64(); i < math.MaxUint64; i++ { - block.Header.Nonce = i - if pow.CheckProofOfWorkWithTarget(block.Header, targetDifficulty) { + headerForMining.SetNonce(i) + if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { + block.Header = headerForMining.ToImmutable() return } } diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 22362e4e4..088f03e9b 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -6,6 +6,7 @@ package dagconfig import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" ) @@ -46,16 +47,16 @@ var genesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.Dom // genesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the main network. var genesisBlock = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 1, - ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: *genesisMerkleRoot, - AcceptedIDMerkleRoot: externalapi.DomainHash{}, - UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1763db5c4a9, - Bits: 0x207fffff, - Nonce: 0x1, - }, + Header: blockheader.NewImmutableBlockHeader( + 1, + []*externalapi.DomainHash{}, + genesisMerkleRoot, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0x1763db5c4a9, + 0x207fffff, + 0x1, + ), Transactions: []*externalapi.DomainTransaction{genesisCoinbaseTx}, } @@ -97,16 +98,16 @@ var devnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externala // devnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. var devnetGenesisBlock = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 1, - ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: *devnetGenesisMerkleRoot, - AcceptedIDMerkleRoot: externalapi.DomainHash{}, - UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1763db5c4a9, - Bits: 0x1e7fffff, - Nonce: 0xb6c8, - }, + Header: blockheader.NewImmutableBlockHeader( + 1, + []*externalapi.DomainHash{}, + devnetGenesisMerkleRoot, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0x1763db5c4a9, + 0x1e7fffff, + 0xb6c8, + ), Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -147,16 +148,16 @@ var simnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externala // simnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. var simnetGenesisBlock = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 1, - ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: *simnetGenesisMerkleRoot, - AcceptedIDMerkleRoot: externalapi.DomainHash{}, - UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1763db5c4a9, - Bits: 0x207fffff, - Nonce: 0x0, - }, + Header: blockheader.NewImmutableBlockHeader( + 1, + []*externalapi.DomainHash{}, + simnetGenesisMerkleRoot, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0x1763db5c4a9, + 0x207fffff, + 0x0, + ), Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } @@ -195,15 +196,15 @@ var testnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[external // testnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for testnet. var testnetGenesisBlock = externalapi.DomainBlock{ - Header: &externalapi.DomainBlockHeader{ - Version: 1, - ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: *testnetGenesisMerkleRoot, - AcceptedIDMerkleRoot: externalapi.DomainHash{}, - UTXOCommitment: externalapi.DomainHash{}, - TimeInMilliseconds: 0x1763db5c4a9, - Bits: 0x1e7fffff, - Nonce: 0x493d, - }, + Header: blockheader.NewImmutableBlockHeader( + 1, + []*externalapi.DomainHash{}, + testnetGenesisMerkleRoot, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0x1763db5c4a9, + 0x1e7fffff, + 0x493d, + ), Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go index 1f216f33f..55906375d 100644 --- a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go +++ b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go @@ -148,7 +148,7 @@ func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexterna } log.Debugf("Created new block template (%d transactions, %d in fees, %d mass, target difficulty %064x)", - len(blk.Transactions), blockTxs.totalFees, blockTxs.totalMass, util.CompactToBig(blk.Header.Bits)) + len(blk.Transactions), blockTxs.totalFees, blockTxs.totalMass, util.CompactToBig(blk.Header.Bits())) return blk, nil } diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index a2b49033e..edaadb660 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -165,7 +165,7 @@ func (networkFlags *NetworkFlags) overrideDAGParams() error { return errors.Errorf("couldn't convert %s to big int", *config.PowMax) } - genesisTarget := math.CompactToBig(networkFlags.ActiveNetParams.GenesisBlock.Header.Bits) + genesisTarget := math.CompactToBig(networkFlags.ActiveNetParams.GenesisBlock.Header.Bits()) if powMax.Cmp(genesisTarget) > 0 { return errors.Errorf("powMax (%s) is smaller than genesis's target (%s)", powMax.Text(16), genesisTarget.Text(16)) diff --git a/testing/integration/mining_test.go b/testing/integration/mining_test.go index 1fecb839c..0f9d77746 100644 --- a/testing/integration/mining_test.go +++ b/testing/integration/mining_test.go @@ -12,11 +12,13 @@ import ( ) func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock { - targetDifficulty := util.CompactToBig(block.Header.Bits) + targetDifficulty := util.CompactToBig(block.Header.Bits()) + headerForMining := block.Header.ToMutable() initialNonce := rand.Uint64() for i := initialNonce; i != initialNonce-1; i++ { - block.Header.Nonce = i - if pow.CheckProofOfWorkWithTarget(block.Header, targetDifficulty) { + headerForMining.SetNonce(i) + if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { + block.Header = headerForMining.ToImmutable() return block } } From d72f70fabe0c8dd8fa87d2bedef6a1cf70c7a276 Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Tue, 29 Dec 2020 14:10:38 +0200 Subject: [PATCH 179/351] Adds new dags for GHOSTDAG tests (formatted as json files). (#1187) * Adds new dags for ghostdag tests. * Change the error msg for the number of tests (6 instead of 3). Co-authored-by: tal --- .../ghostdagmanager/ghostdag_test.go | 4 +- domain/consensus/testdata/dags/dag3.json | 132 ++++++++++++++++++ domain/consensus/testdata/dags/dag4.json | 121 ++++++++++++++++ domain/consensus/testdata/dags/dag5.json | 93 ++++++++++++ 4 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 domain/consensus/testdata/dags/dag3.json create mode 100644 domain/consensus/testdata/dags/dag4.json create mode 100644 domain/consensus/testdata/dags/dag5.json diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index 9bc5dc8fa..f5485da2f 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -172,8 +172,8 @@ func TestGHOSTDAG(t *testing.T) { if err != nil { t.Fatal(err) } - if testsCounter != 3 { - t.Fatalf("Expected 3 test files, ran %d instead", testsCounter) + if testsCounter != 6 { + t.Fatalf("Expected 6 test files, ran %d instead", testsCounter) } }) } diff --git a/domain/consensus/testdata/dags/dag3.json b/domain/consensus/testdata/dags/dag3.json new file mode 100644 index 000000000..1f0b96c2d --- /dev/null +++ b/domain/consensus/testdata/dags/dag3.json @@ -0,0 +1,132 @@ +{ + "K": 3, + "GenesisID": "0", + "Blocks": [ + { + "ID": "1", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "2", + "ExpectedScore": 2, + "ExpectedSelectedParent": "1", + "ExpectedReds": [], + "ExpectedBlues": [ + "1" + ], + "Parents": [ + "1" + ] + }, + { + "ID": "3", + "ExpectedScore": 2, + "ExpectedSelectedParent": "1", + "ExpectedReds": [], + "ExpectedBlues": [ + "1" + ], + "Parents": [ + "1" + ] + }, + { + "ID": "4", + "ExpectedScore": 2, + "ExpectedSelectedParent": "1", + "ExpectedReds": [], + "ExpectedBlues": [ + "1" + ], + "Parents": [ + "1" + ] + }, + { + "ID": "5", + "ExpectedScore": 5, + "ExpectedSelectedParent": "4", + "ExpectedReds": [], + "ExpectedBlues": [ + "4", + "2", + "3" + ], + "Parents": [ + "4", + "2", + "3" + ] + }, + { + "ID": "6", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "7", + "ExpectedScore": 2, + "ExpectedSelectedParent": "6", + "ExpectedReds": [], + "ExpectedBlues": [ + "6" + ], + "Parents": [ + "6" + ] + }, + { + "ID": "8", + "ExpectedScore": 3, + "ExpectedSelectedParent": "7", + "ExpectedReds": [], + "ExpectedBlues": [ + "7" + ], + "Parents": [ + "7" + ] + }, + { + "ID": "9", + "ExpectedScore": 4, + "ExpectedSelectedParent": "8", + "ExpectedReds": [], + "ExpectedBlues": [ + "8" + ], + "Parents": [ + "8" + ] + }, + { + "ID": "10", + "ExpectedScore": 6, + "ExpectedSelectedParent": "5", + "ExpectedReds": ["6", "7", "8", "9"], + "ExpectedBlues": [ + "5" + ], + "Parents": [ + "5", + "9" + ] + } + + ] +} diff --git a/domain/consensus/testdata/dags/dag4.json b/domain/consensus/testdata/dags/dag4.json new file mode 100644 index 000000000..4ddf93a1b --- /dev/null +++ b/domain/consensus/testdata/dags/dag4.json @@ -0,0 +1,121 @@ +{ + "K": 2, + "GenesisID": "0", + "Blocks": [ + { + "ID": "1", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "2", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "3", + "ExpectedScore": 2, + "ExpectedSelectedParent": "2", + "ExpectedReds": [], + "ExpectedBlues": [ + "2" + ], + "Parents": [ + "2" + ] + }, + { + "ID": "4", + "ExpectedScore": 2, + "ExpectedSelectedParent": "2", + "ExpectedReds": [], + "ExpectedBlues": [ + "2" + ], + "Parents": [ + "2" + ] + }, + { + "ID": "5", + "ExpectedScore": 2, + "ExpectedSelectedParent": "1", + "ExpectedReds": [], + "ExpectedBlues": [ + "1" + ], + "Parents": [ + "1" + ] + }, + { + "ID": "6", + "ExpectedScore": 5, + "ExpectedSelectedParent": "5", + "ExpectedReds": [], + "ExpectedBlues": [ + "5", + "2", + "4" + ], + "Parents": [ + "4", + "5" + ] + }, + { + "ID": "7", + "ExpectedScore": 5, + "ExpectedSelectedParent": "5", + "ExpectedReds": [], + "ExpectedBlues": [ + "5", + "2", + "3" + ], + "Parents": [ + "3", + "5" + ] + }, + { + "ID": "8", + "ExpectedScore": 3, + "ExpectedSelectedParent": "3", + "ExpectedReds": [], + "ExpectedBlues": [ + "3" + ], + "Parents": [ + "3" + ] + }, + { + "ID": "9", + "ExpectedScore": 6, + "ExpectedSelectedParent": "7", + "ExpectedReds": ["4", "8", "6"], + "ExpectedBlues": [ + "7" + ], + "Parents": [ + "6","7","8" + ] + } + + ] +} diff --git a/domain/consensus/testdata/dags/dag5.json b/domain/consensus/testdata/dags/dag5.json new file mode 100644 index 000000000..a4250ee7b --- /dev/null +++ b/domain/consensus/testdata/dags/dag5.json @@ -0,0 +1,93 @@ +{ + "K": 3, + "GenesisID": "0", + "Blocks": [ + { + "ID": "1", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "2", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "3", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "4", + "ExpectedScore": 1, + "ExpectedSelectedParent": "0", + "ExpectedReds": [], + "ExpectedBlues": [ + "0" + ], + "Parents": [ + "0" + ] + }, + { + "ID": "5", + "ExpectedScore": 4, + "ExpectedSelectedParent": "3", + "ExpectedReds": [], + "ExpectedBlues": [ + "3", "1", "2" + ], + "Parents": [ + "1", + "2", + "3" + ] + }, + { + "ID": "6", + "ExpectedScore": 5, + "ExpectedSelectedParent": "4", + "ExpectedReds": [], + "ExpectedBlues": [ + "4", "1", "2", "3" + ], + "Parents": [ + "1", "2", "3", "4" + ] + }, + { + "ID": "7", + "ExpectedScore": 6, + "ExpectedSelectedParent": "6", + "ExpectedReds": ["5"], + "ExpectedBlues": [ + "6" + ], + "Parents": [ + "5", + "6" + ] + } + ] +} From 52427cb9531685377cbb12edc98ac0a2c373950c Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 29 Dec 2020 17:08:06 +0200 Subject: [PATCH 180/351] Reduce the amount of calls to FinalityPoint() (#1317) --- .../mergedepthmanager/merge_depth_manager.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index ddb2835df..cabc44985 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -87,8 +87,12 @@ func (mdm *mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exte nonBoundedMergeDepthViolatingBlues := make([]*externalapi.DomainHash, 0, len(ghostdagData.MergeSetBlues())) + finalityPoint, err := mdm.finalityManager.FinalityPoint(blockHash) + if err != nil { + return nil, err + } for _, blue := range ghostdagData.MergeSetBlues() { - notViolatingFinality, err := mdm.hasFinalityPointInOthersSelectedChain(blockHash, blue) + notViolatingFinality, err := mdm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint, blue) if err != nil { return nil, err } @@ -100,12 +104,3 @@ func (mdm *mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *exte return nonBoundedMergeDepthViolatingBlues, nil } - -func (mdm *mergeDepthManager) hasFinalityPointInOthersSelectedChain(this, other *externalapi.DomainHash) (bool, error) { - finalityPoint, err := mdm.finalityManager.FinalityPoint(this) - if err != nil { - return false, err - } - - return mdm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint, other) -} From 0f93189c16e4ef9b5db261aadee918935235694b Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 29 Dec 2020 17:16:38 +0200 Subject: [PATCH 181/351] Don't print the whole UTXODiff to log, it might be quite huge (#1318) --- .../processes/consensusstatemanager/calculate_past_utxo.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 7824377e6..b62d10c96 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -68,7 +68,8 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH return nil, err } utxoDiffs = append(utxoDiffs, utxoDiff) - log.Debugf("Collected UTXO diff for block %s: %s", nextBlockHash, utxoDiff) + log.Debugf("Collected UTXO diff for block %s: toAdd: %d, toRemove: %d", + nextBlockHash, utxoDiff.ToAdd().Len(), utxoDiff.ToRemove().Len()) exists, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, nextBlockHash) if err != nil { From 533fa8c00ea3db43f2896beb4dc791cb26b089e3 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 29 Dec 2020 21:42:31 +0200 Subject: [PATCH 182/351] Change sirtual parents selection to allow faster branch merges in the network (#1315) * if more candidates then max, choose half with highest blueWork and half with lowest * Add a Test GhostDAG sorter * Add a test for pick virtual parents * Fix review nits --- .../pick_virtual_parents.go | 16 ++- .../virtual_parents_test.go | 110 ++++++++++++++++++ .../dagtraversalmanager/window_test.go | 17 +-- domain/consensus/test_ghostdag_sorter.go | 43 +++++++ 4 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 domain/consensus/processes/consensusstatemanager/virtual_parents_test.go create mode 100644 domain/consensus/test_ghostdag_sorter.go diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index fc0d93031..2fef4256e 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -32,11 +32,23 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH log.Debugf("The selected parent of the virtual is: %s", virtualSelectedParent) selectedVirtualParents := hashset.NewFromSlice(virtualSelectedParent) + candidates := candidatesHeap.ToSlice() + // prioritize half the blocks with highest blueWork and half with lowest, so the network will merge splits faster. + if len(candidates) >= int(csm.maxBlockParents) { + // We already have the selectedParent, so we're left with csm.maxBlockParents-1. + maxParents := csm.maxBlockParents - 1 + end := len(candidates) - 1 + for i := (maxParents) / 2; i < maxParents; i++ { + candidates[i], candidates[end] = candidates[end], candidates[i] + end-- + } + } mergeSetSize := uint64(1) // starts counting from 1 because selectedParent is already in the mergeSet - for candidatesHeap.Len() > 0 && uint64(len(selectedVirtualParents)) < uint64(csm.maxBlockParents) { - candidate := candidatesHeap.Pop() + for len(candidates) > 0 && uint64(len(selectedVirtualParents)) < uint64(csm.maxBlockParents) { + candidate := candidates[0] + candidates = candidates[1:] log.Debugf("Attempting to add %s to the virtual parents", candidate) log.Debugf("The current merge set size is %d", mergeSetSize) diff --git a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go new file mode 100644 index 000000000..874c44b17 --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go @@ -0,0 +1,110 @@ +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/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "sort" + "testing" +) + +func TestConsensusStateManager_pickVirtualParents(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + tc, teardown, err := consensus.NewFactory().NewTestConsensus(params, "TestConsensusStateManager_pickVirtualParents") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + getSortedVirtualParents := func(tc testapi.TestConsensus) []*externalapi.DomainHash { + virtualRelations, err := tc.BlockRelationStore().BlockRelation(tc.DatabaseContext(), model.VirtualBlockHash) + if err != nil { + t.Fatalf("Failed getting virtual block virtualRelations: %v", err) + } + + block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{}, nil) + if err != nil { + t.Fatalf("Consensus failed building a block: %v", err) + } + blockParents := block.Header.ParentHashes() + sort.Sort(consensus.NewTestGhostDAGSorter(virtualRelations.Parents, tc, t)) + sort.Sort(consensus.NewTestGhostDAGSorter(blockParents, tc, t)) + if !externalapi.HashesEqual(virtualRelations.Parents, blockParents) { + t.Fatalf("Block relations and BuildBlock return different parents for virtual, %s != %s", virtualRelations.Parents, blockParents) + } + return virtualRelations.Parents + } + + // We build 2*params.MaxBlockParents each one with blueWork higher than the other. + parents := make([]*externalapi.DomainHash, 0, params.MaxBlockParents) + for i := 0; i < 2*int(params.MaxBlockParents); i++ { + lastBlock := params.GenesisHash + for j := 0; j <= i; j++ { + lastBlock, _, err = tc.AddBlock([]*externalapi.DomainHash{lastBlock}, nil, nil) + if err != nil { + t.Fatalf("Failed Adding block to tc: %v", err) + } + } + parents = append(parents, lastBlock) + } + + virtualParents := getSortedVirtualParents(tc) + sort.Sort(consensus.NewTestGhostDAGSorter(parents, tc, t)) + + // Make sure the first half of the blocks are with highest blueWork + // we use (max+1)/2 because the first "half" is rounded up, so `(dividend + (divisor - 1)) / divisor` = `(max + (2-1))/2` = `(max+1)/2` + for i := 0; i < int(params.MaxBlockParents+1)/2; i++ { + if !virtualParents[i].Equal(parents[i]) { + t.Fatalf("Expected block at %d to be equal, instead found %s != %s", i, virtualParents[i], parents[i]) + } + } + + // Make sure the second half is the candidates with lowest blueWork + end := len(parents) - int(params.MaxBlockParents)/2 + for i := (params.MaxBlockParents + 1) / 2; i < params.MaxBlockParents; i++ { + if !virtualParents[i].Equal(parents[end]) { + t.Fatalf("Expected block at %d to be equal, instead found %s != %s", i, virtualParents[i], parents[end]) + } + end++ + } + if end != len(parents) { + t.Fatalf("Expected %d==%d", end, len(parents)) + } + + // Clear all tips. + var virtualSelectedParent *externalapi.DomainHash + for { + block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{}, nil) + if err != nil { + t.Fatalf("Failed building a block: %v", err) + } + _, err = tc.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("Failed Inserting block to tc: %v", err) + } + virtualSelectedParent = consensushashing.BlockHash(block) + if len(block.Header.ParentHashes()) == 1 { + break + } + } + // build exactly params.MaxBlockParents + parents = make([]*externalapi.DomainHash, 0, params.MaxBlockParents) + for i := 0; i < int(params.MaxBlockParents); i++ { + block, _, err := tc.AddBlock([]*externalapi.DomainHash{virtualSelectedParent}, nil, nil) + if err != nil { + t.Fatalf("Failed Adding block to tc: %v", err) + } + parents = append(parents, block) + } + + sort.Sort(consensus.NewTestGhostDAGSorter(parents, tc, t)) + virtualParents = getSortedVirtualParents(tc) + if !externalapi.HashesEqual(virtualParents, parents) { + t.Fatalf("Expected VirtualParents and parents to be equal, instead: %s != %s", virtualParents, parents) + } + }) +} diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index dca6a4d1b..8dfad88e5 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -1,7 +1,6 @@ package dagtraversalmanager_test import ( - "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "reflect" "sort" "testing" @@ -345,7 +344,7 @@ func TestBlueBlockWindow(t *testing.T) { if err != nil { t.Fatalf("BlueWindow: %s", err) } - sortWindow(t, tc, window) + sort.Sort(consensus.NewTestGhostDAGSorter(window, tc, t)) if err := checkWindowIDs(window, blockData.expectedWindowWithGenesisPadding, idByBlockMap); err != nil { t.Errorf("Unexpected values for window for block %s: %s", blockData.id, err) } @@ -353,20 +352,6 @@ func TestBlueBlockWindow(t *testing.T) { }) } -func sortWindow(t *testing.T, tc testapi.TestConsensus, window []*externalapi.DomainHash) { - sort.Slice(window, func(i, j int) bool { - ghostdagDataI, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), window[i]) - if err != nil { - t.Fatalf("Failed getting ghostdag data for %s", err) - } - ghostdagDataJ, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), window[j]) - if err != nil { - t.Fatalf("Failed getting ghostdag data for %s", err) - } - return !tc.GHOSTDAGManager().Less(window[i], ghostdagDataI, window[j], ghostdagDataJ) - }) -} - func checkWindowIDs(window []*externalapi.DomainHash, expectedIDs []string, idByBlockMap map[externalapi.DomainHash]string) error { ids := make([]string, len(window)) for i, node := range window { diff --git a/domain/consensus/test_ghostdag_sorter.go b/domain/consensus/test_ghostdag_sorter.go new file mode 100644 index 000000000..a42b49140 --- /dev/null +++ b/domain/consensus/test_ghostdag_sorter.go @@ -0,0 +1,43 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "sort" + "testing" +) + +type testGhostDAGSorter struct { + slice []*externalapi.DomainHash + tc testapi.TestConsensus + test testing.TB +} + +// NewTestGhostDAGSorter returns a sort.Interface over the slice, so you can sort it via GhostDAG ordering +func NewTestGhostDAGSorter(slice []*externalapi.DomainHash, tc testapi.TestConsensus, t testing.TB) sort.Interface { + return testGhostDAGSorter{ + slice: slice, + tc: tc, + test: t, + } +} + +func (sorter testGhostDAGSorter) Len() int { + return len(sorter.slice) +} + +func (sorter testGhostDAGSorter) Less(i, j int) bool { + ghostdagDataI, err := sorter.tc.GHOSTDAGDataStore().Get(sorter.tc.DatabaseContext(), sorter.slice[i]) + if err != nil { + sorter.test.Fatalf("TestGhostDAGSorter: Failed getting ghostdag data for %s", err) + } + ghostdagDataJ, err := sorter.tc.GHOSTDAGDataStore().Get(sorter.tc.DatabaseContext(), sorter.slice[j]) + if err != nil { + sorter.test.Fatalf("TestGhostDAGSorter: Failed getting ghostdag data for %s", err) + } + return !sorter.tc.GHOSTDAGManager().Less(sorter.slice[i], ghostdagDataI, sorter.slice[j], ghostdagDataJ) +} + +func (sorter testGhostDAGSorter) Swap(i, j int) { + sorter.slice[i], sorter.slice[j] = sorter.slice[j], sorter.slice[i] +} From 9b12b9c58af3223ae37dab2ebfc4b8a172c1b25f Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 30 Dec 2020 09:48:38 +0200 Subject: [PATCH 183/351] Make ReachabilityData a read-only interface with a writable variant, to prevent cloning (#1316) * Rename reachabilityManager.data to dataForInsertion, and use it only during insertions * Make reachabilityData an interface * Fix db serialization of reachability data * Fix reachabilityDataStore * Fix all tests * Cleanup debugging code * Fix insertToFutureCoveringSet * Add comments * Rename to ReachabilityData and MutableReachabilityData --- .../database/serialization/dbobjects.pb.go | 319 +++++++--------- .../database/serialization/dbobjects.proto | 6 +- .../serialization/reachability_data.go | 40 +- .../serialization/reachability_tree_node.go | 41 -- .../reachabilitydatastore.go | 25 +- domain/consensus/finality_test.go | 2 +- ...ce_datastructures_reachabilitydatastore.go | 4 +- domain/consensus/model/reachabilitydata.go | 96 ++--- .../reachabilitydata_equal_clone_test.go | 354 ------------------ .../selected_child_iterator.go | 2 +- .../processes/ghostdagmanager/mergeset.go | 9 +- .../processes/reachabilitymanager/fetch.go | 43 +-- .../future_covering_set.go | 85 +++-- .../ordered_tree_node_set.go | 6 +- .../reachability_external_test.go | 6 +- .../reachabilitymanager/reachability_test.go | 20 +- .../reachabilitymanager.go | 9 +- .../processes/reachabilitymanager/stage.go | 38 +- .../processes/reachabilitymanager/tree.go | 9 +- .../reachabilitydata/reachability_data.go | 111 ++++++ .../reachabilitydata_equal_clone_test.go | 313 ++++++++++++++++ 21 files changed, 725 insertions(+), 813 deletions(-) delete mode 100644 domain/consensus/database/serialization/reachability_tree_node.go delete mode 100644 domain/consensus/model/reachabilitydata_equal_clone_test.go create mode 100644 domain/consensus/utils/reachabilitydata/reachability_data.go create mode 100644 domain/consensus/utils/reachabilitydata/reachabilitydata_equal_clone_test.go diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index 5d4ad688a..cd8a0912a 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -1234,8 +1234,10 @@ type DbReachabilityData struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TreeNode *DbReachabilityTreeNode `protobuf:"bytes,1,opt,name=treeNode,proto3" json:"treeNode,omitempty"` - FutureCoveringSet []*DbHash `protobuf:"bytes,2,rep,name=futureCoveringSet,proto3" json:"futureCoveringSet,omitempty"` + Children []*DbHash `protobuf:"bytes,1,rep,name=children,proto3" json:"children,omitempty"` + Parent *DbHash `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` + Interval *DbReachabilityInterval `protobuf:"bytes,3,opt,name=interval,proto3" json:"interval,omitempty"` + FutureCoveringSet []*DbHash `protobuf:"bytes,4,rep,name=futureCoveringSet,proto3" json:"futureCoveringSet,omitempty"` } func (x *DbReachabilityData) Reset() { @@ -1270,9 +1272,23 @@ func (*DbReachabilityData) Descriptor() ([]byte, []int) { return file_dbobjects_proto_rawDescGZIP(), []int{20} } -func (x *DbReachabilityData) GetTreeNode() *DbReachabilityTreeNode { +func (x *DbReachabilityData) GetChildren() []*DbHash { if x != nil { - return x.TreeNode + return x.Children + } + return nil +} + +func (x *DbReachabilityData) GetParent() *DbHash { + if x != nil { + return x.Parent + } + return nil +} + +func (x *DbReachabilityData) GetInterval() *DbReachabilityInterval { + if x != nil { + return x.Interval } return nil } @@ -1284,69 +1300,6 @@ func (x *DbReachabilityData) GetFutureCoveringSet() []*DbHash { return nil } -type DbReachabilityTreeNode struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Children []*DbHash `protobuf:"bytes,1,rep,name=children,proto3" json:"children,omitempty"` - Parent *DbHash `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` - Interval *DbReachabilityInterval `protobuf:"bytes,3,opt,name=interval,proto3" json:"interval,omitempty"` -} - -func (x *DbReachabilityTreeNode) Reset() { - *x = DbReachabilityTreeNode{} - if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DbReachabilityTreeNode) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DbReachabilityTreeNode) ProtoMessage() {} - -func (x *DbReachabilityTreeNode) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DbReachabilityTreeNode.ProtoReflect.Descriptor instead. -func (*DbReachabilityTreeNode) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{21} -} - -func (x *DbReachabilityTreeNode) GetChildren() []*DbHash { - if x != nil { - return x.Children - } - return nil -} - -func (x *DbReachabilityTreeNode) GetParent() *DbHash { - if x != nil { - return x.Parent - } - return nil -} - -func (x *DbReachabilityTreeNode) GetInterval() *DbReachabilityInterval { - if x != nil { - return x.Interval - } - return nil -} - type DbReachabilityInterval struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1359,7 +1312,7 @@ type DbReachabilityInterval struct { func (x *DbReachabilityInterval) Reset() { *x = DbReachabilityInterval{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[22] + mi := &file_dbobjects_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1372,7 +1325,7 @@ func (x *DbReachabilityInterval) String() string { func (*DbReachabilityInterval) ProtoMessage() {} func (x *DbReachabilityInterval) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[22] + mi := &file_dbobjects_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1385,7 +1338,7 @@ func (x *DbReachabilityInterval) ProtoReflect() protoreflect.Message { // Deprecated: Use DbReachabilityInterval.ProtoReflect.Descriptor instead. func (*DbReachabilityInterval) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{22} + return file_dbobjects_proto_rawDescGZIP(), []int{21} } func (x *DbReachabilityInterval) GetStart() uint64 { @@ -1414,7 +1367,7 @@ type DbUtxoDiff struct { func (x *DbUtxoDiff) Reset() { *x = DbUtxoDiff{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[23] + mi := &file_dbobjects_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1427,7 +1380,7 @@ func (x *DbUtxoDiff) String() string { func (*DbUtxoDiff) ProtoMessage() {} func (x *DbUtxoDiff) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[23] + mi := &file_dbobjects_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1440,7 +1393,7 @@ func (x *DbUtxoDiff) ProtoReflect() protoreflect.Message { // Deprecated: Use DbUtxoDiff.ProtoReflect.Descriptor instead. func (*DbUtxoDiff) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{23} + return file_dbobjects_proto_rawDescGZIP(), []int{22} } func (x *DbUtxoDiff) GetToAdd() []*DbUtxoCollectionItem { @@ -1468,7 +1421,7 @@ type DbPruningPointUTXOSetBytes struct { func (x *DbPruningPointUTXOSetBytes) Reset() { *x = DbPruningPointUTXOSetBytes{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[24] + mi := &file_dbobjects_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1481,7 +1434,7 @@ func (x *DbPruningPointUTXOSetBytes) String() string { func (*DbPruningPointUTXOSetBytes) ProtoMessage() {} func (x *DbPruningPointUTXOSetBytes) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[24] + mi := &file_dbobjects_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1494,7 +1447,7 @@ func (x *DbPruningPointUTXOSetBytes) ProtoReflect() protoreflect.Message { // Deprecated: Use DbPruningPointUTXOSetBytes.ProtoReflect.Descriptor instead. func (*DbPruningPointUTXOSetBytes) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{24} + return file_dbobjects_proto_rawDescGZIP(), []int{23} } func (x *DbPruningPointUTXOSetBytes) GetBytes() []byte { @@ -1515,7 +1468,7 @@ type DbHeaderTips struct { func (x *DbHeaderTips) Reset() { *x = DbHeaderTips{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[25] + mi := &file_dbobjects_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1528,7 +1481,7 @@ func (x *DbHeaderTips) String() string { func (*DbHeaderTips) ProtoMessage() {} func (x *DbHeaderTips) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[25] + mi := &file_dbobjects_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1541,7 +1494,7 @@ func (x *DbHeaderTips) ProtoReflect() protoreflect.Message { // Deprecated: Use DbHeaderTips.ProtoReflect.Descriptor instead. func (*DbHeaderTips) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{25} + return file_dbobjects_proto_rawDescGZIP(), []int{24} } func (x *DbHeaderTips) GetTips() []*DbHash { @@ -1562,7 +1515,7 @@ type DbTips struct { func (x *DbTips) Reset() { *x = DbTips{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[26] + mi := &file_dbobjects_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1575,7 +1528,7 @@ func (x *DbTips) String() string { func (*DbTips) ProtoMessage() {} func (x *DbTips) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[26] + mi := &file_dbobjects_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1588,7 +1541,7 @@ func (x *DbTips) ProtoReflect() protoreflect.Message { // Deprecated: Use DbTips.ProtoReflect.Descriptor instead. func (*DbTips) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{26} + return file_dbobjects_proto_rawDescGZIP(), []int{25} } func (x *DbTips) GetTips() []*DbHash { @@ -1609,7 +1562,7 @@ type DbVirtualDiffParents struct { func (x *DbVirtualDiffParents) Reset() { *x = DbVirtualDiffParents{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[27] + mi := &file_dbobjects_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1622,7 +1575,7 @@ func (x *DbVirtualDiffParents) String() string { func (*DbVirtualDiffParents) ProtoMessage() {} func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[27] + mi := &file_dbobjects_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1635,7 +1588,7 @@ func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { // Deprecated: Use DbVirtualDiffParents.ProtoReflect.Descriptor instead. func (*DbVirtualDiffParents) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{27} + return file_dbobjects_proto_rawDescGZIP(), []int{26} } func (x *DbVirtualDiffParents) GetVirtualDiffParents() []*DbHash { @@ -1656,7 +1609,7 @@ type DbBlockCount struct { func (x *DbBlockCount) Reset() { *x = DbBlockCount{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[28] + mi := &file_dbobjects_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1669,7 +1622,7 @@ func (x *DbBlockCount) String() string { func (*DbBlockCount) ProtoMessage() {} func (x *DbBlockCount) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[28] + mi := &file_dbobjects_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1682,7 +1635,7 @@ func (x *DbBlockCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DbBlockCount.ProtoReflect.Descriptor instead. func (*DbBlockCount) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{28} + return file_dbobjects_proto_rawDescGZIP(), []int{27} } func (x *DbBlockCount) GetCount() uint64 { @@ -1703,7 +1656,7 @@ type DbBlockHeaderCount struct { func (x *DbBlockHeaderCount) Reset() { *x = DbBlockHeaderCount{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[29] + mi := &file_dbobjects_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1716,7 +1669,7 @@ func (x *DbBlockHeaderCount) String() string { func (*DbBlockHeaderCount) ProtoMessage() {} func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[29] + mi := &file_dbobjects_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1729,7 +1682,7 @@ func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DbBlockHeaderCount.ProtoReflect.Descriptor instead. func (*DbBlockHeaderCount) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{29} + return file_dbobjects_proto_rawDescGZIP(), []int{28} } func (x *DbBlockHeaderCount) GetCount() uint64 { @@ -1922,66 +1875,60 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, - 0x62, 0x61, 0x73, 0x65, 0x22, 0x9c, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x74, - 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x62, 0x61, 0x73, 0x65, 0x22, 0xfe, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, - 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, - 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x43, - 0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x74, 0x22, 0xbd, 0x01, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x31, - 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, - 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x12, 0x41, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, - 0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, + 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, + 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, + 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, + 0x12, 0x43, 0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x53, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, + 0x6e, 0x67, 0x53, 0x65, 0x74, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, + 0x78, 0x6f, 0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, + 0x64, 0x12, 0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, - 0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x22, 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, - 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, - 0x74, 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, - 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, + 0x73, 0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, + 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, + 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, + 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1996,7 +1943,7 @@ func file_dbobjects_proto_rawDescGZIP() []byte { return file_dbobjects_proto_rawDescData } -var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_dbobjects_proto_goTypes = []interface{}{ (*DbBlock)(nil), // 0: serialization.DbBlock (*DbBlockHeader)(nil), // 1: serialization.DbBlockHeader @@ -2019,15 +1966,14 @@ var file_dbobjects_proto_goTypes = []interface{}{ (*DbUtxoCollectionItem)(nil), // 18: serialization.DbUtxoCollectionItem (*DbUtxoEntry)(nil), // 19: serialization.DbUtxoEntry (*DbReachabilityData)(nil), // 20: serialization.DbReachabilityData - (*DbReachabilityTreeNode)(nil), // 21: serialization.DbReachabilityTreeNode - (*DbReachabilityInterval)(nil), // 22: serialization.DbReachabilityInterval - (*DbUtxoDiff)(nil), // 23: serialization.DbUtxoDiff - (*DbPruningPointUTXOSetBytes)(nil), // 24: serialization.DbPruningPointUTXOSetBytes - (*DbHeaderTips)(nil), // 25: serialization.DbHeaderTips - (*DbTips)(nil), // 26: serialization.DbTips - (*DbVirtualDiffParents)(nil), // 27: serialization.DbVirtualDiffParents - (*DbBlockCount)(nil), // 28: serialization.DbBlockCount - (*DbBlockHeaderCount)(nil), // 29: serialization.DbBlockHeaderCount + (*DbReachabilityInterval)(nil), // 21: serialization.DbReachabilityInterval + (*DbUtxoDiff)(nil), // 22: serialization.DbUtxoDiff + (*DbPruningPointUTXOSetBytes)(nil), // 23: serialization.DbPruningPointUTXOSetBytes + (*DbHeaderTips)(nil), // 24: serialization.DbHeaderTips + (*DbTips)(nil), // 25: serialization.DbTips + (*DbVirtualDiffParents)(nil), // 26: serialization.DbVirtualDiffParents + (*DbBlockCount)(nil), // 27: serialization.DbBlockCount + (*DbBlockHeaderCount)(nil), // 28: serialization.DbBlockHeaderCount } var file_dbobjects_proto_depIdxs = []int32{ 1, // 0: serialization.DbBlock.header:type_name -> serialization.DbBlockHeader @@ -2056,21 +2002,20 @@ var file_dbobjects_proto_depIdxs = []int32{ 18, // 23: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem 5, // 24: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint 19, // 25: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry - 21, // 26: serialization.DbReachabilityData.treeNode:type_name -> serialization.DbReachabilityTreeNode - 2, // 27: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash - 2, // 28: serialization.DbReachabilityTreeNode.children:type_name -> serialization.DbHash - 2, // 29: serialization.DbReachabilityTreeNode.parent:type_name -> serialization.DbHash - 22, // 30: serialization.DbReachabilityTreeNode.interval:type_name -> serialization.DbReachabilityInterval - 18, // 31: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem - 18, // 32: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem - 2, // 33: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash - 2, // 34: serialization.DbTips.tips:type_name -> serialization.DbHash - 2, // 35: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash - 36, // [36:36] is the sub-list for method output_type - 36, // [36:36] is the sub-list for method input_type - 36, // [36:36] is the sub-list for extension type_name - 36, // [36:36] is the sub-list for extension extendee - 0, // [0:36] is the sub-list for field type_name + 2, // 26: serialization.DbReachabilityData.children:type_name -> serialization.DbHash + 2, // 27: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash + 21, // 28: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval + 2, // 29: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash + 18, // 30: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem + 18, // 31: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem + 2, // 32: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash + 2, // 33: serialization.DbTips.tips:type_name -> serialization.DbHash + 2, // 34: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash + 35, // [35:35] is the sub-list for method output_type + 35, // [35:35] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 35, // [35:35] is the sub-list for extension extendee + 0, // [0:35] is the sub-list for field type_name } func init() { file_dbobjects_proto_init() } @@ -2332,18 +2277,6 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbReachabilityTreeNode); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_dbobjects_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbReachabilityInterval); i { case 0: return &v.state @@ -2355,7 +2288,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbUtxoDiff); i { case 0: return &v.state @@ -2367,7 +2300,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbPruningPointUTXOSetBytes); i { case 0: return &v.state @@ -2379,7 +2312,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbHeaderTips); i { case 0: return &v.state @@ -2391,7 +2324,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbTips); i { case 0: return &v.state @@ -2403,7 +2336,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbVirtualDiffParents); i { case 0: return &v.state @@ -2415,7 +2348,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbBlockCount); i { case 0: return &v.state @@ -2427,7 +2360,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbBlockHeaderCount); i { case 0: return &v.state @@ -2446,7 +2379,7 @@ func file_dbobjects_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_dbobjects_proto_rawDesc, NumEnums: 0, - NumMessages: 30, + NumMessages: 29, NumExtensions: 0, NumServices: 0, }, diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 434887c10..36f31a658 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -117,14 +117,10 @@ message DbUtxoEntry { } message DbReachabilityData { - DbReachabilityTreeNode treeNode = 1; - repeated DbHash futureCoveringSet = 2; -} - -message DbReachabilityTreeNode { repeated DbHash children = 1; DbHash parent = 2; DbReachabilityInterval interval = 3; + repeated DbHash futureCoveringSet = 4; } message DbReachabilityInterval { diff --git a/domain/consensus/database/serialization/reachability_data.go b/domain/consensus/database/serialization/reachability_data.go index 5cde8d689..97473c7c7 100644 --- a/domain/consensus/database/serialization/reachability_data.go +++ b/domain/consensus/database/serialization/reachability_data.go @@ -2,30 +2,48 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/reachabilitydata" ) // ReachablityDataToDBReachablityData converts ReachabilityData to DbReachabilityData -func ReachablityDataToDBReachablityData(reachabilityData *model.ReachabilityData) *DbReachabilityData { +func ReachablityDataToDBReachablityData(reachabilityData model.ReachabilityData) *DbReachabilityData { + parent := reachabilityData.Parent() + var dbParent *DbHash + if parent != nil { + dbParent = DomainHashToDbHash(parent) + } + return &DbReachabilityData{ - TreeNode: reachablityTreeNodeToDBReachablityTreeNode(reachabilityData.TreeNode), - FutureCoveringSet: DomainHashesToDbHashes(reachabilityData.FutureCoveringSet), + Children: DomainHashesToDbHashes(reachabilityData.Children()), + Parent: dbParent, + Interval: reachablityIntervalToDBReachablityInterval(reachabilityData.Interval()), + FutureCoveringSet: DomainHashesToDbHashes(reachabilityData.FutureCoveringSet()), } } // DBReachablityDataToReachablityData converts DbReachabilityData to ReachabilityData -func DBReachablityDataToReachablityData(dbReachabilityData *DbReachabilityData) *model.ReachabilityData { - treeNode, err := dbReachablityTreeNodeToReachablityTreeNode(dbReachabilityData.TreeNode) +func DBReachablityDataToReachablityData(dbReachabilityData *DbReachabilityData) (model.ReachabilityData, error) { + children, err := DbHashesToDomainHashes(dbReachabilityData.Children) if err != nil { - return nil + return nil, err } + var parent *externalapi.DomainHash + if dbReachabilityData.Parent != nil { + var err error + parent, err = DbHashToDomainHash(dbReachabilityData.Parent) + if err != nil { + return nil, err + } + } + + interval := dbReachablityIntervalToReachablityInterval(dbReachabilityData.Interval) + futureCoveringSet, err := DbHashesToDomainHashes(dbReachabilityData.FutureCoveringSet) if err != nil { - return nil + return nil, err } - return &model.ReachabilityData{ - TreeNode: treeNode, - FutureCoveringSet: futureCoveringSet, - } + return reachabilitydata.New(children, parent, interval, futureCoveringSet), nil } diff --git a/domain/consensus/database/serialization/reachability_tree_node.go b/domain/consensus/database/serialization/reachability_tree_node.go deleted file mode 100644 index f181375ca..000000000 --- a/domain/consensus/database/serialization/reachability_tree_node.go +++ /dev/null @@ -1,41 +0,0 @@ -package serialization - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -func reachablityTreeNodeToDBReachablityTreeNode(reachabilityTreeNode *model.ReachabilityTreeNode) *DbReachabilityTreeNode { - var parent *DbHash - if reachabilityTreeNode.Parent != nil { - parent = DomainHashToDbHash(reachabilityTreeNode.Parent) - } - - return &DbReachabilityTreeNode{ - Children: DomainHashesToDbHashes(reachabilityTreeNode.Children), - Parent: parent, - Interval: reachablityIntervalToDBReachablityInterval(reachabilityTreeNode.Interval), - } -} - -func dbReachablityTreeNodeToReachablityTreeNode(dbReachabilityTreeNode *DbReachabilityTreeNode) (*model.ReachabilityTreeNode, error) { - children, err := DbHashesToDomainHashes(dbReachabilityTreeNode.Children) - if err != nil { - return nil, err - } - - var parent *externalapi.DomainHash - if dbReachabilityTreeNode.Parent != nil { - var err error - parent, err = DbHashToDomainHash(dbReachabilityTreeNode.Parent) - if err != nil { - return nil, err - } - } - - return &model.ReachabilityTreeNode{ - Children: children, - Parent: parent, - Interval: dbReachablityIntervalToReachablityInterval(dbReachabilityTreeNode.Interval), - }, nil -} diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index c14f0e997..187510453 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -14,7 +14,7 @@ var reachabilityReindexRootKey = dbkeys.MakeBucket().Key([]byte("reachability-re // reachabilityDataStore represents a store of ReachabilityData type reachabilityDataStore struct { - reachabilityDataStaging map[externalapi.DomainHash]*model.ReachabilityData + reachabilityDataStaging map[externalapi.DomainHash]model.ReachabilityData reachabilityReindexRootStaging *externalapi.DomainHash reachabilityDataCache *lrucache.LRUCache reachabilityReindexRootCache *externalapi.DomainHash @@ -23,15 +23,16 @@ type reachabilityDataStore struct { // New instantiates a new ReachabilityDataStore func New(cacheSize int) model.ReachabilityDataStore { return &reachabilityDataStore{ - reachabilityDataStaging: make(map[externalapi.DomainHash]*model.ReachabilityData), + reachabilityDataStaging: make(map[externalapi.DomainHash]model.ReachabilityData), reachabilityDataCache: lrucache.New(cacheSize), } } // StageReachabilityData stages the given reachabilityData for the given blockHash func (rds *reachabilityDataStore) StageReachabilityData(blockHash *externalapi.DomainHash, - reachabilityData *model.ReachabilityData) { - rds.reachabilityDataStaging[*blockHash] = reachabilityData.Clone() + reachabilityData model.ReachabilityData) { + + rds.reachabilityDataStaging[*blockHash] = reachabilityData } // StageReachabilityReindexRoot stages the given reachabilityReindexRoot @@ -44,7 +45,7 @@ func (rds *reachabilityDataStore) IsAnythingStaged() bool { } func (rds *reachabilityDataStore) Discard() { - rds.reachabilityDataStaging = make(map[externalapi.DomainHash]*model.ReachabilityData) + rds.reachabilityDataStaging = make(map[externalapi.DomainHash]model.ReachabilityData) rds.reachabilityReindexRootStaging = nil } @@ -78,14 +79,14 @@ func (rds *reachabilityDataStore) Commit(dbTx model.DBTransaction) error { // ReachabilityData returns the reachabilityData associated with the given blockHash func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader, - blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) { + blockHash *externalapi.DomainHash) (model.ReachabilityData, error) { if reachabilityData, ok := rds.reachabilityDataStaging[*blockHash]; ok { - return reachabilityData.Clone(), nil + return reachabilityData, nil } if reachabilityData, ok := rds.reachabilityDataCache.Get(blockHash); ok { - return reachabilityData.(*model.ReachabilityData).Clone(), nil + return reachabilityData.(model.ReachabilityData), nil } reachabilityDataBytes, err := dbContext.Get(rds.reachabilityDataBlockHashAsKey(blockHash)) @@ -98,7 +99,7 @@ func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader, return nil, err } rds.reachabilityDataCache.Add(blockHash, reachabilityData) - return reachabilityData.Clone(), nil + return reachabilityData, nil } func (rds *reachabilityDataStore) HasReachabilityData(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { @@ -140,18 +141,18 @@ func (rds *reachabilityDataStore) reachabilityDataBlockHashAsKey(hash *externala return reachabilityDataBucket.Key(hash.ByteSlice()) } -func (rds *reachabilityDataStore) serializeReachabilityData(reachabilityData *model.ReachabilityData) ([]byte, error) { +func (rds *reachabilityDataStore) serializeReachabilityData(reachabilityData model.ReachabilityData) ([]byte, error) { return proto.Marshal(serialization.ReachablityDataToDBReachablityData(reachabilityData)) } -func (rds *reachabilityDataStore) deserializeReachabilityData(reachabilityDataBytes []byte) (*model.ReachabilityData, error) { +func (rds *reachabilityDataStore) deserializeReachabilityData(reachabilityDataBytes []byte) (model.ReachabilityData, error) { dbReachabilityData := &serialization.DbReachabilityData{} err := proto.Unmarshal(reachabilityDataBytes, dbReachabilityData) if err != nil { return nil, err } - return serialization.DBReachablityDataToReachablityData(dbReachabilityData), nil + return serialization.DBReachablityDataToReachablityData(dbReachabilityData) } func (rds *reachabilityDataStore) serializeReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) ([]byte, error) { diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index a428127c7..e267c5380 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -186,7 +186,7 @@ func TestBoundedMergeDepth(t *testing.T) { checkViolatingMergeDepth := func(consensus testapi.TestConsensus, parents []*externalapi.DomainHash) (*externalapi.DomainBlock, bool) { block, _, err := consensus.BuildBlockWithParents(parents, nil, nil) if err != nil { - t.Fatalf("TestBoundedMergeDepth: BuildBlockWithParents failed: %v", err) + t.Fatalf("TestBoundedMergeDepth: BuildBlockWithParents failed: %+v", err) return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns } diff --git a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go index e1225b19e..be77b8f22 100644 --- a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go +++ b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go @@ -5,10 +5,10 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // ReachabilityDataStore represents a store of ReachabilityData type ReachabilityDataStore interface { Store - StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *ReachabilityData) + StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData ReachabilityData) StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) IsAnythingStaged() bool - ReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (*ReachabilityData, error) + ReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (ReachabilityData, error) HasReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) ReachabilityReindexRoot(dbContext DBReader) (*externalapi.DomainHash, error) } diff --git a/domain/consensus/model/reachabilitydata.go b/domain/consensus/model/reachabilitydata.go index d95e5f809..718d47c55 100644 --- a/domain/consensus/model/reachabilitydata.go +++ b/domain/consensus/model/reachabilitydata.go @@ -6,43 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// ReachabilityData holds the set of data required to answer -// reachability queries -type ReachabilityData struct { - TreeNode *ReachabilityTreeNode - FutureCoveringSet FutureCoveringTreeNodeSet -} - -// If this doesn't compile, it means the type definition has been changed, so it's -// an indication to update Equal and Clone accordingly. -var _ = &ReachabilityData{&ReachabilityTreeNode{}, FutureCoveringTreeNodeSet{}} - -// Equal returns whether rd equals to other -func (rd *ReachabilityData) Equal(other *ReachabilityData) bool { - if rd == nil || other == nil { - return rd == other - } - - if !rd.TreeNode.Equal(other.TreeNode) { - return false - } - - if !rd.FutureCoveringSet.Equal(other.FutureCoveringSet) { - return false - } - - return true -} - -// Clone returns a clone of ReachabilityData -func (rd *ReachabilityData) Clone() *ReachabilityData { - return &ReachabilityData{ - TreeNode: rd.TreeNode.Clone(), - FutureCoveringSet: rd.FutureCoveringSet.Clone(), - } -} - -// ReachabilityTreeNode represents a node in the reachability tree +// MutableReachabilityData represents a node in the reachability tree // of some DAG block. It mainly provides the ability to query *tree* // reachability with O(1) query time. It does so by managing an // index interval for each node and making sure all nodes in its @@ -57,48 +21,30 @@ func (rd *ReachabilityData) Clone() *ReachabilityData { // (e.g., [0, 2^64-1]) should always suffice for any practical use- // case, and so reindexing should always succeed unless more than // 2^64 blocks are added to the DAG/tree. -type ReachabilityTreeNode struct { - Children []*externalapi.DomainHash - Parent *externalapi.DomainHash +// +// In addition, we keep a future covering set for every node. +// This set allows to query reachability over the entirety of the DAG. +// See documentation of FutureCoveringTreeNodeSet for additional details. - // interval is the index interval containing all intervals of - // blocks in this node's subtree - Interval *ReachabilityInterval +// ReachabilityData is a read-only version of a block's MutableReachabilityData +// Use CloneWritable to edit the MutableReachabilityData. +type ReachabilityData interface { + Children() []*externalapi.DomainHash + Parent() *externalapi.DomainHash + Interval() *ReachabilityInterval + FutureCoveringSet() FutureCoveringTreeNodeSet + CloneMutable() MutableReachabilityData + Equal(other ReachabilityData) bool } -// If this doesn't compile, it means the type definition has been changed, so it's -// an indication to update Equal and Clone accordingly. -var _ = &ReachabilityTreeNode{[]*externalapi.DomainHash{}, &externalapi.DomainHash{}, - &ReachabilityInterval{}} +// MutableReachabilityData represents a block's MutableReachabilityData, with ability to edit it +type MutableReachabilityData interface { + ReachabilityData -// Equal returns whether rtn equals to other -func (rtn *ReachabilityTreeNode) Equal(other *ReachabilityTreeNode) bool { - if rtn == nil || other == nil { - return rtn == other - } - - if !externalapi.HashesEqual(rtn.Children, other.Children) { - return false - } - - if !rtn.Parent.Equal(other.Parent) { - return false - } - - if !rtn.Interval.Equal(other.Interval) { - return false - } - - return true -} - -// Clone returns a clone of ReachabilityTreeNode -func (rtn *ReachabilityTreeNode) Clone() *ReachabilityTreeNode { - return &ReachabilityTreeNode{ - Children: externalapi.CloneHashes(rtn.Children), - Parent: rtn.Parent, - Interval: rtn.Interval.Clone(), - } + AddChild(child *externalapi.DomainHash) + SetParent(parent *externalapi.DomainHash) + SetInterval(interval *ReachabilityInterval) + SetFutureCoveringSet(futureCoveringSet FutureCoveringTreeNodeSet) } // ReachabilityInterval represents an interval to be used within the diff --git a/domain/consensus/model/reachabilitydata_equal_clone_test.go b/domain/consensus/model/reachabilitydata_equal_clone_test.go deleted file mode 100644 index a4251ddfa..000000000 --- a/domain/consensus/model/reachabilitydata_equal_clone_test.go +++ /dev/null @@ -1,354 +0,0 @@ -package model - -import ( - "reflect" - "testing" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -func TestReachabilityData_Equal(t *testing.T) { - type dataToCompare struct { - data *ReachabilityData - expectedResult bool - } - tests := []struct { - baseData *ReachabilityData - dataToCompareTo []dataToCompare - }{ - // Test nil data - { - baseData: nil, - dataToCompareTo: nil, - }, - // Test empty data - { - baseData: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - &externalapi.DomainHash{}, - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{}, - }, - dataToCompareTo: []dataToCompare{ - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - &externalapi.DomainHash{}, - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{}, - }, - expectedResult: true, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - }, // Changed - &externalapi.DomainHash{}, - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), // Changed - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - &externalapi.DomainHash{}, - &ReachabilityInterval{100, 0}, // Changed start - }, - FutureCoveringTreeNodeSet{}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - &externalapi.DomainHash{}, - &ReachabilityInterval{0, 100}, // Changed end - }, - FutureCoveringTreeNodeSet{}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - &externalapi.DomainHash{}, - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, // Changed - }, - expectedResult: false, - }, - }, - }, - // Test filled data - { - baseData: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - dataToCompareTo: []dataToCompare{ - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: true, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{}, // Changed - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{200, 200}, // Changed start - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - nil, //Changed - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 100}, // Changed end - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, // Changed - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - &externalapi.DomainHash{}, // Changed - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{}, // Changed - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{}, // Changed - }, - expectedResult: false, - }, - { - data: &ReachabilityData{ - nil, - FutureCoveringTreeNodeSet{}, - }, - expectedResult: false, - }, - { - data: nil, - expectedResult: false, - }, - }, - }, - } - - for i, test := range tests { - for j, subTest := range test.dataToCompareTo { - result1 := test.baseData.Equal(subTest.data) - if result1 != subTest.expectedResult { - t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) - } - - result2 := subTest.data.Equal(test.baseData) - if result2 != subTest.expectedResult { - t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) - } - } - } -} - -func TestReachabilityData_Clone(t *testing.T) { - testData := []*ReachabilityData{ - { - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - &externalapi.DomainHash{}, - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{}, - }, - { - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - { - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - { - &ReachabilityTreeNode{ - []*externalapi.DomainHash{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - { - &ReachabilityTreeNode{ - []*externalapi.DomainHash{}, - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - &ReachabilityInterval{100, 200}, - }, - FutureCoveringTreeNodeSet{ - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, - }, - } - - for i, data := range testData { - clone := data.Clone() - if !clone.Equal(data) { - t.Fatalf("Test #%d: clone should be equal to the original", i) - } - - if !reflect.DeepEqual(data, clone) { - t.Fatalf("Test #%d: clone should be equal to the original", i) - } - } -} diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index 21e9646ef..c5e22bb76 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -21,7 +21,7 @@ func (s *selectedChildIterator) Next() bool { panic(err) } - for _, child := range data.TreeNode.Children { + for _, child := range data.Children() { isChildInSelectedParentChainOfHighHash, err := s.dagTopologyManager.IsInSelectedParentChainOf(child, s.highHash) if err != nil { panic(err) diff --git a/domain/consensus/processes/ghostdagmanager/mergeset.go b/domain/consensus/processes/ghostdagmanager/mergeset.go index 4668eb127..9124ce3ce 100644 --- a/domain/consensus/processes/ghostdagmanager/mergeset.go +++ b/domain/consensus/processes/ghostdagmanager/mergeset.go @@ -1,11 +1,12 @@ package ghostdagmanager import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "sort" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -func (gm *ghostdagManager) mergeSetWithoutSelectedParent(selecteParent *externalapi.DomainHash, +func (gm *ghostdagManager) mergeSetWithoutSelectedParent(selectedParent *externalapi.DomainHash, blockParents []*externalapi.DomainHash) ([]*externalapi.DomainHash, error) { mergeSetMap := make(map[externalapi.DomainHash]struct{}, gm.k) @@ -14,7 +15,7 @@ func (gm *ghostdagManager) mergeSetWithoutSelectedParent(selecteParent *external queue := []*externalapi.DomainHash{} // Queueing all parents (other than the selected parent itself) for processing. for _, parent := range blockParents { - if parent.Equal(selecteParent) { + if parent.Equal(selectedParent) { continue } mergeSetMap[*parent] = struct{}{} @@ -40,7 +41,7 @@ func (gm *ghostdagManager) mergeSetWithoutSelectedParent(selecteParent *external continue } - isAncestorOfSelectedParent, err := gm.dagTopologyManager.IsAncestorOf(parent, selecteParent) + isAncestorOfSelectedParent, err := gm.dagTopologyManager.IsAncestorOf(parent, selectedParent) if err != nil { return nil, err } diff --git a/domain/consensus/processes/reachabilitymanager/fetch.go b/domain/consensus/processes/reachabilitymanager/fetch.go index 9805a4e35..d314b3cb1 100644 --- a/domain/consensus/processes/reachabilitymanager/fetch.go +++ b/domain/consensus/processes/reachabilitymanager/fetch.go @@ -3,67 +3,62 @@ package reachabilitymanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/reachabilitydata" ) -func (rt *reachabilityManager) data(blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) { +func (rt *reachabilityManager) reachabilityDataForInsertion( + blockHash *externalapi.DomainHash) (model.MutableReachabilityData, error) { + hasData, err := rt.reachabilityDataStore.HasReachabilityData(rt.databaseContext, blockHash) if err != nil { return nil, err } if !hasData { - return &model.ReachabilityData{ - TreeNode: nil, - FutureCoveringSet: nil, - }, nil + return reachabilitydata.EmptyReachabilityData(), nil } - return rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) + data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) + if err != nil { + return nil, err + } + return data.CloneMutable(), nil } -func (rt *reachabilityManager) futureCoveringSet(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - data, err := rt.data(blockHash) +func (rt *reachabilityManager) futureCoveringSet(blockHash *externalapi.DomainHash) (model.FutureCoveringTreeNodeSet, error) { + data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) if err != nil { return nil, err } - return data.FutureCoveringSet, nil -} - -func (rt *reachabilityManager) treeNode(blockHash *externalapi.DomainHash) (*model.ReachabilityTreeNode, error) { - data, err := rt.data(blockHash) - if err != nil { - return nil, err - } - - return data.TreeNode, nil + return data.FutureCoveringSet(), nil } func (rt *reachabilityManager) interval(blockHash *externalapi.DomainHash) (*model.ReachabilityInterval, error) { - treeNode, err := rt.treeNode(blockHash) + data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) if err != nil { return nil, err } - return treeNode.Interval, nil + return data.Interval(), nil } func (rt *reachabilityManager) children(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - data, err := rt.data(blockHash) + data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) if err != nil { return nil, err } - return data.TreeNode.Children, nil + return data.Children(), nil } func (rt *reachabilityManager) parent(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - data, err := rt.data(blockHash) + data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) if err != nil { return nil, err } - return data.TreeNode.Parent, nil + return data.Parent(), nil } func (rt *reachabilityManager) reindexRoot() (*externalapi.DomainHash, error) { diff --git a/domain/consensus/processes/reachabilitymanager/future_covering_set.go b/domain/consensus/processes/reachabilitymanager/future_covering_set.go index cfee01075..70d54672b 100644 --- a/domain/consensus/processes/reachabilitymanager/future_covering_set.go +++ b/domain/consensus/processes/reachabilitymanager/future_covering_set.go @@ -19,59 +19,57 @@ import ( // is-superset relation will by definition // be always preserved. func (rt *reachabilityManager) insertToFutureCoveringSet(node, futureNode *externalapi.DomainHash) error { - futureCoveringSet, err := rt.futureCoveringSet(node) - if err != nil { - return err - } - - ancestorIndex, ok, err := rt.findAncestorIndexOfNode(futureCoveringSet, futureNode) + reachabilityData, err := rt.reachabilityDataForInsertion(node) + if err != nil { + return err + } + futureCoveringSet := reachabilityData.FutureCoveringSet() + + ancestorIndex, ok, err := rt.findAncestorIndexOfNode(orderedTreeNodeSet(futureCoveringSet), futureNode) if err != nil { return err } + var newSet []*externalapi.DomainHash if !ok { - newSet := append([]*externalapi.DomainHash{futureNode}, futureCoveringSet...) - err := rt.stageFutureCoveringSet(node, newSet) + newSet = append([]*externalapi.DomainHash{futureNode}, futureCoveringSet...) + } else { + candidate := futureCoveringSet[ancestorIndex] + candidateIsAncestorOfFutureNode, err := rt.IsReachabilityTreeAncestorOf(candidate, futureNode) if err != nil { return err } - return nil + if candidateIsAncestorOfFutureNode { + // candidate is an ancestor of futureNode, no need to insert + return nil + } + + futureNodeIsAncestorOfCandidate, err := rt.IsReachabilityTreeAncestorOf(futureNode, candidate) + if err != nil { + return err + } + + if futureNodeIsAncestorOfCandidate { + // futureNode is an ancestor of candidate, and can thus replace it + newSet := make([]*externalapi.DomainHash, len(futureCoveringSet)) + copy(newSet, futureCoveringSet) + newSet[ancestorIndex] = futureNode + + return rt.stageFutureCoveringSet(node, newSet) + } + + // Insert futureNode in the correct index to maintain futureCoveringTreeNodeSet as + // a sorted-by-interval list. + // Note that ancestorIndex might be equal to len(futureCoveringTreeNodeSet) + left := futureCoveringSet[:ancestorIndex+1] + right := append([]*externalapi.DomainHash{futureNode}, futureCoveringSet[ancestorIndex+1:]...) + newSet = append(left, right...) } + reachabilityData.SetFutureCoveringSet(newSet) + rt.stageData(node, reachabilityData) - candidate := futureCoveringSet[ancestorIndex] - candidateIsAncestorOfFutureNode, err := rt.IsReachabilityTreeAncestorOf(candidate, futureNode) - if err != nil { - return err - } - - if candidateIsAncestorOfFutureNode { - // candidate is an ancestor of futureNode, no need to insert - return nil - } - - futureNodeIsAncestorOfCandidate, err := rt.IsReachabilityTreeAncestorOf(futureNode, candidate) - if err != nil { - return err - } - - if futureNodeIsAncestorOfCandidate { - // futureNode is an ancestor of candidate, and can thus replace it - newSet := make([]*externalapi.DomainHash, len(futureCoveringSet)) - copy(newSet, futureCoveringSet) - newSet[ancestorIndex] = futureNode - - return rt.stageFutureCoveringSet(node, newSet) - } - - // Insert futureNode in the correct index to maintain futureCoveringTreeNodeSet as - // a sorted-by-interval list. - // Note that ancestorIndex might be equal to len(futureCoveringTreeNodeSet) - left := futureCoveringSet[:ancestorIndex+1] - right := append([]*externalapi.DomainHash{futureNode}, futureCoveringSet[ancestorIndex+1:]...) - newSet := append(left, right...) - return rt.stageFutureCoveringSet(node, newSet) - + return nil } // futureCoveringSetHasAncestorOf resolves whether the given node `other` is in the subtree of @@ -88,7 +86,7 @@ func (rt *reachabilityManager) futureCoveringSetHasAncestorOf(this, other *exter return false, err } - ancestorIndex, ok, err := rt.findAncestorIndexOfNode(futureCoveringSet, other) + ancestorIndex, ok, err := rt.findAncestorIndexOfNode(orderedTreeNodeSet(futureCoveringSet), other) if err != nil { return false, err } @@ -99,5 +97,6 @@ func (rt *reachabilityManager) futureCoveringSetHasAncestorOf(this, other *exter } candidate := futureCoveringSet[ancestorIndex] + return rt.IsReachabilityTreeAncestorOf(candidate, other) } diff --git a/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go b/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go index 0713ceda0..84f06fe09 100644 --- a/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go +++ b/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go @@ -5,7 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// orderedTreeNodeSet is an ordered set of model.ReachabilityTreeNodes +// orderedTreeNodeSet is an ordered set of model.DomainHash ordered by the respectful intervals. // Note that this type does not validate order validity. It's the // responsibility of the caller to construct instances of this // type properly. @@ -31,12 +31,10 @@ func (rt *reachabilityManager) findAncestorOfNode(tns orderedTreeNodeSet, node * // the index of the block with the maximum start that is below the // given block. func (rt *reachabilityManager) findAncestorIndexOfNode(tns orderedTreeNodeSet, node *externalapi.DomainHash) (int, bool, error) { - treeNode, err := rt.treeNode(node) + blockInterval, err := rt.interval(node) if err != nil { return 0, false, err } - - blockInterval := treeNode.Interval end := blockInterval.End low := 0 diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index 01f0aaac6..f35b85a15 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -81,7 +81,7 @@ func TestUpdateReindexRoot(t *testing.T) { if err != nil { t.Fatalf("ReachabilityData: %s", err) } - return data.TreeNode.Interval.End - data.TreeNode.Interval.Start + 1 + return data.Interval().End - data.Interval().Start + 1 } // Add two blocks on top of the genesis block @@ -171,7 +171,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { if err != nil { t.Fatalf("ReachabilityData: %s", err) } - return data.TreeNode.Interval.End - data.TreeNode.Interval.Start + 1 + return data.Interval().End - data.Interval().Start + 1 } // Add three children to the genesis: leftBlock, centerBlock, rightBlock @@ -242,7 +242,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { t.Fatalf("ReachabilityData: %s", err) } - treeChildOfCenterBlock := centerData.TreeNode.Children[0] + treeChildOfCenterBlock := centerData.Children()[0] treeChildOfCenterBlockOriginalIntervalSize := intervalSize(treeChildOfCenterBlock) leftTipHash := leftBlock for i := uint64(0); i < reachabilityReindexWindow-1; i++ { diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go index cb45f6ad1..3a873ec27 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go @@ -11,7 +11,7 @@ import ( ) type reachabilityDataStoreMock struct { - reachabilityDataStaging map[externalapi.DomainHash]*model.ReachabilityData + reachabilityDataStaging map[externalapi.DomainHash]model.ReachabilityData recorder map[externalapi.DomainHash]struct{} reachabilityReindexRootStaging *externalapi.DomainHash } @@ -24,7 +24,9 @@ func (r *reachabilityDataStoreMock) Commit(_ model.DBTransaction) error { panic("implement me") } -func (r *reachabilityDataStoreMock) StageReachabilityData(blockHash *externalapi.DomainHash, reachabilityData *model.ReachabilityData) { +func (r *reachabilityDataStoreMock) StageReachabilityData( + blockHash *externalapi.DomainHash, reachabilityData model.ReachabilityData) { + r.reachabilityDataStaging[*blockHash] = reachabilityData r.recorder[*blockHash] = struct{}{} } @@ -37,7 +39,9 @@ func (r *reachabilityDataStoreMock) IsAnythingStaged() bool { panic("implement me") } -func (r *reachabilityDataStoreMock) ReachabilityData(_ model.DBReader, blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) { +func (r *reachabilityDataStoreMock) ReachabilityData(_ model.DBReader, blockHash *externalapi.DomainHash) ( + model.ReachabilityData, error) { + return r.reachabilityDataStaging[*blockHash], nil } @@ -70,7 +74,7 @@ func (r *reachabilityDataStoreMock) resetRecorder() { func newReachabilityDataStoreMock() *reachabilityDataStoreMock { return &reachabilityDataStoreMock{ - reachabilityDataStaging: make(map[externalapi.DomainHash]*model.ReachabilityData), + reachabilityDataStaging: make(map[externalapi.DomainHash]model.ReachabilityData), recorder: make(map[externalapi.DomainHash]struct{}), reachabilityReindexRootStaging: nil, } @@ -96,11 +100,7 @@ func (th *testHelper) generateHash() *externalapi.DomainHash { func (th *testHelper) newNode() *externalapi.DomainHash { node := th.generateHash() - err := th.stageTreeNode(node, newReachabilityTreeNode()) - if err != nil { - th.t.Fatalf("stageTreeNode: %s", err) - } - + th.stageData(node, newReachabilityTreeData()) return node } @@ -793,7 +793,7 @@ func TestInsertToFutureCoveringSet(t *testing.T) { if err != nil { t.Fatalf("futureCoveringSet: %s", err) } - if !reflect.DeepEqual(model.FutureCoveringTreeNodeSet(resultFutureCoveringTreeNodeSet), test.expectedResult) { + if !reflect.DeepEqual(resultFutureCoveringTreeNodeSet, test.expectedResult) { t.Errorf("TestInsertToFutureCoveringSet: unexpected result in test #%d. Want: %s, got: %s", i, test.expectedResult, resultFutureCoveringTreeNodeSet) } diff --git a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go index 577239571..ad00735db 100644 --- a/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/reachabilitymanager.go @@ -32,12 +32,9 @@ func New( // AddBlock adds the block with the given blockHash into the reachability tree. func (rt *reachabilityManager) AddBlock(blockHash *externalapi.DomainHash) error { - // Allocate a new reachability tree node - newTreeNode := newReachabilityTreeNode() - err := rt.stageTreeNode(blockHash, newTreeNode) - if err != nil { - return err - } + // Allocate a new reachability data + newReachabilityData := newReachabilityTreeData() + rt.stageData(blockHash, newReachabilityData) ghostdagData, err := rt.ghostdagDataStore.Get(rt.databaseContext, blockHash) if err != nil { diff --git a/domain/consensus/processes/reachabilitymanager/stage.go b/domain/consensus/processes/reachabilitymanager/stage.go index 0c38d61d8..fb58a9b4e 100644 --- a/domain/consensus/processes/reachabilitymanager/stage.go +++ b/domain/consensus/processes/reachabilitymanager/stage.go @@ -5,28 +5,18 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data *model.ReachabilityData) { +func (rt *reachabilityManager) stageData(blockHash *externalapi.DomainHash, data model.ReachabilityData) { rt.reachabilityDataStore.StageReachabilityData(blockHash, data) } func (rt *reachabilityManager) stageFutureCoveringSet(blockHash *externalapi.DomainHash, set model.FutureCoveringTreeNodeSet) error { - data, err := rt.data(blockHash) + data, err := rt.reachabilityDataForInsertion(blockHash) if err != nil { return err } - data.FutureCoveringSet = set - rt.reachabilityDataStore.StageReachabilityData(blockHash, data) - return nil -} + data.SetFutureCoveringSet(set) -func (rt *reachabilityManager) stageTreeNode(blockHash *externalapi.DomainHash, node *model.ReachabilityTreeNode) error { - data, err := rt.data(blockHash) - if err != nil { - return err - } - - data.TreeNode = node rt.reachabilityDataStore.StageReachabilityData(blockHash, data) return nil } @@ -36,31 +26,35 @@ func (rt *reachabilityManager) stageReindexRoot(blockHash *externalapi.DomainHas } func (rt *reachabilityManager) addChildAndStage(node, child *externalapi.DomainHash) error { - nodeData, err := rt.data(node) + nodeData, err := rt.reachabilityDataForInsertion(node) if err != nil { return err } - nodeData.TreeNode.Children = append(nodeData.TreeNode.Children, child) - return rt.stageTreeNode(node, nodeData.TreeNode) + nodeData.AddChild(child) + rt.stageData(node, nodeData) + + return nil } func (rt *reachabilityManager) stageParent(node, parent *externalapi.DomainHash) error { - treeNode, err := rt.treeNode(node) + nodeData, err := rt.reachabilityDataForInsertion(node) if err != nil { return err } + nodeData.SetParent(parent) + rt.stageData(node, nodeData) - treeNode.Parent = parent - return rt.stageTreeNode(node, treeNode) + return nil } func (rt *reachabilityManager) stageInterval(node *externalapi.DomainHash, interval *model.ReachabilityInterval) error { - treeNode, err := rt.treeNode(node) + nodeData, err := rt.reachabilityDataForInsertion(node) if err != nil { return err } + nodeData.SetInterval(interval) + rt.stageData(node, nodeData) - treeNode.Interval = interval - return rt.stageTreeNode(node, treeNode) + return nil } diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 2e2f3398c..540f1770a 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -5,6 +5,8 @@ import ( "strings" "time" + "github.com/kaspanet/kaspad/domain/consensus/utils/reachabilitydata" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -57,11 +59,14 @@ func exponentialFractions(sizes []uint64) []float64 { return fractions } -func newReachabilityTreeNode() *model.ReachabilityTreeNode { +func newReachabilityTreeData() model.ReachabilityData { // Please see the comment above model.ReachabilityTreeNode to understand why // we use these initial values. interval := newReachabilityInterval(1, math.MaxUint64-1) - return &model.ReachabilityTreeNode{Interval: interval} + data := reachabilitydata.EmptyReachabilityData() + data.SetInterval(interval) + + return data } func (rt *reachabilityManager) intervalRangeForChildAllocation(hash *externalapi.DomainHash) (*model.ReachabilityInterval, error) { diff --git a/domain/consensus/utils/reachabilitydata/reachability_data.go b/domain/consensus/utils/reachabilitydata/reachability_data.go new file mode 100644 index 000000000..3d9ca8bb1 --- /dev/null +++ b/domain/consensus/utils/reachabilitydata/reachability_data.go @@ -0,0 +1,111 @@ +package reachabilitydata + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +type reachabilityData struct { + children []*externalapi.DomainHash + parent *externalapi.DomainHash + interval *model.ReachabilityInterval + futureCoveringSet model.FutureCoveringTreeNodeSet +} + +// If this doesn't compile, it means the type definition has been changed, so it's +// an indication to update Equal and Clone accordingly. +var _ = &reachabilityData{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{}, +} + +// EmptyReachabilityData constructs an empty MutableReachabilityData object +func EmptyReachabilityData() model.MutableReachabilityData { + return &reachabilityData{} +} + +// New constructs a ReachabilityData object filled with given fields +func New(children []*externalapi.DomainHash, + parent *externalapi.DomainHash, + interval *model.ReachabilityInterval, + futureCoveringSet model.FutureCoveringTreeNodeSet) model.ReachabilityData { + + return &reachabilityData{ + children: children, + parent: parent, + interval: interval, + futureCoveringSet: futureCoveringSet, + } +} + +func (rd *reachabilityData) Children() []*externalapi.DomainHash { + return rd.children +} + +func (rd *reachabilityData) Parent() *externalapi.DomainHash { + return rd.parent +} + +func (rd *reachabilityData) Interval() *model.ReachabilityInterval { + return rd.interval +} + +func (rd *reachabilityData) FutureCoveringSet() model.FutureCoveringTreeNodeSet { + return rd.futureCoveringSet +} + +func (rd *reachabilityData) CloneMutable() model.MutableReachabilityData { + return &reachabilityData{ + children: externalapi.CloneHashes(rd.children), + parent: rd.parent, + interval: rd.interval.Clone(), + futureCoveringSet: rd.futureCoveringSet.Clone(), + } +} + +func (rd *reachabilityData) AddChild(child *externalapi.DomainHash) { + rd.children = append(rd.children, child) +} + +func (rd *reachabilityData) SetParent(parent *externalapi.DomainHash) { + rd.parent = parent +} + +func (rd *reachabilityData) SetInterval(interval *model.ReachabilityInterval) { + rd.interval = interval +} + +func (rd *reachabilityData) SetFutureCoveringSet(futureCoveringSet model.FutureCoveringTreeNodeSet) { + rd.futureCoveringSet = futureCoveringSet +} + +// Equal returns whether rd equals to other +func (rd *reachabilityData) Equal(other model.ReachabilityData) bool { + otherReachabilityData, ok := other.(*reachabilityData) + if !ok { + return false + } + if rd == nil || otherReachabilityData == nil { + return rd == otherReachabilityData + } + + if !externalapi.HashesEqual(rd.children, otherReachabilityData.Children()) { + return false + } + + if !rd.parent.Equal(otherReachabilityData.Parent()) { + return false + } + + if !rd.interval.Equal(otherReachabilityData.Interval()) { + return false + } + + if !rd.futureCoveringSet.Equal(otherReachabilityData.FutureCoveringSet()) { + return false + } + + return true +} diff --git a/domain/consensus/utils/reachabilitydata/reachabilitydata_equal_clone_test.go b/domain/consensus/utils/reachabilitydata/reachabilitydata_equal_clone_test.go new file mode 100644 index 000000000..c3811c9f8 --- /dev/null +++ b/domain/consensus/utils/reachabilitydata/reachabilitydata_equal_clone_test.go @@ -0,0 +1,313 @@ +package reachabilitydata + +import ( + "reflect" + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +func TestReachabilityData_Equal(t *testing.T) { + type dataToCompare struct { + data *reachabilityData + expectedResult bool + } + tests := []struct { + baseData *reachabilityData + dataToCompareTo []dataToCompare + }{ + // Test nil data + { + baseData: nil, + dataToCompareTo: nil, + }, + // Test empty data + { + baseData: &reachabilityData{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{}, + }, + dataToCompareTo: []dataToCompare{ + { + data: &reachabilityData{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{}, + }, + expectedResult: true, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + }, // Changed + &externalapi.DomainHash{}, + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), // Changed + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{100, 0}, // Changed start + model.FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{0, 100}, // Changed end + model.FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, // Changed + }, + expectedResult: false, + }, + }, + }, + // Test filled data + { + baseData: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + dataToCompareTo: []dataToCompare{ + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: true, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{}, // Changed + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{200, 200}, // Changed start + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + nil, //Changed + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 100}, // Changed end + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{}, // Changed + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + &externalapi.DomainHash{}, // Changed + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{}, // Changed + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{}, // Changed + }, + expectedResult: false, + }, + { + data: &reachabilityData{ + nil, + nil, + nil, + model.FutureCoveringTreeNodeSet{}, + }, + expectedResult: false, + }, + { + data: nil, + expectedResult: false, + }, + }, + }, + } + + for i, test := range tests { + for j, subTest := range test.dataToCompareTo { + result1 := test.baseData.Equal(subTest.data) + if result1 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result1) + } + + result2 := subTest.data.Equal(test.baseData) + if result2 != subTest.expectedResult { + t.Fatalf("Test #%d:%d: Expected %t but got %t", i, j, subTest.expectedResult, result2) + } + } + } +} + +func TestReachabilityData_CloneWritable(t *testing.T) { + testData := []*reachabilityData{ + { + []*externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{}, + }, + { + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + { + []*externalapi.DomainHash{}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + { + []*externalapi.DomainHash{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + { + []*externalapi.DomainHash{}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + &model.ReachabilityInterval{100, 200}, + model.FutureCoveringTreeNodeSet{ + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + }, + } + + for i, data := range testData { + clone := data.CloneMutable() + if !clone.Equal(data) { + t.Fatalf("Test #%d: clone should be equal to the original", i) + } + + if !reflect.DeepEqual(data, clone) { + t.Fatalf("Test #%d: clone should be equal to the original", i) + } + } +} From d917a1fc1eac275d23710f42d5050327303743a3 Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 30 Dec 2020 12:37:23 +0200 Subject: [PATCH 184/351] Remove the block delay from kaspaminer (#1320) --- cmd/kaspaminer/config.go | 1 - cmd/kaspaminer/main.go | 5 +++-- cmd/kaspaminer/mineloop.go | 23 +++++++---------------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/cmd/kaspaminer/config.go b/cmd/kaspaminer/config.go index c1ac0d3aa..243dbf22e 100644 --- a/cmd/kaspaminer/config.go +++ b/cmd/kaspaminer/config.go @@ -34,7 +34,6 @@ type configFlags struct { RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` MiningAddr string `long:"miningaddr" description:"Address to mine to"` NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."` - BlockDelay uint64 `long:"block-delay" description:"Delay for block submission (in milliseconds). This is used only for testing purposes."` MineWhenNotSynced bool `long:"mine-when-not-synced" description:"Mine even if the node is not synced with the rest of the network."` Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` config.NetworkFlags diff --git a/cmd/kaspaminer/main.go b/cmd/kaspaminer/main.go index 6acc8a032..a4a85fa7a 100644 --- a/cmd/kaspaminer/main.go +++ b/cmd/kaspaminer/main.go @@ -2,9 +2,10 @@ package main import ( "fmt" - "github.com/kaspanet/kaspad/util" "os" + "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/version" "github.com/pkg/errors" @@ -47,7 +48,7 @@ func main() { doneChan := make(chan struct{}) spawn("mineLoop", func() { - err = mineLoop(client, cfg.NumberOfBlocks, cfg.BlockDelay, cfg.MineWhenNotSynced, miningAddr) + err = mineLoop(client, cfg.NumberOfBlocks, cfg.MineWhenNotSynced, miningAddr) if err != nil { panic(errors.Wrap(err, "error in mine loop")) } diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 96d244d55..2538769e5 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -2,12 +2,12 @@ package main import ( nativeerrors "errors" - "github.com/kaspanet/kaspad/domain/consensus/model/pow" "math/rand" - "sync" "sync/atomic" "time" + "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -24,7 +24,7 @@ var hashesTried uint64 const logHashRateInterval = 10 * time.Second -func mineLoop(client *minerClient, numberOfBlocks uint64, blockDelay uint64, mineWhenNotSynced bool, +func mineLoop(client *minerClient, numberOfBlocks uint64, mineWhenNotSynced bool, miningAddr util.Address) error { errChan := make(chan error) @@ -33,25 +33,16 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, blockDelay uint64, min doneChan := make(chan struct{}) spawn("mineLoop-internalLoop", func() { - wg := sync.WaitGroup{} for i := uint64(0); numberOfBlocks == 0 || i < numberOfBlocks; i++ { foundBlock := make(chan *externalapi.DomainBlock) mineNextBlock(client, miningAddr, foundBlock, mineWhenNotSynced, templateStopChan, errChan) block := <-foundBlock templateStopChan <- struct{}{} - wg.Add(1) - spawn("mineLoop-handleFoundBlock", func() { - if blockDelay != 0 { - time.Sleep(time.Duration(blockDelay) * time.Millisecond) - } - err := handleFoundBlock(client, block) - if err != nil { - errChan <- err - } - wg.Done() - }) + err := handleFoundBlock(client, block) + if err != nil { + errChan <- err + } } - wg.Wait() doneChan <- struct{}{} }) From bd89ca2125c3b02d64ad4347335adbd4c160123d Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 30 Dec 2020 13:02:34 +0200 Subject: [PATCH 185/351] Log only tips length, and inspect ReachabilityData error instead of calling HasReachabilityData (#1321) * Print the amount of tips instead of the tips themselves * Inspect ReachabilityData error instead of calling HasReachabilityData --- .../add_block_to_virtual.go | 5 ++--- .../pick_virtual_parents.go | 4 ++-- .../consensusstatemanager/update_virtual.go | 2 +- .../processes/reachabilitymanager/fetch.go | 18 +++++++----------- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index ef9e6cc83..5b8478974 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -53,7 +53,7 @@ func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (* if err != nil { return nil, err } - log.Debugf("After adding %s, the new tips are %s", blockHash, newTips) + log.Debugf("After adding %s, the amount of new tips are %d", blockHash, len(newTips)) log.Debugf("Updating the virtual with the new tips") selectedParentChainChanges, err := csm.updateVirtual(blockHash, newTips) @@ -99,10 +99,9 @@ func (csm *consensusStateManager) addTip(newTipHash *externalapi.DomainHash) (ne if err != nil { return nil, err } - log.Debugf("The new tips are: %s", newTips) csm.consensusStateStore.StageTips(newTips) - log.Debugf("Staged the new tips %s", newTips) + log.Debugf("Staged the new tips, len: %d", len(newTips)) return newTips, nil } diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 2fef4256e..7779e3056 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -9,8 +9,8 @@ import ( ) func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainHash) ([]*externalapi.DomainHash, error) { - log.Debugf("pickVirtualParents start for tips: %s", tips) - defer log.Debugf("pickVirtualParents end for tips: %s", tips) + log.Debugf("pickVirtualParents start for tips len: %d", len(tips)) + defer log.Debugf("pickVirtualParents end for tips len: %d", len(tips)) log.Debugf("Pushing all tips into a DownHeap") candidatesHeap := csm.dagTraversalManager.NewDownHeap() diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index aa56d6848..a2752bcfa 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -21,7 +21,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain oldVirtualSelectedParent = oldVirtualGHOSTDAGData.SelectedParent() } - log.Debugf("Picking virtual parents from the tips: %s", tips) + log.Debugf("Picking virtual parents from tips len: %d", len(tips)) virtualParents, err := csm.pickVirtualParents(tips) if err != nil { return nil, err diff --git a/domain/consensus/processes/reachabilitymanager/fetch.go b/domain/consensus/processes/reachabilitymanager/fetch.go index d314b3cb1..561105eed 100644 --- a/domain/consensus/processes/reachabilitymanager/fetch.go +++ b/domain/consensus/processes/reachabilitymanager/fetch.go @@ -4,25 +4,21 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/reachabilitydata" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/pkg/errors" ) func (rt *reachabilityManager) reachabilityDataForInsertion( blockHash *externalapi.DomainHash) (model.MutableReachabilityData, error) { - - hasData, err := rt.reachabilityDataStore.HasReachabilityData(rt.databaseContext, blockHash) - if err != nil { - return nil, err + data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) + if err == nil { + return data.CloneMutable(), nil } - if !hasData { + if errors.Is(err, database.ErrNotFound) { return reachabilitydata.EmptyReachabilityData(), nil } - - data, err := rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) - if err != nil { - return nil, err - } - return data.CloneMutable(), nil + return nil, err } func (rt *reachabilityManager) futureCoveringSet(blockHash *externalapi.DomainHash) (model.FutureCoveringTreeNodeSet, error) { From 739cffd9180d850263ce18723f43e48e0716717c Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 30 Dec 2020 13:53:46 +0200 Subject: [PATCH 186/351] Remove half the ghostdag store calls in LowestChainBlockAboveOrEqualToBlueScore (#1323) --- .../processes/dagtraversalmanager/dagtraversalmanager.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 3c4662bb3..ca1ece855 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -110,8 +110,7 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash currentHash := highHash currentBlockGHOSTDAGData := highBlockGHOSTDAGData - iterator := dtm.SelectedParentIterator(highHash) - for iterator.Next() { + for currentBlockGHOSTDAGData.SelectedParent() != nil { selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent()) if err != nil { return nil, err From 6172e48adc1d5b0688e1689a7c580c32674bc9e8 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 30 Dec 2020 15:15:41 +0200 Subject: [PATCH 187/351] Don't ban when capacity has been reached (#1326) --- .../netadapter/server/grpcserver/connection_loops.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/infrastructure/network/netadapter/server/grpcserver/connection_loops.go b/infrastructure/network/netadapter/server/grpcserver/connection_loops.go index 7cc40c0e0..63df69ffc 100644 --- a/infrastructure/network/netadapter/server/grpcserver/connection_loops.go +++ b/infrastructure/network/netadapter/server/grpcserver/connection_loops.go @@ -89,6 +89,12 @@ func (c *gRPCConnection) receiveLoop() error { if errors.Is(err, routerpkg.ErrRouteClosed) { return nil } + + // ErrRouteCapacityReached isn't an invalid message error, so + // we return it in order to log it later on. + if errors.Is(err, routerpkg.ErrRouteCapacityReached) { + return err + } if c.onInvalidMessageHandler != nil { c.onInvalidMessageHandler(err) } From 7dd0188838ea4ee38e85a64c5c962dda57a6ce94 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 30 Dec 2020 15:44:14 +0200 Subject: [PATCH 188/351] Move the heavy lifting in BlockLocator from the syncer to the syncee (#1324) * Add a new message: BlockLocatorHighestHash. * Add a new message: IBDBlockLocator. * Implement HandleIBDBlockLocator. * Reimplement findHighestSharedBlockHash. * Make HandleIBDBlockLocator only return hashes that are in the selected parent chain of the target hash. * Increase the cache sizes of blockRelationStore, reachabilityDataStore, and ghostdagDataStore. * Fix wrong initial highHash in findHighestSharedBlockHash. * Make go vet happy. * Protect against receiving wrong messages when expecting MsgIBDBlockLocatorHighestHash. --- app/appmessage/message.go | 4 + app/appmessage/p2p_msgibdblocklocator.go | 27 + .../p2p_msgibdblocklocatorhighesthash.go | 23 + app/appmessage/p2p_msgibdroothash.go | 14 +- app/appmessage/p2p_requestibdroothash.go | 14 +- .../blockrelay/handle_ibd_block_locator.go | 77 + .../handle_ibd_root_hash_requests.go | 4 +- app/protocol/flows/blockrelay/ibd.go | 91 +- app/protocol/protocol.go | 11 +- domain/consensus/consensus.go | 23 + domain/consensus/factory.go | 8 +- .../consensus/model/externalapi/consensus.go | 2 + .../grpcserver/protowire/messages.pb.go | 2493 +++++++++-------- .../grpcserver/protowire/messages.proto | 31 +- .../protowire/p2p_ibd_block_locator.go | 28 + .../p2p_ibd_block_locator_highest_hash.go | 21 + .../grpcserver/protowire/p2p_ibd_root_hash.go | 6 +- .../protowire/p2p_request_ibd_root_hash.go | 4 +- .../server/grpcserver/protowire/wire.go | 26 +- 19 files changed, 1678 insertions(+), 1229 deletions(-) create mode 100644 app/appmessage/p2p_msgibdblocklocator.go create mode 100644 app/appmessage/p2p_msgibdblocklocatorhighesthash.go create mode 100644 app/protocol/flows/blockrelay/handle_ibd_block_locator.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 117762f02..b9f7d9766 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -57,6 +57,8 @@ const ( CmdIBDRootNotFound CmdRequestIBDRootHash CmdIBDRootHash + CmdIBDBlockLocator + CmdIBDBlockLocatorHighestHash // rpc CmdGetCurrentNetworkRequestMessage @@ -149,6 +151,8 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdIBDRootNotFound: "IBDRootNotFound", CmdRequestIBDRootHash: "IBDRequestIBDRootHash", CmdIBDRootHash: "IBDIBDRootHash", + CmdIBDBlockLocator: "IBDBlockLocator", + CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", } // RPCMessageCommandToString maps all MessageCommands to their string representation diff --git a/app/appmessage/p2p_msgibdblocklocator.go b/app/appmessage/p2p_msgibdblocklocator.go new file mode 100644 index 000000000..c0adae4d6 --- /dev/null +++ b/app/appmessage/p2p_msgibdblocklocator.go @@ -0,0 +1,27 @@ +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgIBDBlockLocator represents a kaspa ibdBlockLocator message +type MsgIBDBlockLocator struct { + baseMessage + TargetHash *externalapi.DomainHash + BlockLocatorHashes []*externalapi.DomainHash +} + +// Command returns the protocol command string for the message +func (msg *MsgIBDBlockLocator) Command() MessageCommand { + return CmdIBDBlockLocator +} + +// NewMsgIBDBlockLocator returns a new kaspa ibdBlockLocator message +func NewMsgIBDBlockLocator(targetHash *externalapi.DomainHash, + blockLocatorHashes []*externalapi.DomainHash) *MsgIBDBlockLocator { + + return &MsgIBDBlockLocator{ + TargetHash: targetHash, + BlockLocatorHashes: blockLocatorHashes, + } +} diff --git a/app/appmessage/p2p_msgibdblocklocatorhighesthash.go b/app/appmessage/p2p_msgibdblocklocatorhighesthash.go new file mode 100644 index 000000000..2d21f0318 --- /dev/null +++ b/app/appmessage/p2p_msgibdblocklocatorhighesthash.go @@ -0,0 +1,23 @@ +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgIBDBlockLocatorHighestHash represents a kaspa BlockLocatorHighestHash message +type MsgIBDBlockLocatorHighestHash struct { + baseMessage + HighestHash *externalapi.DomainHash +} + +// Command returns the protocol command string for the message +func (msg *MsgIBDBlockLocatorHighestHash) Command() MessageCommand { + return CmdIBDBlockLocatorHighestHash +} + +// NewMsgIBDBlockLocatorHighestHash returns a new BlockLocatorHighestHash message +func NewMsgIBDBlockLocatorHighestHash(highestHash *externalapi.DomainHash) *MsgIBDBlockLocatorHighestHash { + return &MsgIBDBlockLocatorHighestHash{ + HighestHash: highestHash, + } +} diff --git a/app/appmessage/p2p_msgibdroothash.go b/app/appmessage/p2p_msgibdroothash.go index 1b21ac65d..2ed8568bb 100644 --- a/app/appmessage/p2p_msgibdroothash.go +++ b/app/appmessage/p2p_msgibdroothash.go @@ -4,23 +4,23 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// MsgIBDRootHash implements the Message interface and represents a kaspa +// MsgIBDRootHashMessage implements the Message interface and represents a kaspa // IBDRootHash message. It is used as a reply to IBD root hash requests. -type MsgIBDRootHash struct { +type MsgIBDRootHashMessage struct { baseMessage Hash *externalapi.DomainHash } // Command returns the protocol command string for the message. This is part // of the Message interface implementation. -func (msg *MsgIBDRootHash) Command() MessageCommand { +func (msg *MsgIBDRootHashMessage) Command() MessageCommand { return CmdIBDRootHash } -// NewMsgIBDRootHash returns a new kaspa IBDRootHash message that conforms to -// the Message interface. See MsgIBDRootHash for details. -func NewMsgIBDRootHash(hash *externalapi.DomainHash) *MsgIBDRootHash { - return &MsgIBDRootHash{ +// NewMsgIBDRootHashMessage returns a new kaspa IBDRootHash message that conforms to +// the Message interface. See MsgIBDRootHashMessage for details. +func NewMsgIBDRootHashMessage(hash *externalapi.DomainHash) *MsgIBDRootHashMessage { + return &MsgIBDRootHashMessage{ Hash: hash, } } diff --git a/app/appmessage/p2p_requestibdroothash.go b/app/appmessage/p2p_requestibdroothash.go index 0c8139568..ce30225fc 100644 --- a/app/appmessage/p2p_requestibdroothash.go +++ b/app/appmessage/p2p_requestibdroothash.go @@ -1,22 +1,22 @@ package appmessage -// MsgRequestIBDRootHash implements the Message interface and represents a kaspa -// MsgRequestIBDRootHash message. It is used to request the IBD root hash +// MsgRequestIBDRootHashMessage implements the Message interface and represents a kaspa +// MsgRequestIBDRootHashMessage message. It is used to request the IBD root hash // from a peer during IBD. // // This message has no payload. -type MsgRequestIBDRootHash struct { +type MsgRequestIBDRootHashMessage struct { baseMessage } // Command returns the protocol command string for the message. This is part // of the Message interface implementation. -func (msg *MsgRequestIBDRootHash) Command() MessageCommand { +func (msg *MsgRequestIBDRootHashMessage) Command() MessageCommand { return CmdRequestIBDRootHash } -// NewMsgRequestIBDRootHash returns a new kaspa RequestIBDRootHash message that conforms to the +// NewMsgRequestIBDRootHashMessage returns a new kaspa RequestIBDRootHash message that conforms to the // Message interface. -func NewMsgRequestIBDRootHash() *MsgRequestIBDRootHash { - return &MsgRequestIBDRootHash{} +func NewMsgRequestIBDRootHashMessage() *MsgRequestIBDRootHashMessage { + return &MsgRequestIBDRootHashMessage{} } diff --git a/app/protocol/flows/blockrelay/handle_ibd_block_locator.go b/app/protocol/flows/blockrelay/handle_ibd_block_locator.go new file mode 100644 index 000000000..a04d0699e --- /dev/null +++ b/app/protocol/flows/blockrelay/handle_ibd_block_locator.go @@ -0,0 +1,77 @@ +package blockrelay + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/peer" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleIBDBlockLocatorContext is the interface for the context needed for the HandleIBDBlockLocator flow. +type HandleIBDBlockLocatorContext interface { + Domain() domain.Domain +} + +// HandleIBDBlockLocator listens to appmessage.MsgIBDBlockLocator messages and sends +// the highest known block that's in the selected parent chain of `targetHash` to the +// requesting peer. +func HandleIBDBlockLocator(context HandleIBDBlockLocatorContext, incomingRoute *router.Route, + outgoingRoute *router.Route, peer *peer.Peer) error { + + for { + message, err := incomingRoute.Dequeue() + if err != nil { + return err + } + ibdBlockLocatorMessage := message.(*appmessage.MsgIBDBlockLocator) + + targetHash := ibdBlockLocatorMessage.TargetHash + log.Debugf("Received IBDBlockLocator from %s with targetHash %s", peer, targetHash) + + blockInfo, err := context.Domain().Consensus().GetBlockInfo(targetHash) + if err != nil { + return err + } + if !blockInfo.Exists { + return protocolerrors.Errorf(true, "received IBDBlockLocator "+ + "with an unknown targetHash %s", targetHash) + } + + foundHighestHashInTheSelectedParentChainOfTargetHash := false + for _, blockLocatorHash := range ibdBlockLocatorMessage.BlockLocatorHashes { + blockInfo, err := context.Domain().Consensus().GetBlockInfo(blockLocatorHash) + if err != nil { + return err + } + if !blockInfo.Exists { + continue + } + + isBlockLocatorHashInSelectedParentChainOfHighHash, err := + context.Domain().Consensus().IsInSelectedParentChainOf(blockLocatorHash, targetHash) + if err != nil { + return err + } + if !isBlockLocatorHashInSelectedParentChainOfHighHash { + continue + } + + foundHighestHashInTheSelectedParentChainOfTargetHash = true + log.Debugf("Found a known hash %s amongst peer %s's "+ + "blockLocator that's in the selected parent chain of targetHash %s", blockLocatorHash, peer, targetHash) + + ibdBlockLocatorHighestHashMessage := appmessage.NewMsgIBDBlockLocatorHighestHash(blockLocatorHash) + err = outgoingRoute.Enqueue(ibdBlockLocatorHighestHashMessage) + if err != nil { + return err + } + break + } + + if !foundHighestHashInTheSelectedParentChainOfTargetHash { + return protocolerrors.Errorf(true, "no hash was found in the blockLocator "+ + "that was in the selected parent chain of targetHash %s", targetHash) + } + } +} diff --git a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go index 1a63d0403..3d8948233 100644 --- a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go +++ b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go @@ -16,7 +16,7 @@ type handleIBDRootHashRequestsFlow struct { incomingRoute, outgoingRoute *router.Route } -// HandleIBDRootHashRequests listens to appmessage.MsgRequestIBDRootHash messages and sends +// HandleIBDRootHashRequests listens to appmessage.MsgRequestIBDRootHashMessage messages and sends // the IBD root hash as response. func HandleIBDRootHashRequests(context HandleIBDRootHashRequestsFlowContext, incomingRoute, outgoingRoute *router.Route) error { @@ -41,7 +41,7 @@ func (flow *handleIBDRootHashRequestsFlow) start() error { return err } - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootHash(pruningPoint)) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootHashMessage(pruningPoint)) if err != nil { return err } diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 1d4dfb71d..9d70cc3cb 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -31,7 +31,7 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain // Fetch the UTXO set if we don't already have it log.Debugf("Checking if there's a new pruning point under %s", highHash) - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHash()) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHashMessage()) if err != nil { return err } @@ -41,7 +41,7 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain return err } - msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHash) + msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHashMessage) if !ok { return protocolerrors.Errorf(true, "received unexpected message type. "+ "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) @@ -118,40 +118,61 @@ func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) e return nil } -func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(highHash *externalapi.DomainHash) ( - lowHash *externalapi.DomainHash, err error) { - - lowHash = flow.Config().ActiveNetParams.GenesisHash - currentHighHash := highHash - - for { - err := flow.sendGetBlockLocator(lowHash, currentHighHash, 0) - if err != nil { - return nil, err - } - - blockLocatorHashes, err := flow.receiveBlockLocator() - if err != nil { - return nil, err - } - - // We check whether the locator's highest hash is in the local DAG. - // If it is, return it. If it isn't, we need to narrow our - // getBlockLocator request and try again. - locatorHighHash := blockLocatorHashes[0] - locatorHighHashInfo, err := flow.Domain().Consensus().GetBlockInfo(locatorHighHash) - if err != nil { - return nil, err - } - if locatorHighHashInfo.Exists { - return locatorHighHash, nil - } - - lowHash, currentHighHash, err = flow.Domain().Consensus().FindNextBlockLocatorBoundaries(blockLocatorHashes) - if err != nil { - return nil, err - } +func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + lowHash := flow.Config().ActiveNetParams.GenesisHash + highHash, err := flow.Domain().Consensus().GetHeadersSelectedTip() + if err != nil { + return nil, err } + + for !lowHash.Equal(highHash) { + log.Debugf("Sending a blockLocator to %s between %s and %s", flow.peer, lowHash, highHash) + blockLocator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash, 0) + if err != nil { + return nil, err + } + + ibdBlockLocatorMessage := appmessage.NewMsgIBDBlockLocator(targetHash, blockLocator) + err = flow.outgoingRoute.Enqueue(ibdBlockLocatorMessage) + if err != nil { + return nil, err + } + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return nil, err + } + ibdBlockLocatorHighestHashMessage, ok := message.(*appmessage.MsgIBDBlockLocatorHighestHash) + if !ok { + return nil, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDBlockLocatorHighestHash, message.Command()) + } + highestHash := ibdBlockLocatorHighestHashMessage.HighestHash + log.Debugf("The highest hash the peer %s knows is %s", flow.peer, highestHash) + + highestHashIndex := 0 + highestHashIndexFound := false + for i, blockLocatorHash := range blockLocator { + if highestHash.Equal(blockLocatorHash) { + highestHashIndex = i + highestHashIndexFound = true + break + } + } + if !highestHashIndexFound { + return nil, protocolerrors.Errorf(true, "highest hash %s "+ + "returned from peer %s is not in the original blockLocator", highestHash, flow.peer) + } + log.Debugf("The index of the highest hash in the original "+ + "blockLocator sent to %s is %d", flow.peer, highestHashIndex) + + locatorHashAboveHighestHash := highestHash + if highestHashIndex > 0 { + locatorHashAboveHighestHash = blockLocator[highestHashIndex-1] + } + highHash = locatorHashAboveHighestHash + lowHash = highestHash + } + return highHash, nil } func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash, diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 1e00f961e..aaa4d4d6c 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -136,8 +136,8 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, - appmessage.CmdHeader, appmessage.CmdIBDRootHash}, isStopping, errChan, - func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + appmessage.CmdHeader, appmessage.CmdIBDRootHash, appmessage.CmdIBDBlockLocatorHighestHash}, + isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) }, @@ -183,6 +183,13 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * return blockrelay.HandleIBDRootHashRequests(m.context, incomingRoute, outgoingRoute) }, ), + + m.registerFlow("HandleIBDBlockLocator", router, + []appmessage.MessageCommand{appmessage.CmdIBDBlockLocator}, isStopping, errChan, + func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.HandleIBDBlockLocator(m.context, incomingRoute, outgoingRoute, peer) + }, + ), } } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 8a01b263a..cf29254ec 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -344,3 +344,26 @@ func (s *consensus) validateBlockHashExists(blockHash *externalapi.DomainHash) e } return nil } + +func (s *consensus) IsInSelectedParentChainOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { + s.lock.Lock() + defer s.lock.Unlock() + + err := s.validateBlockHashExists(blockHashA) + if err != nil { + return false, err + } + err = s.validateBlockHashExists(blockHashB) + if err != nil { + return false, err + } + + return s.dagTopologyManager.IsInSelectedParentChainOf(blockHashA, blockHashB) +} + +func (s *consensus) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { + s.lock.Lock() + defer s.lock.Unlock() + + return s.headersSelectedTipStore.HeadersSelectedTip(s.databaseContext) +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 124151d45..27828c460 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -64,6 +64,8 @@ func NewFactory() Factory { func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) { dbManager := consensusdatabase.New(db) + pruningWindowSizeForCaches := int(dagParams.PruningDepth()) + // Data Structures acceptanceDataStore := acceptancedatastore.New(200) blockStore, err := blockstore.New(dbManager, 200) @@ -74,14 +76,14 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat if err != nil { return nil, err } - blockRelationStore := blockrelationstore.New(10_000) + blockRelationStore := blockrelationstore.New(pruningWindowSizeForCaches) blockStatusStore := blockstatusstore.New(200) multisetStore := multisetstore.New(200) pruningStore := pruningstore.New() - reachabilityDataStore := reachabilitydatastore.New(10_000) + reachabilityDataStore := reachabilitydatastore.New(pruningWindowSizeForCaches) utxoDiffStore := utxodiffstore.New(200) consensusStateStore := consensusstatestore.New() - ghostdagDataStore := ghostdagdatastore.New(10_000) + ghostdagDataStore := ghostdagdatastore.New(pruningWindowSizeForCaches) headersSelectedTipStore := headersselectedtipstore.New() finalityStore := finalitystore.New(200) diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 45ea17e59..8921d9a28 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -24,4 +24,6 @@ type Consensus interface { GetVirtualInfo() (*VirtualInfo, error) IsValidPruningPoint(blockHash *DomainHash) (bool, error) GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) + IsInSelectedParentChainOf(blockHashA *DomainHash, blockHashB *DomainHash) (bool, error) + GetHeadersSelectedTip() (*DomainHash, error) } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 99a7a979b..a1e60fb75 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -58,6 +58,8 @@ type KaspadMessage struct { // *KaspadMessage_IbdRootNotFound // *KaspadMessage_RequestIBDRootHash // *KaspadMessage_IbdRootHash + // *KaspadMessage_IbdBlockLocator + // *KaspadMessage_IbdBlockLocatorHighestHash // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -333,20 +335,34 @@ func (x *KaspadMessage) GetIbdRootNotFound() *IBDRootNotFoundMessage { return nil } -func (x *KaspadMessage) GetRequestIBDRootHash() *RequestIBDRootHash { +func (x *KaspadMessage) GetRequestIBDRootHash() *RequestIBDRootHashMessage { if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDRootHash); ok { return x.RequestIBDRootHash } return nil } -func (x *KaspadMessage) GetIbdRootHash() *IBDRootHash { +func (x *KaspadMessage) GetIbdRootHash() *IBDRootHashMessage { if x, ok := x.GetPayload().(*KaspadMessage_IbdRootHash); ok { return x.IbdRootHash } return nil } +func (x *KaspadMessage) GetIbdBlockLocator() *IbdBlockLocatorMessage { + if x, ok := x.GetPayload().(*KaspadMessage_IbdBlockLocator); ok { + return x.IbdBlockLocator + } + return nil +} + +func (x *KaspadMessage) GetIbdBlockLocatorHighestHash() *IbdBlockLocatorHighestHashMessage { + if x, ok := x.GetPayload().(*KaspadMessage_IbdBlockLocatorHighestHash); ok { + return x.IbdBlockLocatorHighestHash + } + return nil +} + func (x *KaspadMessage) GetGetCurrentNetworkRequest() *GetCurrentNetworkRequestMessage { if x, ok := x.GetPayload().(*KaspadMessage_GetCurrentNetworkRequest); ok { return x.GetCurrentNetworkRequest @@ -858,11 +874,19 @@ type KaspadMessage_IbdRootNotFound struct { } type KaspadMessage_RequestIBDRootHash struct { - RequestIBDRootHash *RequestIBDRootHash `protobuf:"bytes,28,opt,name=requestIBDRootHash,proto3,oneof"` + RequestIBDRootHash *RequestIBDRootHashMessage `protobuf:"bytes,28,opt,name=requestIBDRootHash,proto3,oneof"` } type KaspadMessage_IbdRootHash struct { - IbdRootHash *IBDRootHash `protobuf:"bytes,29,opt,name=ibdRootHash,proto3,oneof"` + IbdRootHash *IBDRootHashMessage `protobuf:"bytes,29,opt,name=ibdRootHash,proto3,oneof"` +} + +type KaspadMessage_IbdBlockLocator struct { + IbdBlockLocator *IbdBlockLocatorMessage `protobuf:"bytes,30,opt,name=ibdBlockLocator,proto3,oneof"` +} + +type KaspadMessage_IbdBlockLocatorHighestHash struct { + IbdBlockLocatorHighestHash *IbdBlockLocatorHighestHashMessage `protobuf:"bytes,31,opt,name=ibdBlockLocatorHighestHash,proto3,oneof"` } type KaspadMessage_GetCurrentNetworkRequest struct { @@ -1151,6 +1175,10 @@ func (*KaspadMessage_RequestIBDRootHash) isKaspadMessage_Payload() {} func (*KaspadMessage_IbdRootHash) isKaspadMessage_Payload() {} +func (*KaspadMessage_IbdBlockLocator) isKaspadMessage_Payload() {} + +func (*KaspadMessage_IbdBlockLocatorHighestHash) isKaspadMessage_Payload() {} + func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkResponse) isKaspadMessage_Payload() {} @@ -2991,15 +3019,15 @@ func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{31} } -// RequestIBDRootHash start -type RequestIBDRootHash struct { +// RequestIBDRootHashMessage start +type RequestIBDRootHashMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *RequestIBDRootHash) Reset() { - *x = RequestIBDRootHash{} +func (x *RequestIBDRootHashMessage) Reset() { + *x = RequestIBDRootHashMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3007,13 +3035,13 @@ func (x *RequestIBDRootHash) Reset() { } } -func (x *RequestIBDRootHash) String() string { +func (x *RequestIBDRootHashMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RequestIBDRootHash) ProtoMessage() {} +func (*RequestIBDRootHashMessage) ProtoMessage() {} -func (x *RequestIBDRootHash) ProtoReflect() protoreflect.Message { +func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3025,13 +3053,13 @@ func (x *RequestIBDRootHash) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use RequestIBDRootHash.ProtoReflect.Descriptor instead. -func (*RequestIBDRootHash) Descriptor() ([]byte, []int) { +// Deprecated: Use RequestIBDRootHashMessage.ProtoReflect.Descriptor instead. +func (*RequestIBDRootHashMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{32} } -// IBDRootHash start -type IBDRootHash struct { +// IBDRootHashMessage start +type IBDRootHashMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -3039,8 +3067,8 @@ type IBDRootHash struct { Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` } -func (x *IBDRootHash) Reset() { - *x = IBDRootHash{} +func (x *IBDRootHashMessage) Reset() { + *x = IBDRootHashMessage{} if protoimpl.UnsafeEnabled { mi := &file_messages_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3048,13 +3076,13 @@ func (x *IBDRootHash) Reset() { } } -func (x *IBDRootHash) String() string { +func (x *IBDRootHashMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*IBDRootHash) ProtoMessage() {} +func (*IBDRootHashMessage) ProtoMessage() {} -func (x *IBDRootHash) ProtoReflect() protoreflect.Message { +func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { mi := &file_messages_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3066,18 +3094,122 @@ func (x *IBDRootHash) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use IBDRootHash.ProtoReflect.Descriptor instead. -func (*IBDRootHash) Descriptor() ([]byte, []int) { +// Deprecated: Use IBDRootHashMessage.ProtoReflect.Descriptor instead. +func (*IBDRootHashMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{33} } -func (x *IBDRootHash) GetHash() *Hash { +func (x *IBDRootHashMessage) GetHash() *Hash { if x != nil { return x.Hash } return nil } +// IbdBlockLocatorMessage start +type IbdBlockLocatorMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TargetHash *Hash `protobuf:"bytes,1,opt,name=targetHash,proto3" json:"targetHash,omitempty"` + BlockLocatorHashes []*Hash `protobuf:"bytes,2,rep,name=blockLocatorHashes,proto3" json:"blockLocatorHashes,omitempty"` +} + +func (x *IbdBlockLocatorMessage) Reset() { + *x = IbdBlockLocatorMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IbdBlockLocatorMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IbdBlockLocatorMessage) ProtoMessage() {} + +func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IbdBlockLocatorMessage.ProtoReflect.Descriptor instead. +func (*IbdBlockLocatorMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{34} +} + +func (x *IbdBlockLocatorMessage) GetTargetHash() *Hash { + if x != nil { + return x.TargetHash + } + return nil +} + +func (x *IbdBlockLocatorMessage) GetBlockLocatorHashes() []*Hash { + if x != nil { + return x.BlockLocatorHashes + } + return nil +} + +// IbdBlockLocatorHighestHashMessage start +type IbdBlockLocatorHighestHashMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HighestHash *Hash `protobuf:"bytes,1,opt,name=highestHash,proto3" json:"highestHash,omitempty"` +} + +func (x *IbdBlockLocatorHighestHashMessage) Reset() { + *x = IbdBlockLocatorHighestHashMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IbdBlockLocatorHighestHashMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IbdBlockLocatorHighestHashMessage) ProtoMessage() {} + +func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IbdBlockLocatorHighestHashMessage.ProtoReflect.Descriptor instead. +func (*IbdBlockLocatorHighestHashMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{35} +} + +func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { + if x != nil { + return x.HighestHash + } + return nil +} + type RPCError struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3089,7 +3221,7 @@ type RPCError struct { func (x *RPCError) Reset() { *x = RPCError{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3102,7 +3234,7 @@ func (x *RPCError) String() string { func (*RPCError) ProtoMessage() {} func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3115,7 +3247,7 @@ func (x *RPCError) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCError.ProtoReflect.Descriptor instead. func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} + return file_messages_proto_rawDescGZIP(), []int{36} } func (x *RPCError) GetMessage() string { @@ -3134,7 +3266,7 @@ type GetCurrentNetworkRequestMessage struct { func (x *GetCurrentNetworkRequestMessage) Reset() { *x = GetCurrentNetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3147,7 +3279,7 @@ func (x *GetCurrentNetworkRequestMessage) String() string { func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3160,7 +3292,7 @@ func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{35} + return file_messages_proto_rawDescGZIP(), []int{37} } type GetCurrentNetworkResponseMessage struct { @@ -3175,7 +3307,7 @@ type GetCurrentNetworkResponseMessage struct { func (x *GetCurrentNetworkResponseMessage) Reset() { *x = GetCurrentNetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3188,7 +3320,7 @@ func (x *GetCurrentNetworkResponseMessage) String() string { func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3201,7 +3333,7 @@ func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} + return file_messages_proto_rawDescGZIP(), []int{38} } func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { @@ -3229,7 +3361,7 @@ type SubmitBlockRequestMessage struct { func (x *SubmitBlockRequestMessage) Reset() { *x = SubmitBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3242,7 +3374,7 @@ func (x *SubmitBlockRequestMessage) String() string { func (*SubmitBlockRequestMessage) ProtoMessage() {} func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3255,7 +3387,7 @@ func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} + return file_messages_proto_rawDescGZIP(), []int{39} } func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { @@ -3276,7 +3408,7 @@ type SubmitBlockResponseMessage struct { func (x *SubmitBlockResponseMessage) Reset() { *x = SubmitBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3289,7 +3421,7 @@ func (x *SubmitBlockResponseMessage) String() string { func (*SubmitBlockResponseMessage) ProtoMessage() {} func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3302,7 +3434,7 @@ func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} + return file_messages_proto_rawDescGZIP(), []int{40} } func (x *SubmitBlockResponseMessage) GetError() *RPCError { @@ -3323,7 +3455,7 @@ type GetBlockTemplateRequestMessage struct { func (x *GetBlockTemplateRequestMessage) Reset() { *x = GetBlockTemplateRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3336,7 +3468,7 @@ func (x *GetBlockTemplateRequestMessage) String() string { func (*GetBlockTemplateRequestMessage) ProtoMessage() {} func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3349,7 +3481,7 @@ func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} + return file_messages_proto_rawDescGZIP(), []int{41} } func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { @@ -3372,7 +3504,7 @@ type GetBlockTemplateResponseMessage struct { func (x *GetBlockTemplateResponseMessage) Reset() { *x = GetBlockTemplateResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3385,7 +3517,7 @@ func (x *GetBlockTemplateResponseMessage) String() string { func (*GetBlockTemplateResponseMessage) ProtoMessage() {} func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3398,7 +3530,7 @@ func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} + return file_messages_proto_rawDescGZIP(), []int{42} } func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { @@ -3431,7 +3563,7 @@ type NotifyBlockAddedRequestMessage struct { func (x *NotifyBlockAddedRequestMessage) Reset() { *x = NotifyBlockAddedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3444,7 +3576,7 @@ func (x *NotifyBlockAddedRequestMessage) String() string { func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3457,7 +3589,7 @@ func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} + return file_messages_proto_rawDescGZIP(), []int{43} } type NotifyBlockAddedResponseMessage struct { @@ -3471,7 +3603,7 @@ type NotifyBlockAddedResponseMessage struct { func (x *NotifyBlockAddedResponseMessage) Reset() { *x = NotifyBlockAddedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3484,7 +3616,7 @@ func (x *NotifyBlockAddedResponseMessage) String() string { func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3497,7 +3629,7 @@ func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} + return file_messages_proto_rawDescGZIP(), []int{44} } func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { @@ -3518,7 +3650,7 @@ type BlockAddedNotificationMessage struct { func (x *BlockAddedNotificationMessage) Reset() { *x = BlockAddedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3531,7 +3663,7 @@ func (x *BlockAddedNotificationMessage) String() string { func (*BlockAddedNotificationMessage) ProtoMessage() {} func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3544,7 +3676,7 @@ func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} + return file_messages_proto_rawDescGZIP(), []int{45} } func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { @@ -3563,7 +3695,7 @@ type GetPeerAddressesRequestMessage struct { func (x *GetPeerAddressesRequestMessage) Reset() { *x = GetPeerAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3576,7 +3708,7 @@ func (x *GetPeerAddressesRequestMessage) String() string { func (*GetPeerAddressesRequestMessage) ProtoMessage() {} func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3589,7 +3721,7 @@ func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} + return file_messages_proto_rawDescGZIP(), []int{46} } type GetPeerAddressesResponseMessage struct { @@ -3605,7 +3737,7 @@ type GetPeerAddressesResponseMessage struct { func (x *GetPeerAddressesResponseMessage) Reset() { *x = GetPeerAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3618,7 +3750,7 @@ func (x *GetPeerAddressesResponseMessage) String() string { func (*GetPeerAddressesResponseMessage) ProtoMessage() {} func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3631,7 +3763,7 @@ func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} + return file_messages_proto_rawDescGZIP(), []int{47} } func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { @@ -3666,7 +3798,7 @@ type GetPeerAddressesKnownAddressMessage struct { func (x *GetPeerAddressesKnownAddressMessage) Reset() { *x = GetPeerAddressesKnownAddressMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3679,7 +3811,7 @@ func (x *GetPeerAddressesKnownAddressMessage) String() string { func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3692,7 +3824,7 @@ func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} + return file_messages_proto_rawDescGZIP(), []int{48} } func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { @@ -3711,7 +3843,7 @@ type GetSelectedTipHashRequestMessage struct { func (x *GetSelectedTipHashRequestMessage) Reset() { *x = GetSelectedTipHashRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3724,7 +3856,7 @@ func (x *GetSelectedTipHashRequestMessage) String() string { func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3737,7 +3869,7 @@ func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} + return file_messages_proto_rawDescGZIP(), []int{49} } type GetSelectedTipHashResponseMessage struct { @@ -3752,7 +3884,7 @@ type GetSelectedTipHashResponseMessage struct { func (x *GetSelectedTipHashResponseMessage) Reset() { *x = GetSelectedTipHashResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3765,7 +3897,7 @@ func (x *GetSelectedTipHashResponseMessage) String() string { func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3778,7 +3910,7 @@ func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} + return file_messages_proto_rawDescGZIP(), []int{50} } func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { @@ -3808,7 +3940,7 @@ type MempoolEntry struct { func (x *MempoolEntry) Reset() { *x = MempoolEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3821,7 +3953,7 @@ func (x *MempoolEntry) String() string { func (*MempoolEntry) ProtoMessage() {} func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3834,7 +3966,7 @@ func (x *MempoolEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} + return file_messages_proto_rawDescGZIP(), []int{51} } func (x *MempoolEntry) GetFee() uint64 { @@ -3862,7 +3994,7 @@ type GetMempoolEntryRequestMessage struct { func (x *GetMempoolEntryRequestMessage) Reset() { *x = GetMempoolEntryRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3875,7 +4007,7 @@ func (x *GetMempoolEntryRequestMessage) String() string { func (*GetMempoolEntryRequestMessage) ProtoMessage() {} func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3888,7 +4020,7 @@ func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} + return file_messages_proto_rawDescGZIP(), []int{52} } func (x *GetMempoolEntryRequestMessage) GetTxId() string { @@ -3910,7 +4042,7 @@ type GetMempoolEntryResponseMessage struct { func (x *GetMempoolEntryResponseMessage) Reset() { *x = GetMempoolEntryResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3923,7 +4055,7 @@ func (x *GetMempoolEntryResponseMessage) String() string { func (*GetMempoolEntryResponseMessage) ProtoMessage() {} func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3936,7 +4068,7 @@ func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} + return file_messages_proto_rawDescGZIP(), []int{53} } func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { @@ -3962,7 +4094,7 @@ type GetMempoolEntriesRequestMessage struct { func (x *GetMempoolEntriesRequestMessage) Reset() { *x = GetMempoolEntriesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3975,7 +4107,7 @@ func (x *GetMempoolEntriesRequestMessage) String() string { func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3988,7 +4120,7 @@ func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} + return file_messages_proto_rawDescGZIP(), []int{54} } type GetMempoolEntriesResponseMessage struct { @@ -4003,7 +4135,7 @@ type GetMempoolEntriesResponseMessage struct { func (x *GetMempoolEntriesResponseMessage) Reset() { *x = GetMempoolEntriesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4016,7 +4148,7 @@ func (x *GetMempoolEntriesResponseMessage) String() string { func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4029,7 +4161,7 @@ func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} + return file_messages_proto_rawDescGZIP(), []int{55} } func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { @@ -4055,7 +4187,7 @@ type GetConnectedPeerInfoRequestMessage struct { func (x *GetConnectedPeerInfoRequestMessage) Reset() { *x = GetConnectedPeerInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4068,7 +4200,7 @@ func (x *GetConnectedPeerInfoRequestMessage) String() string { func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4081,7 +4213,7 @@ func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} + return file_messages_proto_rawDescGZIP(), []int{56} } type GetConnectedPeerInfoResponseMessage struct { @@ -4096,7 +4228,7 @@ type GetConnectedPeerInfoResponseMessage struct { func (x *GetConnectedPeerInfoResponseMessage) Reset() { *x = GetConnectedPeerInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4109,7 +4241,7 @@ func (x *GetConnectedPeerInfoResponseMessage) String() string { func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4122,7 +4254,7 @@ func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} + return file_messages_proto_rawDescGZIP(), []int{57} } func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { @@ -4157,7 +4289,7 @@ type GetConnectedPeerInfoMessage struct { func (x *GetConnectedPeerInfoMessage) Reset() { *x = GetConnectedPeerInfoMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4170,7 +4302,7 @@ func (x *GetConnectedPeerInfoMessage) String() string { func (*GetConnectedPeerInfoMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4183,7 +4315,7 @@ func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} + return file_messages_proto_rawDescGZIP(), []int{58} } func (x *GetConnectedPeerInfoMessage) GetId() string { @@ -4254,7 +4386,7 @@ type AddPeerRequestMessage struct { func (x *AddPeerRequestMessage) Reset() { *x = AddPeerRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4267,7 +4399,7 @@ func (x *AddPeerRequestMessage) String() string { func (*AddPeerRequestMessage) ProtoMessage() {} func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4280,7 +4412,7 @@ func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} + return file_messages_proto_rawDescGZIP(), []int{59} } func (x *AddPeerRequestMessage) GetAddress() string { @@ -4308,7 +4440,7 @@ type AddPeerResponseMessage struct { func (x *AddPeerResponseMessage) Reset() { *x = AddPeerResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4321,7 +4453,7 @@ func (x *AddPeerResponseMessage) String() string { func (*AddPeerResponseMessage) ProtoMessage() {} func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4334,7 +4466,7 @@ func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} + return file_messages_proto_rawDescGZIP(), []int{60} } func (x *AddPeerResponseMessage) GetError() *RPCError { @@ -4355,7 +4487,7 @@ type SubmitTransactionRequestMessage struct { func (x *SubmitTransactionRequestMessage) Reset() { *x = SubmitTransactionRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4368,7 +4500,7 @@ func (x *SubmitTransactionRequestMessage) String() string { func (*SubmitTransactionRequestMessage) ProtoMessage() {} func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4381,7 +4513,7 @@ func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} + return file_messages_proto_rawDescGZIP(), []int{61} } func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { @@ -4403,7 +4535,7 @@ type SubmitTransactionResponseMessage struct { func (x *SubmitTransactionResponseMessage) Reset() { *x = SubmitTransactionResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4416,7 +4548,7 @@ func (x *SubmitTransactionResponseMessage) String() string { func (*SubmitTransactionResponseMessage) ProtoMessage() {} func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4429,7 +4561,7 @@ func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} + return file_messages_proto_rawDescGZIP(), []int{62} } func (x *SubmitTransactionResponseMessage) GetTransactionId() string { @@ -4455,7 +4587,7 @@ type NotifyVirtualSelectedParentChainChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4468,7 +4600,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4481,7 +4613,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() p // Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} + return file_messages_proto_rawDescGZIP(), []int{63} } type NotifyVirtualSelectedParentChainChangedResponseMessage struct { @@ -4495,7 +4627,7 @@ type NotifyVirtualSelectedParentChainChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4508,7 +4640,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4521,7 +4653,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() // Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} + return file_messages_proto_rawDescGZIP(), []int{64} } func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { @@ -4543,7 +4675,7 @@ type VirtualSelectedParentChainChangedNotificationMessage struct { func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { *x = VirtualSelectedParentChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4556,7 +4688,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4569,7 +4701,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() pr // Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} + return file_messages_proto_rawDescGZIP(), []int{65} } func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { @@ -4598,7 +4730,7 @@ type ChainBlock struct { func (x *ChainBlock) Reset() { *x = ChainBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4611,7 +4743,7 @@ func (x *ChainBlock) String() string { func (*ChainBlock) ProtoMessage() {} func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4624,7 +4756,7 @@ func (x *ChainBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} + return file_messages_proto_rawDescGZIP(), []int{66} } func (x *ChainBlock) GetHash() string { @@ -4653,7 +4785,7 @@ type AcceptedBlock struct { func (x *AcceptedBlock) Reset() { *x = AcceptedBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4666,7 +4798,7 @@ func (x *AcceptedBlock) String() string { func (*AcceptedBlock) ProtoMessage() {} func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4679,7 +4811,7 @@ func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} + return file_messages_proto_rawDescGZIP(), []int{67} } func (x *AcceptedBlock) GetHash() string { @@ -4709,7 +4841,7 @@ type GetBlockRequestMessage struct { func (x *GetBlockRequestMessage) Reset() { *x = GetBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4722,7 +4854,7 @@ func (x *GetBlockRequestMessage) String() string { func (*GetBlockRequestMessage) ProtoMessage() {} func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4735,7 +4867,7 @@ func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} + return file_messages_proto_rawDescGZIP(), []int{68} } func (x *GetBlockRequestMessage) GetHash() string { @@ -4772,7 +4904,7 @@ type GetBlockResponseMessage struct { func (x *GetBlockResponseMessage) Reset() { *x = GetBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4785,7 +4917,7 @@ func (x *GetBlockResponseMessage) String() string { func (*GetBlockResponseMessage) ProtoMessage() {} func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4798,7 +4930,7 @@ func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} + return file_messages_proto_rawDescGZIP(), []int{69} } func (x *GetBlockResponseMessage) GetBlockHash() string { @@ -4848,7 +4980,7 @@ type BlockVerboseData struct { func (x *BlockVerboseData) Reset() { *x = BlockVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4861,7 +4993,7 @@ func (x *BlockVerboseData) String() string { func (*BlockVerboseData) ProtoMessage() {} func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4874,7 +5006,7 @@ func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} + return file_messages_proto_rawDescGZIP(), []int{70} } func (x *BlockVerboseData) GetHash() string { @@ -5013,7 +5145,7 @@ type TransactionVerboseData struct { func (x *TransactionVerboseData) Reset() { *x = TransactionVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5026,7 +5158,7 @@ func (x *TransactionVerboseData) String() string { func (*TransactionVerboseData) ProtoMessage() {} func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5039,7 +5171,7 @@ func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} + return file_messages_proto_rawDescGZIP(), []int{71} } func (x *TransactionVerboseData) GetTxId() string { @@ -5154,7 +5286,7 @@ type TransactionVerboseInput struct { func (x *TransactionVerboseInput) Reset() { *x = TransactionVerboseInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5167,7 +5299,7 @@ func (x *TransactionVerboseInput) String() string { func (*TransactionVerboseInput) ProtoMessage() {} func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5180,7 +5312,7 @@ func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} + return file_messages_proto_rawDescGZIP(), []int{72} } func (x *TransactionVerboseInput) GetTxId() string { @@ -5223,7 +5355,7 @@ type ScriptSig struct { func (x *ScriptSig) Reset() { *x = ScriptSig{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5236,7 +5368,7 @@ func (x *ScriptSig) String() string { func (*ScriptSig) ProtoMessage() {} func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5249,7 +5381,7 @@ func (x *ScriptSig) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} + return file_messages_proto_rawDescGZIP(), []int{73} } func (x *ScriptSig) GetAsm() string { @@ -5279,7 +5411,7 @@ type TransactionVerboseOutput struct { func (x *TransactionVerboseOutput) Reset() { *x = TransactionVerboseOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5292,7 +5424,7 @@ func (x *TransactionVerboseOutput) String() string { func (*TransactionVerboseOutput) ProtoMessage() {} func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5305,7 +5437,7 @@ func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} + return file_messages_proto_rawDescGZIP(), []int{74} } func (x *TransactionVerboseOutput) GetValue() uint64 { @@ -5343,7 +5475,7 @@ type ScriptPubKeyResult struct { func (x *ScriptPubKeyResult) Reset() { *x = ScriptPubKeyResult{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5356,7 +5488,7 @@ func (x *ScriptPubKeyResult) String() string { func (*ScriptPubKeyResult) ProtoMessage() {} func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5369,7 +5501,7 @@ func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptPubKeyResult.ProtoReflect.Descriptor instead. func (*ScriptPubKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} + return file_messages_proto_rawDescGZIP(), []int{75} } func (x *ScriptPubKeyResult) GetAsm() string { @@ -5411,7 +5543,7 @@ type GetSubnetworkRequestMessage struct { func (x *GetSubnetworkRequestMessage) Reset() { *x = GetSubnetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5424,7 +5556,7 @@ func (x *GetSubnetworkRequestMessage) String() string { func (*GetSubnetworkRequestMessage) ProtoMessage() {} func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5437,7 +5569,7 @@ func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} + return file_messages_proto_rawDescGZIP(), []int{76} } func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { @@ -5459,7 +5591,7 @@ type GetSubnetworkResponseMessage struct { func (x *GetSubnetworkResponseMessage) Reset() { *x = GetSubnetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5472,7 +5604,7 @@ func (x *GetSubnetworkResponseMessage) String() string { func (*GetSubnetworkResponseMessage) ProtoMessage() {} func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5485,7 +5617,7 @@ func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} + return file_messages_proto_rawDescGZIP(), []int{77} } func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { @@ -5513,7 +5645,7 @@ type GetVirtualSelectedParentChainFromBlockRequestMessage struct { func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5526,7 +5658,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5539,7 +5671,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() pr // Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} + return file_messages_proto_rawDescGZIP(), []int{78} } func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { @@ -5562,7 +5694,7 @@ type GetVirtualSelectedParentChainFromBlockResponseMessage struct { func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5575,7 +5707,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5588,7 +5720,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() p // Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} + return file_messages_proto_rawDescGZIP(), []int{79} } func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { @@ -5626,7 +5758,7 @@ type GetBlocksRequestMessage struct { func (x *GetBlocksRequestMessage) Reset() { *x = GetBlocksRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5639,7 +5771,7 @@ func (x *GetBlocksRequestMessage) String() string { func (*GetBlocksRequestMessage) ProtoMessage() {} func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5652,7 +5784,7 @@ func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} + return file_messages_proto_rawDescGZIP(), []int{80} } func (x *GetBlocksRequestMessage) GetLowHash() string { @@ -5697,7 +5829,7 @@ type GetBlocksResponseMessage struct { func (x *GetBlocksResponseMessage) Reset() { *x = GetBlocksResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5710,7 +5842,7 @@ func (x *GetBlocksResponseMessage) String() string { func (*GetBlocksResponseMessage) ProtoMessage() {} func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5723,7 +5855,7 @@ func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} + return file_messages_proto_rawDescGZIP(), []int{81} } func (x *GetBlocksResponseMessage) GetBlockHashes() []string { @@ -5763,7 +5895,7 @@ type GetBlockCountRequestMessage struct { func (x *GetBlockCountRequestMessage) Reset() { *x = GetBlockCountRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5776,7 +5908,7 @@ func (x *GetBlockCountRequestMessage) String() string { func (*GetBlockCountRequestMessage) ProtoMessage() {} func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5789,7 +5921,7 @@ func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} + return file_messages_proto_rawDescGZIP(), []int{82} } type GetBlockCountResponseMessage struct { @@ -5805,7 +5937,7 @@ type GetBlockCountResponseMessage struct { func (x *GetBlockCountResponseMessage) Reset() { *x = GetBlockCountResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5818,7 +5950,7 @@ func (x *GetBlockCountResponseMessage) String() string { func (*GetBlockCountResponseMessage) ProtoMessage() {} func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5831,7 +5963,7 @@ func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} + return file_messages_proto_rawDescGZIP(), []int{83} } func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { @@ -5864,7 +5996,7 @@ type GetBlockDagInfoRequestMessage struct { func (x *GetBlockDagInfoRequestMessage) Reset() { *x = GetBlockDagInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5877,7 +6009,7 @@ func (x *GetBlockDagInfoRequestMessage) String() string { func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5890,7 +6022,7 @@ func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} + return file_messages_proto_rawDescGZIP(), []int{84} } type GetBlockDagInfoResponseMessage struct { @@ -5911,7 +6043,7 @@ type GetBlockDagInfoResponseMessage struct { func (x *GetBlockDagInfoResponseMessage) Reset() { *x = GetBlockDagInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5924,7 +6056,7 @@ func (x *GetBlockDagInfoResponseMessage) String() string { func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5937,7 +6069,7 @@ func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} + return file_messages_proto_rawDescGZIP(), []int{85} } func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { @@ -6007,7 +6139,7 @@ type ResolveFinalityConflictRequestMessage struct { func (x *ResolveFinalityConflictRequestMessage) Reset() { *x = ResolveFinalityConflictRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6020,7 +6152,7 @@ func (x *ResolveFinalityConflictRequestMessage) String() string { func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6033,7 +6165,7 @@ func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} + return file_messages_proto_rawDescGZIP(), []int{86} } func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { @@ -6054,7 +6186,7 @@ type ResolveFinalityConflictResponseMessage struct { func (x *ResolveFinalityConflictResponseMessage) Reset() { *x = ResolveFinalityConflictResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6067,7 +6199,7 @@ func (x *ResolveFinalityConflictResponseMessage) String() string { func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6080,7 +6212,7 @@ func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} + return file_messages_proto_rawDescGZIP(), []int{87} } func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { @@ -6099,7 +6231,7 @@ type NotifyFinalityConflictsRequestMessage struct { func (x *NotifyFinalityConflictsRequestMessage) Reset() { *x = NotifyFinalityConflictsRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6112,7 +6244,7 @@ func (x *NotifyFinalityConflictsRequestMessage) String() string { func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6125,7 +6257,7 @@ func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} + return file_messages_proto_rawDescGZIP(), []int{88} } type NotifyFinalityConflictsResponseMessage struct { @@ -6139,7 +6271,7 @@ type NotifyFinalityConflictsResponseMessage struct { func (x *NotifyFinalityConflictsResponseMessage) Reset() { *x = NotifyFinalityConflictsResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6152,7 +6284,7 @@ func (x *NotifyFinalityConflictsResponseMessage) String() string { func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6165,7 +6297,7 @@ func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} + return file_messages_proto_rawDescGZIP(), []int{89} } func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { @@ -6186,7 +6318,7 @@ type FinalityConflictNotificationMessage struct { func (x *FinalityConflictNotificationMessage) Reset() { *x = FinalityConflictNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6199,7 +6331,7 @@ func (x *FinalityConflictNotificationMessage) String() string { func (*FinalityConflictNotificationMessage) ProtoMessage() {} func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6212,7 +6344,7 @@ func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} + return file_messages_proto_rawDescGZIP(), []int{90} } func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { @@ -6233,7 +6365,7 @@ type FinalityConflictResolvedNotificationMessage struct { func (x *FinalityConflictResolvedNotificationMessage) Reset() { *x = FinalityConflictResolvedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6246,7 +6378,7 @@ func (x *FinalityConflictResolvedNotificationMessage) String() string { func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6259,7 +6391,7 @@ func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflec // Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} + return file_messages_proto_rawDescGZIP(), []int{91} } func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { @@ -6278,7 +6410,7 @@ type ShutDownRequestMessage struct { func (x *ShutDownRequestMessage) Reset() { *x = ShutDownRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6291,7 +6423,7 @@ func (x *ShutDownRequestMessage) String() string { func (*ShutDownRequestMessage) ProtoMessage() {} func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[92] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6304,7 +6436,7 @@ func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{90} + return file_messages_proto_rawDescGZIP(), []int{92} } type ShutDownResponseMessage struct { @@ -6318,7 +6450,7 @@ type ShutDownResponseMessage struct { func (x *ShutDownResponseMessage) Reset() { *x = ShutDownResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6331,7 +6463,7 @@ func (x *ShutDownResponseMessage) String() string { func (*ShutDownResponseMessage) ProtoMessage() {} func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[93] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6344,7 +6476,7 @@ func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{91} + return file_messages_proto_rawDescGZIP(), []int{93} } func (x *ShutDownResponseMessage) GetError() *RPCError { @@ -6367,7 +6499,7 @@ type GetHeadersRequestMessage struct { func (x *GetHeadersRequestMessage) Reset() { *x = GetHeadersRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6380,7 +6512,7 @@ func (x *GetHeadersRequestMessage) String() string { func (*GetHeadersRequestMessage) ProtoMessage() {} func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[94] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6393,7 +6525,7 @@ func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{92} + return file_messages_proto_rawDescGZIP(), []int{94} } func (x *GetHeadersRequestMessage) GetStartHash() string { @@ -6429,7 +6561,7 @@ type GetHeadersResponseMessage struct { func (x *GetHeadersResponseMessage) Reset() { *x = GetHeadersResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6442,7 +6574,7 @@ func (x *GetHeadersResponseMessage) String() string { func (*GetHeadersResponseMessage) ProtoMessage() {} func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[95] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6455,7 +6587,7 @@ func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{93} + return file_messages_proto_rawDescGZIP(), []int{95} } func (x *GetHeadersResponseMessage) GetHeaders() []string { @@ -6483,7 +6615,7 @@ type NotifyUtxosChangedRequestMessage struct { func (x *NotifyUtxosChangedRequestMessage) Reset() { *x = NotifyUtxosChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6496,7 +6628,7 @@ func (x *NotifyUtxosChangedRequestMessage) String() string { func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[96] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6509,7 +6641,7 @@ func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{94} + return file_messages_proto_rawDescGZIP(), []int{96} } func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { @@ -6530,7 +6662,7 @@ type NotifyUtxosChangedResponseMessage struct { func (x *NotifyUtxosChangedResponseMessage) Reset() { *x = NotifyUtxosChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6543,7 +6675,7 @@ func (x *NotifyUtxosChangedResponseMessage) String() string { func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[97] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6556,7 +6688,7 @@ func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{95} + return file_messages_proto_rawDescGZIP(), []int{97} } func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { @@ -6578,7 +6710,7 @@ type UtxosChangedNotificationMessage struct { func (x *UtxosChangedNotificationMessage) Reset() { *x = UtxosChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6591,7 +6723,7 @@ func (x *UtxosChangedNotificationMessage) String() string { func (*UtxosChangedNotificationMessage) ProtoMessage() {} func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[98] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6604,7 +6736,7 @@ func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{96} + return file_messages_proto_rawDescGZIP(), []int{98} } func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { @@ -6634,7 +6766,7 @@ type UtxosByAddressesEntry struct { func (x *UtxosByAddressesEntry) Reset() { *x = UtxosByAddressesEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6647,7 +6779,7 @@ func (x *UtxosByAddressesEntry) String() string { func (*UtxosByAddressesEntry) ProtoMessage() {} func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[99] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6660,7 +6792,7 @@ func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{97} + return file_messages_proto_rawDescGZIP(), []int{99} } func (x *UtxosByAddressesEntry) GetAddress() string { @@ -6702,7 +6834,7 @@ type RpcTransaction struct { func (x *RpcTransaction) Reset() { *x = RpcTransaction{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6715,7 +6847,7 @@ func (x *RpcTransaction) String() string { func (*RpcTransaction) ProtoMessage() {} func (x *RpcTransaction) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[100] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6728,7 +6860,7 @@ func (x *RpcTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. func (*RpcTransaction) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{98} + return file_messages_proto_rawDescGZIP(), []int{100} } func (x *RpcTransaction) GetVersion() int32 { @@ -6800,7 +6932,7 @@ type RpcTransactionInput struct { func (x *RpcTransactionInput) Reset() { *x = RpcTransactionInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6813,7 +6945,7 @@ func (x *RpcTransactionInput) String() string { func (*RpcTransactionInput) ProtoMessage() {} func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[101] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6826,7 +6958,7 @@ func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. func (*RpcTransactionInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{99} + return file_messages_proto_rawDescGZIP(), []int{101} } func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { @@ -6862,7 +6994,7 @@ type RpcTransactionOutput struct { func (x *RpcTransactionOutput) Reset() { *x = RpcTransactionOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6875,7 +7007,7 @@ func (x *RpcTransactionOutput) String() string { func (*RpcTransactionOutput) ProtoMessage() {} func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[102] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6888,7 +7020,7 @@ func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{100} + return file_messages_proto_rawDescGZIP(), []int{102} } func (x *RpcTransactionOutput) GetAmount() uint64 { @@ -6917,7 +7049,7 @@ type RpcOutpoint struct { func (x *RpcOutpoint) Reset() { *x = RpcOutpoint{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6930,7 +7062,7 @@ func (x *RpcOutpoint) String() string { func (*RpcOutpoint) ProtoMessage() {} func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[103] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6943,7 +7075,7 @@ func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. func (*RpcOutpoint) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{101} + return file_messages_proto_rawDescGZIP(), []int{103} } func (x *RpcOutpoint) GetTransactionId() string { @@ -6974,7 +7106,7 @@ type RpcUtxoEntry struct { func (x *RpcUtxoEntry) Reset() { *x = RpcUtxoEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6987,7 +7119,7 @@ func (x *RpcUtxoEntry) String() string { func (*RpcUtxoEntry) ProtoMessage() {} func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[104] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7000,7 +7132,7 @@ func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{102} + return file_messages_proto_rawDescGZIP(), []int{104} } func (x *RpcUtxoEntry) GetAmount() uint64 { @@ -7042,7 +7174,7 @@ type GetUtxosByAddressesRequestMessage struct { func (x *GetUtxosByAddressesRequestMessage) Reset() { *x = GetUtxosByAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7055,7 +7187,7 @@ func (x *GetUtxosByAddressesRequestMessage) String() string { func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[105] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7068,7 +7200,7 @@ func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{103} + return file_messages_proto_rawDescGZIP(), []int{105} } func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { @@ -7090,7 +7222,7 @@ type GetUtxosByAddressesResponseMessage struct { func (x *GetUtxosByAddressesResponseMessage) Reset() { *x = GetUtxosByAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7103,7 +7235,7 @@ func (x *GetUtxosByAddressesResponseMessage) String() string { func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[106] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7116,7 +7248,7 @@ func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{104} + return file_messages_proto_rawDescGZIP(), []int{106} } func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { @@ -7142,7 +7274,7 @@ type GetVirtualSelectedParentBlueScoreRequestMessage struct { func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7155,7 +7287,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[107] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7168,7 +7300,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protore // Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{105} + return file_messages_proto_rawDescGZIP(), []int{107} } type GetVirtualSelectedParentBlueScoreResponseMessage struct { @@ -7183,7 +7315,7 @@ type GetVirtualSelectedParentBlueScoreResponseMessage struct { func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7196,7 +7328,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[108] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7209,7 +7341,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protor // Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{106} + return file_messages_proto_rawDescGZIP(), []int{108} } func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { @@ -7235,7 +7367,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7248,7 +7380,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() str func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[109] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7261,7 +7393,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{107} + return file_messages_proto_rawDescGZIP(), []int{109} } type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { @@ -7275,7 +7407,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[108] + mi := &file_messages_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7288,7 +7420,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() st func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[108] + mi := &file_messages_proto_msgTypes[110] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7301,7 +7433,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflec // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{108} + return file_messages_proto_rawDescGZIP(), []int{110} } func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { @@ -7322,7 +7454,7 @@ type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[109] + mi := &file_messages_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7335,7 +7467,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() stri func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[109] + mi := &file_messages_proto_msgTypes[111] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7348,7 +7480,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect( // Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{109} + return file_messages_proto_rawDescGZIP(), []int{111} } func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { @@ -7362,7 +7494,7 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0x86, 0x44, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xd3, 0x45, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -7478,633 +7610,661 @@ var file_messages_proto_rawDesc = []byte{ 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, - 0x64, 0x12, 0x4f, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, - 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x64, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, + 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x12, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, - 0x73, 0x68, 0x12, 0x3a, 0x0a, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, - 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x48, - 0x00, 0x52, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x69, - 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, 0x69, 0x62, 0x64, + 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, + 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, + 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, + 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, + 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, + 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x69, 0x0a, 0x18, 0x67, + 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, - 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, + 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, + 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, - 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, + 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, + 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, + 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, + 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, - 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, - 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, - 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, - 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, - 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, + 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, + 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, + 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x14, 0x67, - 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x15, - 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 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, 0x48, - 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, + 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, + 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, - 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, - 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, + 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, + 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, + 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, - 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, - 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, + 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x14, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x15, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x1e, 0x6e, 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, 0x12, - 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, + 0x1e, 0x72, 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, 0x12, + 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, + 0x72, 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, 0x12, + 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x12, - 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, - 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, - 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, - 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, + 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, + 0x66, 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, 0x18, 0x91, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x24, 0x66, + 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, + 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, + 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, + 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, + 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, + 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, + 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, - 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, - 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, + 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, - 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, + 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, + 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, + 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, + 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, + 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, + 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, + 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, + 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, + 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, + 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, + 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, + 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, + 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, + 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, + 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, + 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, + 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, + 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, + 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, + 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, - 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, - 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, - 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, - 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, - 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, + 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, + 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, + 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, + 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, + 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, - 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, - 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, - 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, - 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, - 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, - 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, - 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, - 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, - 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, - 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, - 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, - 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, - 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, - 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, - 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, - 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, - 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, - 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, - 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x22, 0x32, 0x0a, 0x0b, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, + 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, + 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, @@ -8709,7 +8869,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 110) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 112) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage @@ -8743,84 +8903,86 @@ var file_messages_proto_goTypes = []interface{}{ (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage - (*RequestIBDRootHash)(nil), // 32: protowire.RequestIBDRootHash - (*IBDRootHash)(nil), // 33: protowire.IBDRootHash - (*RPCError)(nil), // 34: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 35: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 36: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 37: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 38: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 39: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 40: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 41: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 42: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 43: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 44: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 45: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 46: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 47: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 48: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 49: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 50: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 51: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 52: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 53: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 54: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 55: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 56: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 57: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 58: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 59: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 60: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 61: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 62: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 63: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*ChainBlock)(nil), // 64: protowire.ChainBlock - (*AcceptedBlock)(nil), // 65: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 66: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 67: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 68: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 69: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 70: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 71: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 72: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 73: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 74: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 75: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 76: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 77: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 78: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 79: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 80: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 81: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 82: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 83: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 84: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 85: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 86: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 87: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 88: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 89: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 90: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 91: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 92: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 93: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 94: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 95: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 96: protowire.UtxosChangedNotificationMessage - (*UtxosByAddressesEntry)(nil), // 97: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 98: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 99: protowire.RpcTransactionInput - (*RpcTransactionOutput)(nil), // 100: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 101: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 102: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 103: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 104: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 105: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 106: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 107: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 108: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 109: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*RequestIBDRootHashMessage)(nil), // 32: protowire.RequestIBDRootHashMessage + (*IBDRootHashMessage)(nil), // 33: protowire.IBDRootHashMessage + (*IbdBlockLocatorMessage)(nil), // 34: protowire.IbdBlockLocatorMessage + (*IbdBlockLocatorHighestHashMessage)(nil), // 35: protowire.IbdBlockLocatorHighestHashMessage + (*RPCError)(nil), // 36: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 37: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 38: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 39: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 40: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 41: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 42: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 43: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 44: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 45: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 46: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 47: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 48: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 49: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 50: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 51: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 52: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 53: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 54: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 55: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 56: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 57: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 58: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 59: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 60: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 61: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 62: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 63: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 64: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 65: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*ChainBlock)(nil), // 66: protowire.ChainBlock + (*AcceptedBlock)(nil), // 67: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 68: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 69: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 70: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 71: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 72: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 73: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 74: protowire.TransactionVerboseOutput + (*ScriptPubKeyResult)(nil), // 75: protowire.ScriptPubKeyResult + (*GetSubnetworkRequestMessage)(nil), // 76: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 77: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 78: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 79: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 80: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 81: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 82: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 83: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 84: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 85: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 86: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 87: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 88: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 89: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 90: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 91: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 92: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 93: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 94: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 95: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 96: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 97: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 98: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 99: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 100: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 101: protowire.RpcTransactionInput + (*RpcTransactionOutput)(nil), // 102: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 103: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 104: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 105: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 106: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 107: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 108: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 109: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 110: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 111: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -8848,159 +9010,164 @@ var file_messages_proto_depIdxs = []int32{ 29, // 22: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage 30, // 23: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage 31, // 24: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 32, // 25: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHash - 33, // 26: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHash - 35, // 27: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 36, // 28: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 37, // 29: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 38, // 30: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 39, // 31: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 40, // 32: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 41, // 33: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 42, // 34: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 43, // 35: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 44, // 36: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 45, // 37: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 47, // 38: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 48, // 39: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 50, // 40: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 51, // 41: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 54, // 42: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 55, // 43: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 57, // 44: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 58, // 45: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 59, // 46: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 60, // 47: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 61, // 48: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 62, // 49: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 63, // 50: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 66, // 51: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 67, // 52: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 74, // 53: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 75, // 54: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 76, // 55: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 77, // 56: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 78, // 57: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 79, // 58: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 80, // 59: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 81, // 60: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 82, // 61: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 83, // 62: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 84, // 63: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 85, // 64: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 86, // 65: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 87, // 66: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 88, // 67: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 89, // 68: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 52, // 69: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 53, // 70: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 90, // 71: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 91, // 72: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 92, // 73: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 93, // 74: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 94, // 75: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 95, // 76: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 96, // 77: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 103, // 78: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 104, // 79: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 105, // 80: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 106, // 81: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 107, // 82: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 108, // 83: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 109, // 84: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 4, // 85: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId - 3, // 86: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 6, // 87: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 88: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 4, // 89: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 90: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 91: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint - 8, // 92: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId - 11, // 93: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 94: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 95: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 12, // 96: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 97: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash - 12, // 98: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 12, // 99: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 100: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 101: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 102: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 12, // 103: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 12, // 104: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 105: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId - 8, // 106: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId - 12, // 107: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 108: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId - 3, // 109: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 4, // 110: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 111: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 112: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 113: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 12, // 114: protowire.IBDRootHash.hash:type_name -> protowire.Hash - 34, // 115: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 116: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 34, // 117: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 118: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 34, // 119: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 34, // 120: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 121: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 46, // 122: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 46, // 123: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 34, // 124: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 34, // 125: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 69, // 126: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 49, // 127: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 34, // 128: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 49, // 129: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 34, // 130: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 56, // 131: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 34, // 132: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 133: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 98, // 134: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 34, // 135: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 34, // 136: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 64, // 137: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 65, // 138: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 68, // 139: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 140: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 69, // 141: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 70, // 142: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 72, // 143: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 71, // 144: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 73, // 145: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 34, // 146: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 64, // 147: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 34, // 148: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 68, // 149: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 34, // 150: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 34, // 151: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 34, // 152: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 34, // 153: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 34, // 154: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 34, // 155: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 34, // 156: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 34, // 157: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 97, // 158: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 97, // 159: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 101, // 160: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 102, // 161: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 99, // 162: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 100, // 163: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 101, // 164: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 97, // 165: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 34, // 166: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 34, // 167: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 34, // 168: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 0, // 169: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 170: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 171: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 172: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 171, // [171:173] is the sub-list for method output_type - 169, // [169:171] is the sub-list for method input_type - 169, // [169:169] is the sub-list for extension type_name - 169, // [169:169] is the sub-list for extension extendee - 0, // [0:169] is the sub-list for field type_name + 32, // 25: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage + 33, // 26: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage + 34, // 27: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage + 35, // 28: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage + 37, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 38, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 39, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 40, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 41, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 42, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 43, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 44, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 45, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 46, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 47, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 49, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 50, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 52, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 53, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 56, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 57, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 59, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 60, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 61, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 62, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 63, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 64, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 65, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 68, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 69, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 76, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 77, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 78, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 79, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 80, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 81, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 82, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 83, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 84, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 85, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 86, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 87, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 88, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 89, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 90, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 91, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 54, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 55, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 92, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 93, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 94, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 95, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 96, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 97, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 98, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 105, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 106, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 107, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 108, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 109, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 110, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 111, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 4, // 87: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId + 3, // 88: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 6, // 89: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 90: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 4, // 91: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 92: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 7, // 93: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint + 8, // 94: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId + 11, // 95: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 96: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 97: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 98: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 99: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash + 12, // 100: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 101: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 102: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 103: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 104: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 105: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 106: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 107: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 8, // 108: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId + 12, // 109: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 110: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId + 3, // 111: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 4, // 112: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 113: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 114: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 115: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 12, // 116: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash + 12, // 117: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash + 12, // 118: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash + 12, // 119: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash + 36, // 120: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 121: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 36, // 122: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 123: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 36, // 124: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 36, // 125: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 126: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 48, // 127: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 48, // 128: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 36, // 129: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 36, // 130: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 71, // 131: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 51, // 132: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 36, // 133: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 51, // 134: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 36, // 135: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 58, // 136: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 36, // 137: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 36, // 138: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 100, // 139: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 36, // 140: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 36, // 141: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 66, // 142: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 67, // 143: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 70, // 144: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 36, // 145: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 71, // 146: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 72, // 147: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 74, // 148: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 73, // 149: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 75, // 150: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 36, // 151: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 66, // 152: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 36, // 153: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 70, // 154: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 36, // 155: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 36, // 156: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 36, // 157: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 36, // 158: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 36, // 159: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 36, // 160: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 36, // 161: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 36, // 162: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 99, // 163: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 99, // 164: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 103, // 165: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 104, // 166: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 101, // 167: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 102, // 168: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 103, // 169: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 99, // 170: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 36, // 171: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 36, // 172: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 36, // 173: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 0, // 174: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 175: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 176: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 177: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 176, // [176:178] is the sub-list for method output_type + 174, // [174:176] is the sub-list for method input_type + 174, // [174:174] is the sub-list for extension type_name + 174, // [174:174] is the sub-list for extension extendee + 0, // [0:174] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -9394,7 +9561,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootHash); i { + switch v := v.(*RequestIBDRootHashMessage); i { case 0: return &v.state case 1: @@ -9406,7 +9573,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootHash); i { + switch v := v.(*IBDRootHashMessage); i { case 0: return &v.state case 1: @@ -9418,7 +9585,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCError); i { + switch v := v.(*IbdBlockLocatorMessage); i { case 0: return &v.state case 1: @@ -9430,7 +9597,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkRequestMessage); i { + switch v := v.(*IbdBlockLocatorHighestHashMessage); i { case 0: return &v.state case 1: @@ -9442,7 +9609,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkResponseMessage); i { + switch v := v.(*RPCError); i { case 0: return &v.state case 1: @@ -9454,7 +9621,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockRequestMessage); i { + switch v := v.(*GetCurrentNetworkRequestMessage); i { case 0: return &v.state case 1: @@ -9466,7 +9633,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockResponseMessage); i { + switch v := v.(*GetCurrentNetworkResponseMessage); i { case 0: return &v.state case 1: @@ -9478,7 +9645,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateRequestMessage); i { + switch v := v.(*SubmitBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9490,7 +9657,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateResponseMessage); i { + switch v := v.(*SubmitBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9502,7 +9669,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedRequestMessage); i { + switch v := v.(*GetBlockTemplateRequestMessage); i { case 0: return &v.state case 1: @@ -9514,7 +9681,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedResponseMessage); i { + switch v := v.(*GetBlockTemplateResponseMessage); i { case 0: return &v.state case 1: @@ -9526,7 +9693,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockAddedNotificationMessage); i { + switch v := v.(*NotifyBlockAddedRequestMessage); i { case 0: return &v.state case 1: @@ -9538,7 +9705,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesRequestMessage); i { + switch v := v.(*NotifyBlockAddedResponseMessage); i { case 0: return &v.state case 1: @@ -9550,7 +9717,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesResponseMessage); i { + switch v := v.(*BlockAddedNotificationMessage); i { case 0: return &v.state case 1: @@ -9562,7 +9729,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesKnownAddressMessage); i { + switch v := v.(*GetPeerAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -9574,7 +9741,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashRequestMessage); i { + switch v := v.(*GetPeerAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -9586,7 +9753,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashResponseMessage); i { + switch v := v.(*GetPeerAddressesKnownAddressMessage); i { case 0: return &v.state case 1: @@ -9598,7 +9765,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MempoolEntry); i { + switch v := v.(*GetSelectedTipHashRequestMessage); i { case 0: return &v.state case 1: @@ -9610,7 +9777,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryRequestMessage); i { + switch v := v.(*GetSelectedTipHashResponseMessage); i { case 0: return &v.state case 1: @@ -9622,7 +9789,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryResponseMessage); i { + switch v := v.(*MempoolEntry); i { case 0: return &v.state case 1: @@ -9634,7 +9801,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesRequestMessage); i { + switch v := v.(*GetMempoolEntryRequestMessage); i { case 0: return &v.state case 1: @@ -9646,7 +9813,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesResponseMessage); i { + switch v := v.(*GetMempoolEntryResponseMessage); i { case 0: return &v.state case 1: @@ -9658,7 +9825,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoRequestMessage); i { + switch v := v.(*GetMempoolEntriesRequestMessage); i { case 0: return &v.state case 1: @@ -9670,7 +9837,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoResponseMessage); i { + switch v := v.(*GetMempoolEntriesResponseMessage); i { case 0: return &v.state case 1: @@ -9682,7 +9849,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoMessage); i { + switch v := v.(*GetConnectedPeerInfoRequestMessage); i { case 0: return &v.state case 1: @@ -9694,7 +9861,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerRequestMessage); i { + switch v := v.(*GetConnectedPeerInfoResponseMessage); i { case 0: return &v.state case 1: @@ -9706,7 +9873,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerResponseMessage); i { + switch v := v.(*GetConnectedPeerInfoMessage); i { case 0: return &v.state case 1: @@ -9718,7 +9885,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionRequestMessage); i { + switch v := v.(*AddPeerRequestMessage); i { case 0: return &v.state case 1: @@ -9730,7 +9897,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionResponseMessage); i { + switch v := v.(*AddPeerResponseMessage); i { case 0: return &v.state case 1: @@ -9742,7 +9909,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { + switch v := v.(*SubmitTransactionRequestMessage); i { case 0: return &v.state case 1: @@ -9754,7 +9921,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { + switch v := v.(*SubmitTransactionResponseMessage); i { case 0: return &v.state case 1: @@ -9766,7 +9933,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { case 0: return &v.state case 1: @@ -9778,7 +9945,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainBlock); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { case 0: return &v.state case 1: @@ -9790,7 +9957,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptedBlock); i { + switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -9802,7 +9969,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockRequestMessage); i { + switch v := v.(*ChainBlock); i { case 0: return &v.state case 1: @@ -9814,7 +9981,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockResponseMessage); i { + switch v := v.(*AcceptedBlock); i { case 0: return &v.state case 1: @@ -9826,7 +9993,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockVerboseData); i { + switch v := v.(*GetBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9838,7 +10005,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseData); i { + switch v := v.(*GetBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9850,7 +10017,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseInput); i { + switch v := v.(*BlockVerboseData); i { case 0: return &v.state case 1: @@ -9862,7 +10029,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptSig); i { + switch v := v.(*TransactionVerboseData); i { case 0: return &v.state case 1: @@ -9874,7 +10041,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseOutput); i { + switch v := v.(*TransactionVerboseInput); i { case 0: return &v.state case 1: @@ -9886,7 +10053,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPubKeyResult); i { + switch v := v.(*ScriptSig); i { case 0: return &v.state case 1: @@ -9898,7 +10065,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkRequestMessage); i { + switch v := v.(*TransactionVerboseOutput); i { case 0: return &v.state case 1: @@ -9910,7 +10077,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkResponseMessage); i { + switch v := v.(*ScriptPubKeyResult); i { case 0: return &v.state case 1: @@ -9922,7 +10089,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { + switch v := v.(*GetSubnetworkRequestMessage); i { case 0: return &v.state case 1: @@ -9934,7 +10101,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { + switch v := v.(*GetSubnetworkResponseMessage); i { case 0: return &v.state case 1: @@ -9946,7 +10113,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9958,7 +10125,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9970,7 +10137,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountRequestMessage); i { + switch v := v.(*GetBlocksRequestMessage); i { case 0: return &v.state case 1: @@ -9982,7 +10149,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountResponseMessage); i { + switch v := v.(*GetBlocksResponseMessage); i { case 0: return &v.state case 1: @@ -9994,7 +10161,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoRequestMessage); i { + switch v := v.(*GetBlockCountRequestMessage); i { case 0: return &v.state case 1: @@ -10006,7 +10173,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoResponseMessage); i { + switch v := v.(*GetBlockCountResponseMessage); i { case 0: return &v.state case 1: @@ -10018,7 +10185,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictRequestMessage); i { + switch v := v.(*GetBlockDagInfoRequestMessage); i { case 0: return &v.state case 1: @@ -10030,7 +10197,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictResponseMessage); i { + switch v := v.(*GetBlockDagInfoResponseMessage); i { case 0: return &v.state case 1: @@ -10042,7 +10209,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsRequestMessage); i { + switch v := v.(*ResolveFinalityConflictRequestMessage); i { case 0: return &v.state case 1: @@ -10054,7 +10221,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsResponseMessage); i { + switch v := v.(*ResolveFinalityConflictResponseMessage); i { case 0: return &v.state case 1: @@ -10066,7 +10233,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictNotificationMessage); i { + switch v := v.(*NotifyFinalityConflictsRequestMessage); i { case 0: return &v.state case 1: @@ -10078,7 +10245,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + switch v := v.(*NotifyFinalityConflictsResponseMessage); i { case 0: return &v.state case 1: @@ -10090,7 +10257,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownRequestMessage); i { + switch v := v.(*FinalityConflictNotificationMessage); i { case 0: return &v.state case 1: @@ -10102,7 +10269,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownResponseMessage); i { + switch v := v.(*FinalityConflictResolvedNotificationMessage); i { case 0: return &v.state case 1: @@ -10114,7 +10281,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersRequestMessage); i { + switch v := v.(*ShutDownRequestMessage); i { case 0: return &v.state case 1: @@ -10126,7 +10293,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersResponseMessage); i { + switch v := v.(*ShutDownResponseMessage); i { case 0: return &v.state case 1: @@ -10138,7 +10305,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedRequestMessage); i { + switch v := v.(*GetHeadersRequestMessage); i { case 0: return &v.state case 1: @@ -10150,7 +10317,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedResponseMessage); i { + switch v := v.(*GetHeadersResponseMessage); i { case 0: return &v.state case 1: @@ -10162,7 +10329,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosChangedNotificationMessage); i { + switch v := v.(*NotifyUtxosChangedRequestMessage); i { case 0: return &v.state case 1: @@ -10174,7 +10341,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosByAddressesEntry); i { + switch v := v.(*NotifyUtxosChangedResponseMessage); i { case 0: return &v.state case 1: @@ -10186,7 +10353,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransaction); i { + switch v := v.(*UtxosChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -10198,7 +10365,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionInput); i { + switch v := v.(*UtxosByAddressesEntry); i { case 0: return &v.state case 1: @@ -10210,7 +10377,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionOutput); i { + switch v := v.(*RpcTransaction); i { case 0: return &v.state case 1: @@ -10222,7 +10389,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcOutpoint); i { + switch v := v.(*RpcTransactionInput); i { case 0: return &v.state case 1: @@ -10234,7 +10401,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcUtxoEntry); i { + switch v := v.(*RpcTransactionOutput); i { case 0: return &v.state case 1: @@ -10246,7 +10413,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesRequestMessage); i { + switch v := v.(*RpcOutpoint); i { case 0: return &v.state case 1: @@ -10258,7 +10425,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesResponseMessage); i { + switch v := v.(*RpcUtxoEntry); i { case 0: return &v.state case 1: @@ -10270,7 +10437,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -10282,7 +10449,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -10294,7 +10461,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { case 0: return &v.state case 1: @@ -10306,7 +10473,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { case 0: return &v.state case 1: @@ -10318,6 +10485,30 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { case 0: return &v.state @@ -10358,6 +10549,8 @@ func file_messages_proto_init() { (*KaspadMessage_IbdRootNotFound)(nil), (*KaspadMessage_RequestIBDRootHash)(nil), (*KaspadMessage_IbdRootHash)(nil), + (*KaspadMessage_IbdBlockLocator)(nil), + (*KaspadMessage_IbdBlockLocatorHighestHash)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), @@ -10423,7 +10616,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 110, + NumMessages: 112, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 3f696e14b..77673afd8 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -30,8 +30,10 @@ message KaspadMessage { IBDRootUTXOSetAndBlockMessage ibdRootUTXOSetAndBlock = 25; RequestIBDBlocksMessage requestIBDBlocks = 26; IBDRootNotFoundMessage ibdRootNotFound = 27; - RequestIBDRootHash requestIBDRootHash = 28; - IBDRootHash ibdRootHash = 29; + RequestIBDRootHashMessage requestIBDRootHash = 28; + IBDRootHashMessage ibdRootHash = 29; + IbdBlockLocatorMessage ibdBlockLocator = 30; + IbdBlockLocatorHighestHashMessage ibdBlockLocatorHighestHash = 31; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; @@ -299,16 +301,29 @@ message IBDRootNotFoundMessage{ } // IBDRootNotFoundMessage end -// RequestIBDRootHash start -message RequestIBDRootHash{ +// RequestIBDRootHashMessage start +message RequestIBDRootHashMessage{ } -// RequestIBDRootHash end +// RequestIBDRootHashMessage end -// IBDRootHash start -message IBDRootHash{ +// IBDRootHashMessage start +message IBDRootHashMessage{ Hash hash = 1; } -// IBDRootHash end +// IBDRootHashMessage end + +// IbdBlockLocatorMessage start +message IbdBlockLocatorMessage { + Hash targetHash = 1; + repeated Hash blockLocatorHashes = 2; +} +// IbdBlockLocatorMessage end + +// IbdBlockLocatorHighestHashMessage start +message IbdBlockLocatorHighestHashMessage { + Hash highestHash = 1; +} +// IbdBlockLocatorHighestHashMessage end service P2P { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator.go new file mode 100644 index 000000000..f1bcd577b --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator.go @@ -0,0 +1,28 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_IbdBlockLocator) toAppMessage() (appmessage.Message, error) { + targetHash, err := x.IbdBlockLocator.TargetHash.toDomain() + if err != nil { + return nil, err + } + blockLocatorHash, err := protoHashesToDomain(x.IbdBlockLocator.BlockLocatorHashes) + if err != nil { + return nil, err + } + return &appmessage.MsgIBDBlockLocator{ + TargetHash: targetHash, + BlockLocatorHashes: blockLocatorHash, + }, nil +} + +func (x *KaspadMessage_IbdBlockLocator) fromAppMessage(message *appmessage.MsgIBDBlockLocator) error { + x.IbdBlockLocator = &IbdBlockLocatorMessage{ + TargetHash: domainHashToProto(message.TargetHash), + BlockLocatorHashes: domainHashesToProto(message.BlockLocatorHashes), + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash.go new file mode 100644 index 000000000..ae5c9f44a --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash.go @@ -0,0 +1,21 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_IbdBlockLocatorHighestHash) toAppMessage() (appmessage.Message, error) { + highestHash, err := x.IbdBlockLocatorHighestHash.HighestHash.toDomain() + if err != nil { + return nil, err + } + + return &appmessage.MsgIBDBlockLocatorHighestHash{ + HighestHash: highestHash, + }, nil +} + +func (x *KaspadMessage_IbdBlockLocatorHighestHash) fromAppMessage(message *appmessage.MsgIBDBlockLocatorHighestHash) error { + x.IbdBlockLocatorHighestHash = &IbdBlockLocatorHighestHashMessage{ + HighestHash: domainHashToProto(message.HighestHash), + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go index 2c48f2836..c6ff814fd 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go @@ -8,11 +8,11 @@ func (x *KaspadMessage_IbdRootHash) toAppMessage() (appmessage.Message, error) { return nil, err } - return &appmessage.MsgIBDRootHash{Hash: hash}, nil + return &appmessage.MsgIBDRootHashMessage{Hash: hash}, nil } -func (x *KaspadMessage_IbdRootHash) fromAppMessage(msgIBDRootHash *appmessage.MsgIBDRootHash) error { - x.IbdRootHash = &IBDRootHash{ +func (x *KaspadMessage_IbdRootHash) fromAppMessage(msgIBDRootHash *appmessage.MsgIBDRootHashMessage) error { + x.IbdRootHash = &IBDRootHashMessage{ Hash: domainHashToProto(msgIBDRootHash.Hash), } return nil diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go index da9c3e38e..770fb8a36 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go @@ -3,9 +3,9 @@ package protowire import "github.com/kaspanet/kaspad/app/appmessage" func (x *KaspadMessage_RequestIBDRootHash) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgRequestIBDRootHash{}, nil + return &appmessage.MsgRequestIBDRootHashMessage{}, nil } -func (x *KaspadMessage_RequestIBDRootHash) fromAppMessage(_ *appmessage.MsgRequestIBDRootHash) error { +func (x *KaspadMessage_RequestIBDRootHash) fromAppMessage(_ *appmessage.MsgRequestIBDRootHashMessage) error { return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index a5782f999..b6985e7df 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -195,7 +195,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgBlockHeader: payload := new(KaspadMessage_BlockHeader) err := payload.fromAppMessage(message) @@ -203,7 +202,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgRequestIBDRootUTXOSetAndBlock: payload := new(KaspadMessage_RequestIBDRootUTXOSetAndBlock) err := payload.fromAppMessage(message) @@ -211,7 +209,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgIBDRootUTXOSetAndBlock: payload := new(KaspadMessage_IbdRootUTXOSetAndBlock) err := payload.fromAppMessage(message) @@ -219,7 +216,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgRequestHeaders: payload := new(KaspadMessage_RequestHeaders) err := payload.fromAppMessage(message) @@ -227,7 +223,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgIBDRootNotFound: payload := new(KaspadMessage_IbdRootNotFound) err := payload.fromAppMessage(message) @@ -235,23 +230,34 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - - case *appmessage.MsgRequestIBDRootHash: + case *appmessage.MsgRequestIBDRootHashMessage: payload := new(KaspadMessage_RequestIBDRootHash) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - - case *appmessage.MsgIBDRootHash: + case *appmessage.MsgIBDRootHashMessage: payload := new(KaspadMessage_IbdRootHash) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - + case *appmessage.MsgIBDBlockLocator: + payload := new(KaspadMessage_IbdBlockLocator) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.MsgIBDBlockLocatorHighestHash: + payload := new(KaspadMessage_IbdBlockLocatorHighestHash) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil default: return nil, nil } From e87368157dde00ae3c4bfc80d0bff1f21ae777cc Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 30 Dec 2020 17:46:17 +0200 Subject: [PATCH 189/351] Update go.yml (#1330) --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 97c24090f..b10b6f049 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ ubuntu-16.04, windows-2019, macos-10.15 ] + os: [ ubuntu-16.04, macos-10.15 ] name: Testing on on ${{ matrix.os }} steps: From 9401b77a4f0189417e858703c747c662ae1b9c94 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 30 Dec 2020 18:13:12 +0200 Subject: [PATCH 190/351] Improve the performance of GetBlock and GetBlockHeader. (#1328) --- domain/consensus/consensus.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index cf29254ec..614d19b97 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -1,6 +1,7 @@ package consensus import ( + "github.com/kaspanet/kaspad/infrastructure/db/database" "sync" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -95,24 +96,28 @@ func (s *consensus) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.Do s.lock.Lock() defer s.lock.Unlock() - err := s.validateBlockHashExists(blockHash) + block, err := s.blockStore.Block(s.databaseContext, blockHash) if err != nil { + if errors.Is(err, database.ErrNotFound) { + return nil, errors.Wrapf(err, "block %s does not exist", blockHash) + } return nil, err } - - return s.blockStore.Block(s.databaseContext, blockHash) + return block, nil } func (s *consensus) GetBlockHeader(blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) { s.lock.Lock() defer s.lock.Unlock() - err := s.validateBlockHashExists(blockHash) + blockHeader, err := s.blockHeaderStore.BlockHeader(s.databaseContext, blockHash) if err != nil { + if errors.Is(err, database.ErrNotFound) { + return nil, errors.Wrapf(err, "block header %s does not exist", blockHash) + } return nil, err } - - return s.blockHeaderStore.BlockHeader(s.databaseContext, blockHash) + return blockHeader, nil } func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) { @@ -340,7 +345,7 @@ func (s *consensus) validateBlockHashExists(blockHash *externalapi.DomainHash) e return err } if !exists { - return errors.Errorf("block %s does not exists", blockHash) + return errors.Errorf("block %s does not exist", blockHash) } return nil } From dd356698613447652bd311fe7be93be84e17bfe7 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 30 Dec 2020 18:31:17 +0200 Subject: [PATCH 191/351] Check that there are no prefilled fields when validating a block (#1329) * Check that there are no prefilled fields when validating a block * Use cleanBlockPrefilledFields in AddBlock * Move cleanBlockPrefilledFields to BuildBlockWithParents * Move cleanBlockPrefilledFields to func (bb *testBlockBuilder) BuildBlockWithParents --- .../blockbuilder/test_block_builder.go | 23 +++++++++++++- .../blockvalidator/block_body_in_isolation.go | 30 +++++++++++++++++++ domain/consensus/test_consensus.go | 7 ++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 31eeea624..697672d60 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -28,6 +28,18 @@ func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder, testConsensus test } } +func cleanBlockPrefilledFields(block *externalapi.DomainBlock) { + for _, tx := range block.Transactions { + tx.Fee = 0 + tx.Mass = 0 + tx.ID = nil + + for _, input := range tx.Inputs { + input.UTXOEntry = nil + } + } +} + // BuildBlockWithParents builds a block with provided parents, coinbaseData and transactions, // and returns the block together with its past UTXO-diff from the virtual. func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, @@ -37,7 +49,16 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockWithParents") defer onEnd() - return bb.buildBlockWithParents(parentHashes, coinbaseData, transactions) + block, diff, err := bb.buildBlockWithParents(parentHashes, coinbaseData, transactions) + if err != nil { + return nil, nil, err + } + + // It's invalid to insert a block with prefilled fields to consensus, so we + // clean them before returning the block. + cleanBlockPrefilledFields(block) + + return block, diff, nil } func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index aa0f6d45c..4c3cf18d2 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -23,6 +23,11 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa return err } + err = v.checkNoPrefilledFields(block) + if err != nil { + return err + } + err = v.checkBlockSize(block) if err != nil { return err @@ -224,3 +229,28 @@ func (v *blockValidator) checkBlockSize(block *externalapi.DomainBlock) error { return nil } + +func (v *blockValidator) checkNoPrefilledFields(block *externalapi.DomainBlock) error { + for _, tx := range block.Transactions { + if tx.Fee != 0 { + return errors.Errorf("transaction %s has a prefilled fee", consensushashing.TransactionID(tx)) + } + + if tx.Mass != 0 { + return errors.Errorf("transaction %s has a prefilled mass", consensushashing.TransactionID(tx)) + } + + if tx.ID != nil { + return errors.Errorf("transaction %s has a prefilled ID", consensushashing.TransactionID(tx)) + } + + for i, input := range tx.Inputs { + if input.UTXOEntry != nil { + return errors.Errorf("input %d in transaction %s has a prefilled UTXO entry", + i, consensushashing.TransactionID(tx)) + } + } + } + + return nil +} diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 8c4d002c6..c6e1809f6 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -30,7 +30,12 @@ func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.Domai tc.lock.Lock() defer tc.lock.Unlock() - return tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) + block, diff, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) + if err != nil { + return nil, nil, err + } + + return block, diff, nil } func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, From b473a091114a1238795df80626cf5a892de97fc7 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 31 Dec 2020 14:50:14 +0200 Subject: [PATCH 192/351] Fix a crash in the UTXO index (#1332) * Add a field to TransactionAcceptanceData: TransactionInputUTXOEntries. * Fix failing tests. * Add transactionInputUtxoEntries to the database. * Populate transactionInputUTXOEntries in applyMergeSetBlocks and use them in the UTXO index. * Remove UTXOEntry.Clone(). * Add an additional equality test. --- .../database/serialization/acceptancedata.go | 32 +- .../database/serialization/dbobjects.pb.go | 297 +++++++++--------- .../database/serialization/dbobjects.proto | 1 + .../model/acceptancedata_equal_clone_test.go | 55 ++++ .../model/externalapi/acceptancedata.go | 32 +- .../calculate_past_utxo.go | 15 +- .../resolve_block_status_test.go | 52 +-- domain/utxoindex/utxoindex.go | 24 +- 8 files changed, 325 insertions(+), 183 deletions(-) diff --git a/domain/consensus/database/serialization/acceptancedata.go b/domain/consensus/database/serialization/acceptancedata.go index 40f38f7c9..89e2a028e 100644 --- a/domain/consensus/database/serialization/acceptancedata.go +++ b/domain/consensus/database/serialization/acceptancedata.go @@ -13,10 +13,17 @@ func DomainAcceptanceDataToDbAcceptanceData(domainAcceptanceData externalapi.Acc for j, transactionAcceptanceData := range blockAcceptanceData.TransactionAcceptanceData { dbTransaction := DomainTransactionToDbTransaction(transactionAcceptanceData.Transaction) + + dbTransactionInputUTXOEntries := make([]*DbUtxoEntry, len(transactionAcceptanceData.TransactionInputUTXOEntries)) + for k, transactionInputUTXOEntry := range transactionAcceptanceData.TransactionInputUTXOEntries { + dbTransactionInputUTXOEntries[k] = UTXOEntryToDBUTXOEntry(transactionInputUTXOEntry) + } + dbTransactionAcceptanceData[j] = &DbTransactionAcceptanceData{ - Transaction: dbTransaction, - Fee: transactionAcceptanceData.Fee, - IsAccepted: transactionAcceptanceData.IsAccepted, + Transaction: dbTransaction, + Fee: transactionAcceptanceData.Fee, + IsAccepted: transactionAcceptanceData.IsAccepted, + TransactionInputUtxoEntries: dbTransactionInputUTXOEntries, } } @@ -45,10 +52,23 @@ func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) if err != nil { return nil, err } + + domainTransactionInputUTXOEntries := make([]externalapi.UTXOEntry, len(dbTransactionAcceptanceData.TransactionInputUtxoEntries)) + for k, transactionInputUTXOEntry := range dbTransactionAcceptanceData.TransactionInputUtxoEntries { + domainTransactionInputUTXOEntry := DBUTXOEntryToUTXOEntry(transactionInputUTXOEntry) + domainTransactionInputUTXOEntries[k] = domainTransactionInputUTXOEntry + + // For consistency's sake, we fill up the transaction input's + // UTXOEntry field as well, since that's how the acceptanceData + // must have arrived when it was originally serialized + domainTransaction.Inputs[k].UTXOEntry = domainTransactionInputUTXOEntry + } + domainTransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{ - Transaction: domainTransaction, - Fee: dbTransactionAcceptanceData.Fee, - IsAccepted: dbTransactionAcceptanceData.IsAccepted, + Transaction: domainTransaction, + Fee: dbTransactionAcceptanceData.Fee, + IsAccepted: dbTransactionAcceptanceData.IsAccepted, + TransactionInputUTXOEntries: domainTransactionInputUTXOEntries, } } diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index cd8a0912a..f1e1fcaa0 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -707,9 +707,10 @@ type DbTransactionAcceptanceData struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Transaction *DbTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` - Fee uint64 `protobuf:"varint,2,opt,name=fee,proto3" json:"fee,omitempty"` - IsAccepted bool `protobuf:"varint,3,opt,name=isAccepted,proto3" json:"isAccepted,omitempty"` + Transaction *DbTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` + Fee uint64 `protobuf:"varint,2,opt,name=fee,proto3" json:"fee,omitempty"` + IsAccepted bool `protobuf:"varint,3,opt,name=isAccepted,proto3" json:"isAccepted,omitempty"` + TransactionInputUtxoEntries []*DbUtxoEntry `protobuf:"bytes,4,rep,name=transactionInputUtxoEntries,proto3" json:"transactionInputUtxoEntries,omitempty"` } func (x *DbTransactionAcceptanceData) Reset() { @@ -765,6 +766,13 @@ func (x *DbTransactionAcceptanceData) GetIsAccepted() bool { return false } +func (x *DbTransactionAcceptanceData) GetTransactionInputUtxoEntries() []*DbUtxoEntry { + if x != nil { + return x.TransactionInputUtxoEntries + } + return nil +} + type DbBlockRelations struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1801,7 +1809,7 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x8f, + 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0xed, 0x01, 0x0a, 0x1b, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, @@ -1811,124 +1819,130 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, - 0x22, 0x76, 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, - 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x22, 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, - 0x73, 0x74, 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, - 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, - 0x6f, 0x72, 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x12, 0x5c, 0x0a, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x76, + 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, 0x73, 0x74, + 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, + 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, + 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, - 0x39, 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, - 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, - 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, - 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, - 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, - 0x6d, 0x0a, 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, - 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, - 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, - 0x0a, 0x0a, 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, - 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, + 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0d, + 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a, + 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, + 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, 0x75, 0x65, + 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x22, 0x87, 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x38, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, - 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, - 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, - 0x62, 0x61, 0x73, 0x65, 0x22, 0xfe, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, - 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, - 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, - 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, - 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x12, 0x43, 0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x53, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, + 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, + 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, 0x6d, 0x0a, + 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, + 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, + 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, 0x74, 0x69, + 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, + 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, 0x0a, 0x0a, + 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, + 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x87, + 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, + 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, + 0x73, 0x65, 0x22, 0xfe, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, - 0x6e, 0x67, 0x53, 0x65, 0x74, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, - 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, - 0x78, 0x6f, 0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, - 0x64, 0x12, 0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, + 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, + 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x43, + 0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x74, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, + 0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, - 0x73, 0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, - 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, - 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, - 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, + 0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x22, 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, + 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, + 0x74, 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, + 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1992,30 +2006,31 @@ var file_dbobjects_proto_depIdxs = []int32{ 11, // 13: serialization.DbBlockAcceptanceData.transactionAcceptanceData:type_name -> serialization.DbTransactionAcceptanceData 2, // 14: serialization.DbBlockAcceptanceData.blockHash:type_name -> serialization.DbHash 3, // 15: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction - 2, // 16: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash - 2, // 17: serialization.DbBlockRelations.children:type_name -> serialization.DbHash - 2, // 18: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash - 2, // 19: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash - 2, // 20: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash - 15, // 21: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes - 2, // 22: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash - 18, // 23: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem - 5, // 24: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint - 19, // 25: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry - 2, // 26: serialization.DbReachabilityData.children:type_name -> serialization.DbHash - 2, // 27: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash - 21, // 28: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval - 2, // 29: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash - 18, // 30: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem - 18, // 31: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem - 2, // 32: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash - 2, // 33: serialization.DbTips.tips:type_name -> serialization.DbHash - 2, // 34: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash - 35, // [35:35] is the sub-list for method output_type - 35, // [35:35] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 19, // 16: serialization.DbTransactionAcceptanceData.transactionInputUtxoEntries:type_name -> serialization.DbUtxoEntry + 2, // 17: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash + 2, // 18: serialization.DbBlockRelations.children:type_name -> serialization.DbHash + 2, // 19: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash + 2, // 20: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash + 2, // 21: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash + 15, // 22: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes + 2, // 23: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash + 18, // 24: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem + 5, // 25: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint + 19, // 26: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry + 2, // 27: serialization.DbReachabilityData.children:type_name -> serialization.DbHash + 2, // 28: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash + 21, // 29: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval + 2, // 30: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash + 18, // 31: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem + 18, // 32: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem + 2, // 33: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash + 2, // 34: serialization.DbTips.tips:type_name -> serialization.DbHash + 2, // 35: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash + 36, // [36:36] is the sub-list for method output_type + 36, // [36:36] is the sub-list for method input_type + 36, // [36:36] is the sub-list for extension type_name + 36, // [36:36] is the sub-list for extension extendee + 0, // [0:36] is the sub-list for field type_name } func init() { file_dbobjects_proto_init() } diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 36f31a658..ddb972404 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -71,6 +71,7 @@ message DbTransactionAcceptanceData { DbTransaction transaction = 1; uint64 fee = 2; bool isAccepted = 3; + repeated DbUtxoEntry transactionInputUtxoEntries = 4; } message DbBlockRelations { diff --git a/domain/consensus/model/acceptancedata_equal_clone_test.go b/domain/consensus/model/acceptancedata_equal_clone_test.go index b3d7936f2..1e96b37e6 100644 --- a/domain/consensus/model/acceptancedata_equal_clone_test.go +++ b/domain/consensus/model/acceptancedata_equal_clone_test.go @@ -42,6 +42,7 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }, } return tests @@ -90,6 +91,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, } var testTransactionAcceptanceData1 = externalapi.TransactionAcceptanceData{ @@ -122,6 +124,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, } // test 2: different transactions var testTransactionAcceptanceData2 = externalapi.TransactionAcceptanceData{ @@ -154,6 +157,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, } //test 3: different Fee var testTransactionAcceptanceData3 = externalapi.TransactionAcceptanceData{ @@ -187,6 +191,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 2, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, } //test 4: different isAccepted var testTransactionAcceptanceData4 = externalapi.TransactionAcceptanceData{ @@ -220,6 +225,42 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, false, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + } + + //test 5: different TransactionInputUTXOEntries + var testTransactionAcceptanceData5 = externalapi.TransactionAcceptanceData{ + &externalapi.DomainTransaction{ + Version: 1, + Inputs: []*externalapi.DomainTransactionInput{{externalapi.DomainOutpoint{ + *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, + []byte{1, 2, 3}, + uint64(0xFFFFFFFF), + utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + []byte{1, 2}}, + {uint64(0xFFFF), + []byte{1, 3}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), + }, + 1, + false, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 4, 3}, true, 2)}, } tests := []testTransactionAcceptanceDataStruct{ @@ -238,6 +279,9 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, { transactionAcceptanceData: &testTransactionAcceptanceData4, expectedResult: false, + }, { + transactionAcceptanceData: &testTransactionAcceptanceData5, + expectedResult: false, }, { transactionAcceptanceData: nil, expectedResult: false, @@ -326,6 +370,7 @@ func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}, }, } @@ -377,6 +422,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}} //test 1: structs are equal var testBlockAcceptanceData1 = externalapi.BlockAcceptanceData{ @@ -413,6 +459,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}} // test 2: different size var testBlockAcceptanceData2 = externalapi.BlockAcceptanceData{ @@ -449,6 +496,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }, {}}} //test 3: different transactions, same size var testBlockAcceptanceData3 = externalapi.BlockAcceptanceData{ @@ -485,6 +533,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, false, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}} // test 4 - different block hash @@ -522,6 +571,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}} tests := []testBlockAcceptanceDataStruct{ @@ -629,6 +679,7 @@ func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}, }, } @@ -682,6 +733,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}}} //test 1: structs are equal var testAcceptanceData1 = []*externalapi.BlockAcceptanceData{ @@ -718,6 +770,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}}} // test 2: different size var testAcceptanceData2 = []*externalapi.BlockAcceptanceData{ @@ -754,6 +807,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}}, {}} //test 3: different transactions, same size var testAcceptanceData3 = []*externalapi.BlockAcceptanceData{ @@ -790,6 +844,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, }}}} tests := []testAcceptanceDataStruct{ diff --git a/domain/consensus/model/externalapi/acceptancedata.go b/domain/consensus/model/externalapi/acceptancedata.go index 1cb4ae965..4b85741fc 100644 --- a/domain/consensus/model/externalapi/acceptancedata.go +++ b/domain/consensus/model/externalapi/acceptancedata.go @@ -87,14 +87,15 @@ func (bad *BlockAcceptanceData) Clone() *BlockAcceptanceData { // TransactionAcceptanceData stores a transaction together with an indication // if it was accepted or not by some block type TransactionAcceptanceData struct { - Transaction *DomainTransaction - Fee uint64 - IsAccepted bool + Transaction *DomainTransaction + Fee uint64 + IsAccepted bool + TransactionInputUTXOEntries []UTXOEntry } // If this doesn't compile, it means the type definition has been changed, so it's // an indication to update Equal and Clone accordingly. -var _ = &TransactionAcceptanceData{&DomainTransaction{}, 0, false} +var _ = &TransactionAcceptanceData{&DomainTransaction{}, 0, false, []UTXOEntry{}} // Equal returns whether tad equals to other func (tad *TransactionAcceptanceData) Equal(other *TransactionAcceptanceData) bool { @@ -114,14 +115,31 @@ func (tad *TransactionAcceptanceData) Equal(other *TransactionAcceptanceData) bo return false } + if len(tad.TransactionInputUTXOEntries) != len(other.TransactionInputUTXOEntries) { + return false + } + + for i, thisUTXOEntry := range tad.TransactionInputUTXOEntries { + otherUTXOEntry := other.TransactionInputUTXOEntries[i] + if !thisUTXOEntry.Equal(otherUTXOEntry) { + return false + } + } + return true } // Clone returns a clone of TransactionAcceptanceData func (tad *TransactionAcceptanceData) Clone() *TransactionAcceptanceData { + cloneTransactionInputUTXOEntries := make([]UTXOEntry, len(tad.TransactionInputUTXOEntries)) + for i, utxoEntry := range tad.TransactionInputUTXOEntries { + cloneTransactionInputUTXOEntries[i] = utxoEntry + } + return &TransactionAcceptanceData{ - Transaction: tad.Transaction.Clone(), - Fee: tad.Fee, - IsAccepted: tad.IsAccepted, + Transaction: tad.Transaction.Clone(), + Fee: tad.Fee, + IsAccepted: tad.IsAccepted, + TransactionInputUTXOEntries: cloneTransactionInputUTXOEntries, } } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index b62d10c96..711afe6ba 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -155,10 +155,19 @@ func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.Dom log.Tracef("Transaction %s in block %s isAccepted: %t, fee: %d", transactionID, mergeSetBlockHash, isAccepted, transaction.Fee) + var transactionInputUTXOEntries []externalapi.UTXOEntry + if isAccepted { + transactionInputUTXOEntries = make([]externalapi.UTXOEntry, len(transaction.Inputs)) + for k, input := range transaction.Inputs { + transactionInputUTXOEntries[k] = input.UTXOEntry + } + } + blockAcceptanceData.TransactionAcceptanceData[j] = &externalapi.TransactionAcceptanceData{ - Transaction: transaction, - Fee: transaction.Fee, - IsAccepted: isAccepted, + Transaction: transaction, + Fee: transaction.Fee, + IsAccepted: isAccepted, + TransactionInputUTXOEntries: transactionInputUTXOEntries, } } multiblockAcceptanceData[i] = blockAcceptanceData diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 9b5511fd5..02d749075 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -212,11 +212,21 @@ func TestTransactionAcceptance(t *testing.T) { if err != nil { t.Fatalf("Error creating spendingTransaction1: %+v", err) } + spendingTransaction1UTXOEntry, err := testConsensus.ConsensusStateStore(). + UTXOByOutpoint(testConsensus.DatabaseContext(), &spendingTransaction1.Inputs[0].PreviousOutpoint) + if err != nil { + t.Fatalf("Error getting UTXOEntry for spendingTransaction1: %s", err) + } spendingTransaction2, err := testutils.CreateTransaction(fundingTransaction2) if err != nil { t.Fatalf("Error creating spendingTransaction1: %+v", err) } + spendingTransaction2UTXOEntry, err := testConsensus.ConsensusStateStore(). + UTXOByOutpoint(testConsensus.DatabaseContext(), &spendingTransaction2.Inputs[0].PreviousOutpoint) + if err != nil { + t.Fatalf("Error getting UTXOEntry for spendingTransaction2: %s", err) + } redHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{fundingBlock3Hash}, nil, []*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2}) @@ -284,9 +294,10 @@ func TestTransactionAcceptance(t *testing.T) { BlockHash: finalTipSelectedParentHash, TransactionAcceptanceData: []*externalapi.TransactionAcceptanceData{ { - Transaction: finalTipSelectedParent.Transactions[0], - Fee: 0, - IsAccepted: true, + Transaction: finalTipSelectedParent.Transactions[0], + Fee: 0, + IsAccepted: true, + TransactionInputUTXOEntries: []externalapi.UTXOEntry{}, }, }, }, @@ -294,14 +305,16 @@ func TestTransactionAcceptance(t *testing.T) { BlockHash: blueHash, TransactionAcceptanceData: []*externalapi.TransactionAcceptanceData{ { - Transaction: blue.Transactions[0], - Fee: 0, - IsAccepted: false, + Transaction: blue.Transactions[0], + Fee: 0, + IsAccepted: false, + TransactionInputUTXOEntries: []externalapi.UTXOEntry{}, }, { - Transaction: spendingTransaction1, - Fee: 1, - IsAccepted: true, + Transaction: spendingTransaction1, + Fee: 1, + IsAccepted: true, + TransactionInputUTXOEntries: []externalapi.UTXOEntry{spendingTransaction1UTXOEntry}, }, }, }, @@ -309,19 +322,22 @@ func TestTransactionAcceptance(t *testing.T) { BlockHash: redHash, TransactionAcceptanceData: []*externalapi.TransactionAcceptanceData{ { - Transaction: red.Transactions[0], - Fee: 0, - IsAccepted: false, + Transaction: red.Transactions[0], + Fee: 0, + IsAccepted: false, + TransactionInputUTXOEntries: []externalapi.UTXOEntry{}, }, { - Transaction: spendingTransaction1, - Fee: 0, - IsAccepted: false, + Transaction: spendingTransaction1, + Fee: 0, + IsAccepted: false, + TransactionInputUTXOEntries: []externalapi.UTXOEntry{}, }, { - Transaction: spendingTransaction2, - Fee: 1, - IsAccepted: true, + Transaction: spendingTransaction2, + Fee: 1, + IsAccepted: true, + TransactionInputUTXOEntries: []externalapi.UTXOEntry{spendingTransaction2UTXOEntry}, }, }, }, diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go index defa4a6bb..e4292e567 100644 --- a/domain/utxoindex/utxoindex.go +++ b/domain/utxoindex/utxoindex.go @@ -80,7 +80,8 @@ func (ui *UTXOIndex) addBlock(blockHash *externalapi.DomainHash) error { if !transactionAcceptanceData.IsAccepted { continue } - err := ui.addTransaction(transactionAcceptanceData.Transaction, blockInfo.BlueScore) + err := ui.addTransaction(transactionAcceptanceData.Transaction, + transactionAcceptanceData.TransactionInputUTXOEntries, blockInfo.BlueScore) if err != nil { return err } @@ -100,7 +101,8 @@ func (ui *UTXOIndex) removeBlock(blockHash *externalapi.DomainHash) error { if !transactionAcceptanceData.IsAccepted { continue } - err := ui.removeTransaction(transactionAcceptanceData.Transaction) + err := ui.removeTransaction(transactionAcceptanceData.Transaction, + transactionAcceptanceData.TransactionInputUTXOEntries) if err != nil { return err } @@ -109,15 +111,18 @@ func (ui *UTXOIndex) removeBlock(blockHash *externalapi.DomainHash) error { return nil } -func (ui *UTXOIndex) addTransaction(transaction *externalapi.DomainTransaction, blockBlueScore uint64) error { +func (ui *UTXOIndex) addTransaction(transaction *externalapi.DomainTransaction, + transactionInputUTXOEntries []externalapi.UTXOEntry, blockBlueScore uint64) error { + transactionID := consensushashing.TransactionID(transaction) log.Tracef("Adding transaction %s to UTXO index", transactionID) isCoinbase := transactionhelper.IsCoinBase(transaction) - for _, transactionInput := range transaction.Inputs { + for i, transactionInput := range transaction.Inputs { log.Tracef("Removing outpoint %s:%d from UTXO index", transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) - err := ui.store.remove(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint) + inputUTXOEntry := transactionInputUTXOEntries[i] + err := ui.store.remove(inputUTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint) if err != nil { return err } @@ -134,7 +139,9 @@ func (ui *UTXOIndex) addTransaction(transaction *externalapi.DomainTransaction, return nil } -func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransaction) error { +func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransaction, + transactionInputUTXOEntries []externalapi.UTXOEntry) error { + transactionID := consensushashing.TransactionID(transaction) log.Tracef("Removing transaction %s from UTXO index", transactionID) for index, transactionOutput := range transaction.Outputs { @@ -145,10 +152,11 @@ func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransactio return err } } - for _, transactionInput := range transaction.Inputs { + for i, transactionInput := range transaction.Inputs { log.Tracef("Adding outpoint %s:%d to UTXO index", transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index) - err := ui.store.add(transactionInput.UTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint, transactionInput.UTXOEntry) + inputUTXOEntry := transactionInputUTXOEntries[i] + err := ui.store.add(inputUTXOEntry.ScriptPublicKey(), &transactionInput.PreviousOutpoint, transactionInput.UTXOEntry) if err != nil { return err } From 23304a4977b9552267c592d5e2d53433ac38b334 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 31 Dec 2020 16:34:46 +0200 Subject: [PATCH 193/351] Add UTXO set cache (#1333) * Add UTXO set cache * Add clear method to cache --- .../consensusstatestore.go | 9 ++- .../consensusstatestore/utxo.go | 21 +++++- domain/consensus/factory.go | 2 +- .../utils/utxolrucache/utxolrucache.go | 71 +++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 domain/consensus/utils/utxolrucache/utxolrucache.go diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go index b3a37a789..cc2d14b82 100644 --- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go +++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go @@ -3,6 +3,7 @@ package consensusstatestore import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxolrucache" ) // consensusStateStore represents a store for the current consensus state @@ -12,13 +13,17 @@ type consensusStateStore struct { virtualUTXODiffStaging model.UTXODiff virtualUTXOSetStaging model.UTXOCollection + virtualUTXOSetCache *utxolrucache.LRUCache + tipsCache []*externalapi.DomainHash virtualDiffParentsCache []*externalapi.DomainHash } // New instantiates a new ConsensusStateStore -func New() model.ConsensusStateStore { - return &consensusStateStore{} +func New(utxoSetCacheSize int) model.ConsensusStateStore { + return &consensusStateStore{ + virtualUTXOSetCache: utxolrucache.New(utxoSetCacheSize), + } } func (css *consensusStateStore) Discard() { diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index 6bc76113a..5959bfb1a 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -39,6 +39,9 @@ func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) if err != nil { return err } + + css.virtualUTXOSetCache.Remove(toRemoveOutpoint) + dbKey, err := utxoKey(toRemoveOutpoint) if err != nil { return err @@ -55,6 +58,9 @@ func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) if err != nil { return err } + + css.virtualUTXOSetCache.Add(toAddOutpoint, toAddEntry) + dbKey, err := utxoKey(toAddOutpoint) if err != nil { return err @@ -79,12 +85,15 @@ func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) e return nil } + css.virtualUTXOSetCache.Clear() iterator := css.virtualUTXOSetStaging.Iterator() for iterator.Next() { outpoint, utxoEntry, err := iterator.Get() if err != nil { return err } + + css.virtualUTXOSetCache.Add(outpoint, utxoEntry) dbKey, err := utxoKey(outpoint) if err != nil { return err @@ -127,6 +136,10 @@ func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContex } } + if entry, ok := css.virtualUTXOSetCache.Get(outpoint); ok { + return entry, nil + } + key, err := utxoKey(outpoint) if err != nil { return nil, err @@ -137,7 +150,13 @@ func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContex return nil, err } - return deserializeUTXOEntry(serializedUTXOEntry) + entry, err := deserializeUTXOEntry(serializedUTXOEntry) + if err != nil { + return nil, err + } + + css.virtualUTXOSetCache.Add(outpoint, entry) + return entry, nil } func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 27828c460..37bef61f5 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -82,7 +82,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat pruningStore := pruningstore.New() reachabilityDataStore := reachabilitydatastore.New(pruningWindowSizeForCaches) utxoDiffStore := utxodiffstore.New(200) - consensusStateStore := consensusstatestore.New() + consensusStateStore := consensusstatestore.New(10_000) ghostdagDataStore := ghostdagdatastore.New(pruningWindowSizeForCaches) headersSelectedTipStore := headersselectedtipstore.New() finalityStore := finalitystore.New(200) diff --git a/domain/consensus/utils/utxolrucache/utxolrucache.go b/domain/consensus/utils/utxolrucache/utxolrucache.go new file mode 100644 index 000000000..70a9e879b --- /dev/null +++ b/domain/consensus/utils/utxolrucache/utxolrucache.go @@ -0,0 +1,71 @@ +package utxolrucache + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// LRUCache is a least-recently-used cache for UTXO entries +// indexed by DomainOutpoint +type LRUCache struct { + cache map[externalapi.DomainOutpoint]externalapi.UTXOEntry + capacity int +} + +// New creates a new LRUCache +func New(capacity int) *LRUCache { + return &LRUCache{ + cache: make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, capacity+1), + capacity: capacity, + } +} + +// Add adds an entry to the LRUCache +func (c *LRUCache) Add(key *externalapi.DomainOutpoint, value externalapi.UTXOEntry) { + c.cache[*key] = value + + if len(c.cache) > c.capacity { + c.evictRandom() + } +} + +// Get returns the entry for the given key, or (nil, false) otherwise +func (c *LRUCache) Get(key *externalapi.DomainOutpoint) (externalapi.UTXOEntry, bool) { + value, ok := c.cache[*key] + if !ok { + return nil, false + } + return value, true +} + +// Has returns whether the LRUCache contains the given key +func (c *LRUCache) Has(key *externalapi.DomainOutpoint) bool { + _, ok := c.cache[*key] + return ok +} + +// Remove removes the entry for the the given key. Does nothing if +// the entry does not exist +func (c *LRUCache) Remove(key *externalapi.DomainOutpoint) { + delete(c.cache, *key) +} + +// Clear clears the cache +func (c *LRUCache) Clear() { + keys := make([]externalapi.DomainOutpoint, len(c.cache)) + for outpoint := range c.cache { + keys = append(keys, outpoint) + } + + for _, key := range keys { + delete(c.cache, key) + } +} + +func (c *LRUCache) evictRandom() { + var keyToEvict externalapi.DomainOutpoint + for key := range c.cache { + keyToEvict = key + break + } + c.Remove(&keyToEvict) +} From 6fa3aa1dca37b07de6fd05c33eb1d6ae9a1b1ed4 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 31 Dec 2020 16:45:56 +0200 Subject: [PATCH 194/351] Change SyncRateWindow to 15 minutes + update sync times on block headers as well (#1331) * Change SyncRateWindow to 15 minutes + update sync times on block headers as well * Rename result to isSyncRateTooLow * Fix formula for expected blocks --- app/protocol/flowcontext/blocks.go | 2 +- app/protocol/flowcontext/orphans.go | 2 +- app/protocol/flowcontext/sync_rate.go | 15 ++++++++++++--- .../flows/blockrelay/handle_relay_invs.go | 1 + app/protocol/flows/blockrelay/ibd.go | 6 +++++- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 1ab87e81e..96965d24f 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -24,7 +24,7 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, log.Debugf("OnNewBlock start for block %s", hash) defer log.Debugf("OnNewBlock end for block %s", hash) - f.updateRecentBlockAddedTimesWithLastBlock() + f.UpdateRecentBlockAddedTimesWithLastBlock() unorphaningResults, err := f.UnorphanBlocks(block) if err != nil { return err diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index f655c4bcf..d7a17ab58 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -156,7 +156,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa } return nil, false, err } - f.updateRecentBlockAddedTimesWithLastBlock() + f.UpdateRecentBlockAddedTimesWithLastBlock() log.Infof("Unorphaned block %s", orphanHash) return blockInsertionResult, true, nil diff --git a/app/protocol/flowcontext/sync_rate.go b/app/protocol/flowcontext/sync_rate.go index b7c0f2d2d..fedbc27ed 100644 --- a/app/protocol/flowcontext/sync_rate.go +++ b/app/protocol/flowcontext/sync_rate.go @@ -3,12 +3,14 @@ package flowcontext import "github.com/kaspanet/kaspad/util/mstime" const ( - syncRateWindowInMilliSeconds = 60_000 + syncRateWindowInMilliSeconds = 15 * 60 * 1000 syncRateMaxDeviation = 0.05 maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 300_000 ) -func (f *FlowContext) updateRecentBlockAddedTimesWithLastBlock() { +// UpdateRecentBlockAddedTimesWithLastBlock adds current time to list of times when block was added. +// We use this list to determine the current sync rate +func (f *FlowContext) UpdateRecentBlockAddedTimesWithLastBlock() { f.recentBlockAddedTimesMutex.Lock() defer f.recentBlockAddedTimesMutex.Unlock() @@ -44,7 +46,14 @@ func (f *FlowContext) isSyncRateBelowMinimum() bool { } expectedBlocks := float64(syncRateWindowInMilliSeconds) / float64(f.cfg.NetParams().TargetTimePerBlock.Milliseconds()) - return 1-float64(len(f.recentBlockAddedTimes))/expectedBlocks > syncRateMaxDeviation + isSyncRateTooLow := 1-float64(len(f.recentBlockAddedTimes))/expectedBlocks > syncRateMaxDeviation + + if isSyncRateTooLow { + log.Debugf("In the last %d seconds, got %d blocks, while at least %f were expected.", + syncRateWindowInMilliSeconds/1000, len(f.recentBlockAddedTimes), expectedBlocks*(1-syncRateMaxDeviation)) + } + + return isSyncRateTooLow } // ShouldMine returns whether it's ok to use block template from this node diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 8b91c5788..f4a81a52f 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -33,6 +33,7 @@ type RelayInvsContext interface { IsIBDRunning() bool TrySetIBDRunning() bool UnsetIBDRunning() + UpdateRecentBlockAddedTimesWithLastBlock() } type handleRelayInvsFlow struct { diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 9d70cc3cb..0e266d0ed 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -1,6 +1,8 @@ package blockrelay import ( + "time" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/common" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" @@ -8,7 +10,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/pkg/errors" - "time" ) func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.DomainHash) error { @@ -257,6 +258,9 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) } + + flow.UpdateRecentBlockAddedTimesWithLastBlock() + return nil } From 51625e79670200de450136f095af79965f452d63 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 31 Dec 2020 17:58:01 +0200 Subject: [PATCH 195/351] Remove LevelDBSnapshot from LevelDBTransaction (#1334) * Remove leveldb snapshot from LevelDBTransaction * Update transactions_test.go to represent the new Transaction logic --- infrastructure/db/database/ldb/transaction.go | 37 +++---------------- .../db/database/transaction_test.go | 25 ++++++------- 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/infrastructure/db/database/ldb/transaction.go b/infrastructure/db/database/ldb/transaction.go index 5271ed717..095bc37fc 100644 --- a/infrastructure/db/database/ldb/transaction.go +++ b/infrastructure/db/database/ldb/transaction.go @@ -8,37 +8,25 @@ import ( ) // LevelDBTransaction is a thin wrapper around native leveldb -// batches and snapshots. It supports both get and put. +// batches. It supports both get and put. // -// Snapshots provide a frozen view of the database at the moment -// the transaction begins. On the other hand, batches provide a -// mechanism to combine several database writes into one write, -// which seamlessly rolls back the database in case any individual -// write fails. Together the two forms a logic unit similar -// to what one might expect from a classic database transaction. +// Note that reads are done from the Database directly, so if another transaction changed the data, +// you will read the new data, and not the one from the time the transaction was opened/ // -// Note: Transactions provide data consistency over the state of -// the database as it was when the transaction started. As it's -// currently implemented, if one puts data into the transaction +// Note: As it's currently implemented, if one puts data into the transaction // then it will not be available to get within the same transaction. type LevelDBTransaction struct { db *LevelDB - snapshot *leveldb.Snapshot batch *leveldb.Batch isClosed bool } // Begin begins a new transaction. func (db *LevelDB) Begin() (database.Transaction, error) { - snapshot, err := db.ldb.GetSnapshot() - if err != nil { - return nil, errors.WithStack(err) - } batch := new(leveldb.Batch) transaction := &LevelDBTransaction{ db: db, - snapshot: snapshot, batch: batch, isClosed: false, } @@ -53,7 +41,6 @@ func (tx *LevelDBTransaction) Commit() error { } tx.isClosed = true - tx.snapshot.Release() return errors.WithStack(tx.db.ldb.Write(tx.batch, &opt.WriteOptions{Sync: true})) } @@ -65,7 +52,6 @@ func (tx *LevelDBTransaction) Rollback() error { } tx.isClosed = true - tx.snapshot.Release() tx.batch.Reset() return nil } @@ -97,16 +83,7 @@ func (tx *LevelDBTransaction) Get(key *database.Key) ([]byte, error) { if tx.isClosed { return nil, errors.New("cannot get from a closed transaction") } - - data, err := tx.snapshot.Get(key.Bytes(), nil) - if err != nil { - if errors.Is(err, leveldb.ErrNotFound) { - return nil, errors.Wrapf(database.ErrNotFound, - "key %s not found", key) - } - return nil, errors.WithStack(err) - } - return data, nil + return tx.db.Get(key) } // Has returns true if the database does contains the @@ -115,9 +92,7 @@ func (tx *LevelDBTransaction) Has(key *database.Key) (bool, error) { if tx.isClosed { return false, errors.New("cannot has from a closed transaction") } - - res, err := tx.snapshot.Has(key.Bytes(), nil) - return res, errors.WithStack(err) + return tx.db.Has(key) } // Delete deletes the value for the given key. Will not diff --git a/infrastructure/db/database/transaction_test.go b/infrastructure/db/database/transaction_test.go index cfb5247c1..eda5b137e 100644 --- a/infrastructure/db/database/transaction_test.go +++ b/infrastructure/db/database/transaction_test.go @@ -130,15 +130,14 @@ func testTransactionGet(t *testing.T, db database.Database, testName string) { "unexpectedly failed: %s", testName, err) } - // Make sure that the new value doesn't exist inside the transaction - _, err = dbTx.Get(key2) - if err == nil { + // Make sure that the new value exists inside the transaction + newValue2, err := dbTx.Get(key2) + if err != nil { t.Fatalf("%s: Get "+ - "unexpectedly succeeded", testName) + "unexpectedly failed: %v", testName, err) } - if !database.IsNotFoundError(err) { - t.Fatalf("%s: Get "+ - "returned wrong error: %s", testName, err) + if !bytes.Equal(value2, newValue2) { + t.Fatalf("Expected %x and %x to be the same", value2, newValue2) } // Put a new value into the transaction @@ -221,15 +220,15 @@ func testTransactionHas(t *testing.T, db database.Database, testName string) { "unexpectedly failed: %s", testName, err) } - // Make sure that the new value doesn't exist inside the transaction + // Make sure that the new value exists inside the transaction exists, err = dbTx.Has(key2) if err != nil { t.Fatalf("%s: Has "+ "unexpectedly failed: %s", testName, err) } - if exists { + if !exists { t.Fatalf("%s: Has "+ - "unexpectedly returned that the value exists", testName) + "unexpectedly returned that the value doesn't exists", testName) } } @@ -296,15 +295,15 @@ func testTransactionDelete(t *testing.T, db database.Database, testName string) "unexpectedly returned that the value exists", testName) } - // Make sure that the second transaction was no affected + // Make sure that the second transaction is also affected exists, err = dbTx2.Has(key) if err != nil { t.Fatalf("%s: Has "+ "unexpectedly failed: %s", testName, err) } - if !exists { + if exists { t.Fatalf("%s: Has "+ - "unexpectedly returned that the value does not exist", testName) + "unexpectedly returned that the value exists", testName) } } From 8c8da3b01f4ce7d9d2b5ba164158dafafb3ab039 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 3 Jan 2021 10:20:37 +0200 Subject: [PATCH 196/351] Convert all log messages in pick_virtual_parents.go to Debugf (#1335) --- .../pick_virtual_parents.go | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 7779e3056..dbb947dad 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -95,24 +95,24 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( } selectedParentCandidate := candidatesHeap.Pop() - log.Tracef("Checking block %s for selected parent eligibility", selectedParentCandidate) + log.Debugf("Checking block %s for selected parent eligibility", selectedParentCandidate) selectedParentCandidateStatus, err := csm.blockStatusStore.Get(csm.databaseContext, selectedParentCandidate) if err != nil { return nil, err } if selectedParentCandidateStatus == externalapi.StatusUTXOValid { - log.Tracef("Block %s is valid. Returning it as the selected parent", selectedParentCandidate) + log.Debugf("Block %s is valid. Returning it as the selected parent", selectedParentCandidate) return selectedParentCandidate, nil } - log.Tracef("Block %s is not valid. Adding it to the disqualified set", selectedParentCandidate) + log.Debugf("Block %s is not valid. Adding it to the disqualified set", selectedParentCandidate) disqualifiedCandidates.Add(selectedParentCandidate) candidateParents, err := csm.dagTopologyManager.Parents(selectedParentCandidate) if err != nil { return nil, err } - log.Tracef("The parents of block %s are: %s", selectedParentCandidate, candidateParents) + log.Debugf("The parents of block %s are: %s", selectedParentCandidate, candidateParents) for _, parent := range candidateParents { parentChildren, err := csm.dagTopologyManager.Children(parent) if err != nil { @@ -126,10 +126,10 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( break } } - log.Tracef("The children of block %s are: %s", parent, parentChildren) + log.Debugf("The children of block %s are: %s", parent, parentChildren) if disqualifiedCandidates.ContainsAllInSlice(parentChildren) { - log.Tracef("The disqualified set contains all the "+ + log.Debugf("The disqualified set contains all the "+ "children of %s. Adding it to the candidate heap", parentChildren) err := candidatesHeap.Push(parent) if err != nil { @@ -156,7 +156,7 @@ func (csm *consensusStateManager) mergeSetIncrease( for queue.Len() > 0 { current := queue.Pop() - log.Tracef("Attempting to increment the merge set size increase for block %s", current) + log.Debugf("Attempting to increment the merge set size increase for block %s", current) isInPastOfSelectedVirtualParents, err := csm.dagTopologyManager.IsAncestorOfAny( current, selectedVirtualParents.ToSlice()) @@ -164,7 +164,7 @@ func (csm *consensusStateManager) mergeSetIncrease( return 0, err } if isInPastOfSelectedVirtualParents { - log.Tracef("Skipping block %s because it's in the past of one "+ + log.Debugf("Skipping block %s because it's in the past of one "+ "(or more) of the selected virtual parents", current) continue } @@ -186,7 +186,7 @@ func (csm *consensusStateManager) mergeSetIncrease( } } } - log.Tracef("The resolved merge set size increase is: %d", mergeSetIncrease) + log.Debugf("The resolved merge set size increase is: %d", mergeSetIncrease) return mergeSetIncrease, nil } @@ -197,7 +197,7 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( log.Tracef("boundedMergeBreakingParents start for parents: %s", parents) defer log.Tracef("boundedMergeBreakingParents end for parents: %s", parents) - log.Tracef("Temporarily setting virtual to all parents, so that we can run ghostdag on it") + log.Debug("Temporarily setting virtual to all parents, so that we can run ghostdag on it") err := csm.dagTopologyManager.SetParents(model.VirtualBlockHash, parents) if err != nil { return nil, err @@ -212,13 +212,13 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( if err != nil { return nil, err } - log.Tracef("The potentially kosherizing blocks are: %s", potentiallyKosherizingBlocks) + log.Debugf("The potentially kosherizing blocks are: %s", potentiallyKosherizingBlocks) virtualFinalityPoint, err := csm.finalityManager.VirtualFinalityPoint() if err != nil { return nil, err } - log.Tracef("The finality point of the virtual is: %s", virtualFinalityPoint) + log.Debugf("The finality point of the virtual is: %s", virtualFinalityPoint) var badReds []*externalapi.DomainHash @@ -227,13 +227,13 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( return nil, err } for _, redBlock := range virtualGHOSTDAGData.MergeSetReds() { - log.Tracef("Check whether red block %s is kosherized", redBlock) + log.Debugf("Check whether red block %s is kosherized", redBlock) isFinalityPointInPast, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, redBlock) if err != nil { return nil, err } if isFinalityPointInPast { - log.Tracef("Skipping red block %s because it has the virtual's"+ + log.Debugf("Skipping red block %s because it has the virtual's"+ " finality point in its past", redBlock) continue } @@ -244,21 +244,21 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( if err != nil { return nil, err } - log.Tracef("Red block %s is an ancestor of potentially kosherizing "+ + log.Debugf("Red block %s is an ancestor of potentially kosherizing "+ "block %s, therefore the red block is kosher", redBlock, potentiallyKosherizingBlock) if isKosherized { break } } if !isKosherized { - log.Tracef("Red block %s is not kosher. Adding it to the bad reds set", redBlock) + log.Debugf("Red block %s is not kosher. Adding it to the bad reds set", redBlock) badReds = append(badReds, redBlock) } } boundedMergeBreakingParents := hashset.New() for _, parent := range parents { - log.Tracef("Checking whether parent %s breaks the bounded merge set", parent) + log.Debugf("Checking whether parent %s breaks the bounded merge set", parent) isBadRedInPast := false for _, badRedBlock := range badReds { isBadRedInPast, err = csm.dagTopologyManager.IsAncestorOf(parent, badRedBlock) @@ -266,12 +266,12 @@ func (csm *consensusStateManager) boundedMergeBreakingParents( return nil, err } if isBadRedInPast { - log.Tracef("Parent %s is an ancestor of bad red %s", parent, badRedBlock) + log.Debugf("Parent %s is an ancestor of bad red %s", parent, badRedBlock) break } } if isBadRedInPast { - log.Tracef("Adding parent %s to the bounded merge breaking parents set", parent) + log.Debugf("Adding parent %s to the bounded merge breaking parents set", parent) boundedMergeBreakingParents.Add(parent) } } From 1abffd472cab99b1a8392a929d31655508f8cdde Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 3 Jan 2021 13:06:46 +0200 Subject: [PATCH 197/351] Add lock to mempool.GetTransaction (#1336) --- domain/miningmanager/mempool/mempool.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 40dab8a9d..f654efa87 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -114,6 +114,8 @@ func New(consensus consensusexternalapi.Consensus, acceptNonStd bool) miningmana func (mp *mempool) GetTransaction( transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) { + mp.mtx.RLock() + defer mp.mtx.RUnlock() txDesc, exists := mp.fetchTxDesc(transactionID) if !exists { From d6fe9a3017117eee10d2554ade2ff51117c0c2fd Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 3 Jan 2021 14:35:03 +0200 Subject: [PATCH 198/351] Filter headers-only blocks out of parentChildren when selecting virtualSelectedParent (#1337) --- .../add_block_to_virtual.go | 4 +-- .../check_finality_violation.go | 1 + .../pick_virtual_parents.go | 28 +++++++++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 5b8478974..4546c1c8f 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -3,14 +3,14 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/infrastructure/logger" ) // AddBlock 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) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { - log.Debugf("AddBlock start for block %s", blockHash) - defer log.Debugf("AddBlock end for block %s", blockHash) + logger.LogAndMeasureExecutionTime(log, "csm.AddBlock") log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash) isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go index 0ecea0242..7f3684894 100644 --- a/domain/consensus/processes/consensusstatemanager/check_finality_violation.go +++ b/domain/consensus/processes/consensusstatemanager/check_finality_violation.go @@ -58,6 +58,7 @@ func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.Dom // 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. + log.Debugf("Block %s violates finality, but kaspad is currently doing IBD, so this is normal", blockHash) return true, false, nil } log.Debugf("Block %s does not violate finality", blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index dbb947dad..85e9ba96f 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -114,23 +114,33 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( } log.Debugf("The parents of block %s are: %s", selectedParentCandidate, candidateParents) for _, parent := range candidateParents { - parentChildren, err := csm.dagTopologyManager.Children(parent) + allParentChildren, err := csm.dagTopologyManager.Children(parent) if err != nil { return nil, err } + log.Debugf("The children of block %s are: %s", parent, allParentChildren) - // remove virtual from parentChildren if it's there - for i, parentChild := range parentChildren { + // remove virtual and any headers-only blocks from parentChildren if such are there + nonHeadersOnlyParentChildren := make([]*externalapi.DomainHash, 0, len(allParentChildren)) + for _, parentChild := range allParentChildren { if parentChild.Equal(model.VirtualBlockHash) { - parentChildren = append(parentChildren[:i], parentChildren[i+1:]...) - break + continue } - } - log.Debugf("The children of block %s are: %s", parent, parentChildren) - if disqualifiedCandidates.ContainsAllInSlice(parentChildren) { + parentChildStatus, err := csm.blockStatusStore.Get(csm.databaseContext, parentChild) + if err != nil { + return nil, err + } + if parentChildStatus == externalapi.StatusHeaderOnly { + continue + } + nonHeadersOnlyParentChildren = append(nonHeadersOnlyParentChildren, parentChild) + } + log.Debugf("The non-virtual, non-headers-only children of block %s are: %s", parent, nonHeadersOnlyParentChildren) + + if disqualifiedCandidates.ContainsAllInSlice(nonHeadersOnlyParentChildren) { log.Debugf("The disqualified set contains all the "+ - "children of %s. Adding it to the candidate heap", parentChildren) + "children of %s. Adding it to the candidate heap", nonHeadersOnlyParentChildren) err := candidatesHeap.Push(parent) if err != nil { return nil, err From 97fddeff4b48cfde240415585637eff83a8a0786 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 3 Jan 2021 14:57:09 +0200 Subject: [PATCH 199/351] Don't mine when node is not connected (#1338) --- app/protocol/flowcontext/sync_rate.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/protocol/flowcontext/sync_rate.go b/app/protocol/flowcontext/sync_rate.go index fedbc27ed..79d488c35 100644 --- a/app/protocol/flowcontext/sync_rate.go +++ b/app/protocol/flowcontext/sync_rate.go @@ -59,6 +59,12 @@ func (f *FlowContext) isSyncRateBelowMinimum() bool { // ShouldMine returns whether it's ok to use block template from this node // for mining purposes. func (f *FlowContext) ShouldMine() (bool, error) { + peers := f.Peers() + if len(peers) == 0 { + log.Debugf("The node is not connected, so ShouldMine returns false") + return false, nil + } + if f.isSyncRateBelowMinimum() { log.Debugf("The sync rate is below the minimum, so ShouldMine returns true") return true, nil From e8cad2b2f3f49d5fca90541dd1fd7a22ab50dff2 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 3 Jan 2021 15:50:21 +0200 Subject: [PATCH 200/351] Send headers continuously without needing to run the BlockLocator protocol after every ~maxBlueScoreDifference blocks (#1339) * Send headers continuously without needing to run the BlockLocator protocol after ever ~maxBlueScoreDifference blocks * Add logging. * Make logs more descriptive. --- .../blockrelay/handle_request_headers.go | 107 +++++++++++------- app/protocol/protocol.go | 2 +- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go index 0559bba60..5e9f9776d 100644 --- a/app/protocol/flows/blockrelay/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -1,10 +1,11 @@ package blockrelay import ( + "github.com/kaspanet/kaspad/app/protocol/peer" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -19,14 +20,18 @@ type RequestIBDBlocksContext interface { type handleRequestBlocksFlow struct { RequestIBDBlocksContext incomingRoute, outgoingRoute *router.Route + peer *peer.Peer } // HandleRequestHeaders handles RequestHeaders messages -func HandleRequestHeaders(context RequestIBDBlocksContext, incomingRoute *router.Route, outgoingRoute *router.Route) error { +func HandleRequestHeaders(context RequestIBDBlocksContext, incomingRoute *router.Route, + outgoingRoute *router.Route, peer *peer.Peer) error { + flow := &handleRequestBlocksFlow{ RequestIBDBlocksContext: context, incomingRoute: incomingRoute, outgoingRoute: outgoingRoute, + peer: peer, } return flow.start() } @@ -38,53 +43,69 @@ func (flow *handleRequestBlocksFlow) start() error { return err } - // GetHashesBetween is a relatively heavy operation so we limit it. - // We expect that if the other peer did not receive all the headers - // they requested, they'd re-request a block locator and re-request - // headers with a higher lowHash - const maxBlueScoreDifference = 1 << 10 - blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference) - if err != nil { - return err - } - - for offset := 0; offset < len(blockHashes); offset += ibdBatchSize { - end := offset + ibdBatchSize - if end > len(blockHashes) { - end = len(blockHashes) - } - - blocksHashesToSend := blockHashes[offset:end] - - msgBlockHeadersToSend := make([]*appmessage.MsgBlockHeader, len(blocksHashesToSend)) - for i, blockHash := range blocksHashesToSend { - header, err := flow.Domain().Consensus().GetBlockHeader(blockHash) - if err != nil { - return err - } - msgBlockHeadersToSend[i] = appmessage.DomainBlockHeaderToBlockHeader(header) - } - err = flow.sendHeaders(msgBlockHeadersToSend) - if err != nil { - return nil - } - - // Exit the loop and don't wait for the GetNextIBDBlocks message if the last batch was - // less than ibdBatchSize. - if len(blocksHashesToSend) < ibdBatchSize { - break - } - - message, err := flow.incomingRoute.Dequeue() + batchBlockHeaders := make([]*appmessage.MsgBlockHeader, 0, ibdBatchSize) + for !lowHash.Equal(highHash) { + log.Debugf("Getting block hashes between %s and %s to %s", lowHash, highHash, flow.peer) + // GetHashesBetween is a relatively heavy operation so we limit it + // in order to avoid locking the consensus for too long + const maxBlueScoreDifference = 1 << 10 + blockHashes, err := flow.Domain().Consensus().GetHashesBetween(lowHash, highHash, maxBlueScoreDifference) if err != nil { return err } + log.Debugf("Got %d headers hashes lowHash %s", len(blockHashes), lowHash) - if _, ok := message.(*appmessage.MsgRequestNextHeaders); !ok { - return protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdRequestNextHeaders, message.Command()) + offset := 0 + for offset < len(blockHashes) { + for len(batchBlockHeaders) < ibdBatchSize { + hashAtOffset := blockHashes[offset] + blockHeader, err := flow.Domain().Consensus().GetBlockHeader(hashAtOffset) + if err != nil { + return err + } + blockHeaderMessage := appmessage.DomainBlockHeaderToBlockHeader(blockHeader) + batchBlockHeaders = append(batchBlockHeaders, blockHeaderMessage) + + offset++ + if offset == len(blockHashes) { + break + } + } + + if len(batchBlockHeaders) < ibdBatchSize { + break + } + + err = flow.sendHeaders(batchBlockHeaders) + if err != nil { + return nil + } + log.Debugf("Sent %d headers to peer %s", len(batchBlockHeaders), flow.peer) + + batchBlockHeaders = make([]*appmessage.MsgBlockHeader, 0, ibdBatchSize) + + message, err := flow.incomingRoute.Dequeue() + if err != nil { + return err + } + if _, ok := message.(*appmessage.MsgRequestNextHeaders); !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdRequestNextHeaders, message.Command()) + } } + + // The next lowHash is the last element in blockHashes + lowHash = blockHashes[len(blockHashes)-1] } + + if len(batchBlockHeaders) > 0 { + err = flow.sendHeaders(batchBlockHeaders) + if err != nil { + return nil + } + log.Debugf("Sent %d headers to peer %s", len(batchBlockHeaders), flow.peer) + } + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { return err diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index aaa4d4d6c..1bb0c0e5b 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -159,7 +159,7 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * m.registerFlow("HandleRequestHeaders", router, []appmessage.MessageCommand{appmessage.CmdRequestHeaders, appmessage.CmdRequestNextHeaders}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return blockrelay.HandleRequestHeaders(m.context, incomingRoute, outgoingRoute) + return blockrelay.HandleRequestHeaders(m.context, incomingRoute, outgoingRoute, peer) }, ), From acef311fb4e34d75909f0ec54f33c066de8d49bb Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 3 Jan 2021 17:57:14 +0200 Subject: [PATCH 201/351] Improve the performance of downloading headers (#1340) * Add a new message: BlockHeadersMessage. * Add a new message: BlockHeadersMessage. * Send a lot of headers as a single message instead of many small messages. * Keep a short queue of blockHeadersMessages so that there's never a moment when the node is not validating and inserting headers * Add a missing return statement. * Remove MsgBlockHeader from payloads. --- app/appmessage/message.go | 2 + app/appmessage/p2p_blockheaders.go | 19 + .../blockrelay/handle_request_headers.go | 75 +- app/protocol/flows/blockrelay/ibd.go | 56 +- app/protocol/protocol.go | 2 +- .../grpcserver/protowire/messages.pb.go | 3577 +++++++++-------- .../grpcserver/protowire/messages.proto | 6 +- .../grpcserver/protowire/p2p_block_headers.go | 34 + .../server/grpcserver/protowire/p2p_header.go | 9 - .../server/grpcserver/protowire/wire.go | 14 +- 10 files changed, 1949 insertions(+), 1845 deletions(-) create mode 100644 app/appmessage/p2p_blockheaders.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block_headers.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index b9f7d9766..5fb26ad4f 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -59,6 +59,7 @@ const ( CmdIBDRootHash CmdIBDBlockLocator CmdIBDBlockLocatorHighestHash + CmdBlockHeaders // rpc CmdGetCurrentNetworkRequestMessage @@ -153,6 +154,7 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdIBDRootHash: "IBDIBDRootHash", CmdIBDBlockLocator: "IBDBlockLocator", CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", + CmdBlockHeaders: "BlockHeaders", } // RPCMessageCommandToString maps all MessageCommands to their string representation diff --git a/app/appmessage/p2p_blockheaders.go b/app/appmessage/p2p_blockheaders.go new file mode 100644 index 000000000..c93e67be9 --- /dev/null +++ b/app/appmessage/p2p_blockheaders.go @@ -0,0 +1,19 @@ +package appmessage + +// BlockHeadersMessage represents a kaspa BlockHeaders message +type BlockHeadersMessage struct { + baseMessage + BlockHeaders []*MsgBlockHeader +} + +// Command returns the protocol command string for the message +func (msg *BlockHeadersMessage) Command() MessageCommand { + return CmdBlockHeaders +} + +// NewBlockHeadersMessage returns a new kaspa BlockHeaders message +func NewBlockHeadersMessage(blockHeaders []*MsgBlockHeader) *BlockHeadersMessage { + return &BlockHeadersMessage{ + BlockHeaders: blockHeaders, + } +} diff --git a/app/protocol/flows/blockrelay/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go index 5e9f9776d..5d8615b29 100644 --- a/app/protocol/flows/blockrelay/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -43,9 +43,9 @@ func (flow *handleRequestBlocksFlow) start() error { return err } - batchBlockHeaders := make([]*appmessage.MsgBlockHeader, 0, ibdBatchSize) for !lowHash.Equal(highHash) { log.Debugf("Getting block hashes between %s and %s to %s", lowHash, highHash, flow.peer) + // GetHashesBetween is a relatively heavy operation so we limit it // in order to avoid locking the consensus for too long const maxBlueScoreDifference = 1 << 10 @@ -53,59 +53,36 @@ func (flow *handleRequestBlocksFlow) start() error { if err != nil { return err } - log.Debugf("Got %d headers hashes lowHash %s", len(blockHashes), lowHash) + log.Debugf("Got %d header hashes above lowHash %s", len(blockHashes), lowHash) - offset := 0 - for offset < len(blockHashes) { - for len(batchBlockHeaders) < ibdBatchSize { - hashAtOffset := blockHashes[offset] - blockHeader, err := flow.Domain().Consensus().GetBlockHeader(hashAtOffset) - if err != nil { - return err - } - blockHeaderMessage := appmessage.DomainBlockHeaderToBlockHeader(blockHeader) - batchBlockHeaders = append(batchBlockHeaders, blockHeaderMessage) - - offset++ - if offset == len(blockHashes) { - break - } - } - - if len(batchBlockHeaders) < ibdBatchSize { - break - } - - err = flow.sendHeaders(batchBlockHeaders) - if err != nil { - return nil - } - log.Debugf("Sent %d headers to peer %s", len(batchBlockHeaders), flow.peer) - - batchBlockHeaders = make([]*appmessage.MsgBlockHeader, 0, ibdBatchSize) - - message, err := flow.incomingRoute.Dequeue() + blockHeaders := make([]*appmessage.MsgBlockHeader, len(blockHashes)) + for i, blockHash := range blockHashes { + blockHeader, err := flow.Domain().Consensus().GetBlockHeader(blockHash) if err != nil { return err } - if _, ok := message.(*appmessage.MsgRequestNextHeaders); !ok { - return protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdRequestNextHeaders, message.Command()) - } + blockHeaders[i] = appmessage.DomainBlockHeaderToBlockHeader(blockHeader) + } + + blockHeadersMessage := appmessage.NewBlockHeadersMessage(blockHeaders) + err = flow.outgoingRoute.Enqueue(blockHeadersMessage) + if err != nil { + return err + } + + message, err := flow.incomingRoute.Dequeue() + if err != nil { + return err + } + if _, ok := message.(*appmessage.MsgRequestNextHeaders); !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdRequestNextHeaders, message.Command()) } // The next lowHash is the last element in blockHashes lowHash = blockHashes[len(blockHashes)-1] } - if len(batchBlockHeaders) > 0 { - err = flow.sendHeaders(batchBlockHeaders) - if err != nil { - return nil - } - log.Debugf("Sent %d headers to peer %s", len(batchBlockHeaders), flow.peer) - } - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { return err @@ -124,13 +101,3 @@ func receiveRequestHeaders(incomingRoute *router.Route) (lowHash *externalapi.Do return msgRequestIBDBlocks.LowHash, msgRequestIBDBlocks.HighHash, nil } - -func (flow *handleRequestBlocksFlow) sendHeaders(headers []*appmessage.MsgBlockHeader) error { - for _, msgBlockHeader := range headers { - err := flow.outgoingRoute.Enqueue(msgBlockHeader) - if err != nil { - return err - } - } - return nil -} diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 0e266d0ed..eea862ace 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -184,28 +184,48 @@ func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externa return err } - blocksReceived := 0 - for { - msgBlockHeader, doneIBD, err := flow.receiveHeader() - if err != nil { - return err - } - if doneIBD { - return nil - } + // Keep a short queue of blockHeadersMessages so that there's + // never a moment when the node is not validating and inserting + // headers + blockHeadersMessageChan := make(chan *appmessage.BlockHeadersMessage, 2) + errChan := make(chan error) + doneChan := make(chan interface{}) + spawn("handleRelayInvsFlow-downloadHeaders", func() { + for { + blockHeadersMessage, doneIBD, err := flow.receiveHeaders() + if err != nil { + errChan <- err + return + } + if doneIBD { + doneChan <- struct{}{} + return + } - err = flow.processHeader(msgBlockHeader) - if err != nil { - return err - } + blockHeadersMessageChan <- blockHeadersMessage - blocksReceived++ - if blocksReceived%ibdBatchSize == 0 { err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextHeaders()) if err != nil { - return err + errChan <- err + return } } + }) + + for { + select { + case blockHeadersMessage := <-blockHeadersMessageChan: + for _, header := range blockHeadersMessage.BlockHeaders { + err = flow.processHeader(header) + if err != nil { + return err + } + } + case err := <-errChan: + return err + case <-doneChan: + return nil + } } } @@ -216,13 +236,13 @@ func (flow *handleRelayInvsFlow) sendRequestHeaders(highestSharedBlockHash *exte return flow.outgoingRoute.Enqueue(msgGetBlockInvs) } -func (flow *handleRelayInvsFlow) receiveHeader() (msgIBDBlock *appmessage.MsgBlockHeader, doneIBD bool, err error) { +func (flow *handleRelayInvsFlow) receiveHeaders() (msgIBDBlock *appmessage.BlockHeadersMessage, doneIBD bool, err error) { message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) if err != nil { return nil, false, err } switch message := message.(type) { - case *appmessage.MsgBlockHeader: + case *appmessage.BlockHeadersMessage: return message, false, nil case *appmessage.MsgDoneHeaders: return nil, true, nil diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 1bb0c0e5b..fcd5a811b 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -136,7 +136,7 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, - appmessage.CmdHeader, appmessage.CmdIBDRootHash, appmessage.CmdIBDBlockLocatorHighestHash}, + appmessage.CmdBlockHeaders, appmessage.CmdIBDRootHash, appmessage.CmdIBDBlockLocatorHighestHash}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index a1e60fb75..0c855de34 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -51,7 +51,6 @@ type KaspadMessage struct { // *KaspadMessage_Version // *KaspadMessage_TransactionNotFound // *KaspadMessage_Reject - // *KaspadMessage_BlockHeader // *KaspadMessage_RequestIBDRootUTXOSetAndBlock // *KaspadMessage_IbdRootUTXOSetAndBlock // *KaspadMessage_RequestIBDBlocks @@ -60,6 +59,7 @@ type KaspadMessage struct { // *KaspadMessage_IbdRootHash // *KaspadMessage_IbdBlockLocator // *KaspadMessage_IbdBlockLocatorHighestHash + // *KaspadMessage_BlockHeaders // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -300,13 +300,6 @@ func (x *KaspadMessage) GetReject() *RejectMessage { return nil } -func (x *KaspadMessage) GetBlockHeader() *BlockHeaderMessage { - if x, ok := x.GetPayload().(*KaspadMessage_BlockHeader); ok { - return x.BlockHeader - } - return nil -} - func (x *KaspadMessage) GetRequestIBDRootUTXOSetAndBlock() *RequestIBDRootUTXOSetAndBlockMessage { if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDRootUTXOSetAndBlock); ok { return x.RequestIBDRootUTXOSetAndBlock @@ -363,6 +356,13 @@ func (x *KaspadMessage) GetIbdBlockLocatorHighestHash() *IbdBlockLocatorHighestH return nil } +func (x *KaspadMessage) GetBlockHeaders() *BlockHeadersMessage { + if x, ok := x.GetPayload().(*KaspadMessage_BlockHeaders); ok { + return x.BlockHeaders + } + return nil +} + func (x *KaspadMessage) GetGetCurrentNetworkRequest() *GetCurrentNetworkRequestMessage { if x, ok := x.GetPayload().(*KaspadMessage_GetCurrentNetworkRequest); ok { return x.GetCurrentNetworkRequest @@ -853,10 +853,6 @@ type KaspadMessage_Reject struct { Reject *RejectMessage `protobuf:"bytes,22,opt,name=reject,proto3,oneof"` } -type KaspadMessage_BlockHeader struct { - BlockHeader *BlockHeaderMessage `protobuf:"bytes,23,opt,name=blockHeader,proto3,oneof"` -} - type KaspadMessage_RequestIBDRootUTXOSetAndBlock struct { RequestIBDRootUTXOSetAndBlock *RequestIBDRootUTXOSetAndBlockMessage `protobuf:"bytes,24,opt,name=requestIBDRootUTXOSetAndBlock,proto3,oneof"` } @@ -889,6 +885,10 @@ type KaspadMessage_IbdBlockLocatorHighestHash struct { IbdBlockLocatorHighestHash *IbdBlockLocatorHighestHashMessage `protobuf:"bytes,31,opt,name=ibdBlockLocatorHighestHash,proto3,oneof"` } +type KaspadMessage_BlockHeaders struct { + BlockHeaders *BlockHeadersMessage `protobuf:"bytes,32,opt,name=blockHeaders,proto3,oneof"` +} + type KaspadMessage_GetCurrentNetworkRequest struct { GetCurrentNetworkRequest *GetCurrentNetworkRequestMessage `protobuf:"bytes,1001,opt,name=getCurrentNetworkRequest,proto3,oneof"` } @@ -1161,8 +1161,6 @@ func (*KaspadMessage_TransactionNotFound) isKaspadMessage_Payload() {} func (*KaspadMessage_Reject) isKaspadMessage_Payload() {} -func (*KaspadMessage_BlockHeader) isKaspadMessage_Payload() {} - func (*KaspadMessage_RequestIBDRootUTXOSetAndBlock) isKaspadMessage_Payload() {} func (*KaspadMessage_IbdRootUTXOSetAndBlock) isKaspadMessage_Payload() {} @@ -1179,6 +1177,8 @@ func (*KaspadMessage_IbdBlockLocator) isKaspadMessage_Payload() {} func (*KaspadMessage_IbdBlockLocatorHighestHash) isKaspadMessage_Payload() {} +func (*KaspadMessage_BlockHeaders) isKaspadMessage_Payload() {} + func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkResponse) isKaspadMessage_Payload() {} @@ -3210,6 +3210,53 @@ func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { return nil } +type BlockHeadersMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockHeaders []*BlockHeaderMessage `protobuf:"bytes,1,rep,name=blockHeaders,proto3" json:"blockHeaders,omitempty"` +} + +func (x *BlockHeadersMessage) Reset() { + *x = BlockHeadersMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockHeadersMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockHeadersMessage) ProtoMessage() {} + +func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. +func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{36} +} + +func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { + if x != nil { + return x.BlockHeaders + } + return nil +} + type RPCError struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3221,7 +3268,7 @@ type RPCError struct { func (x *RPCError) Reset() { *x = RPCError{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3234,7 +3281,7 @@ func (x *RPCError) String() string { func (*RPCError) ProtoMessage() {} func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3247,7 +3294,7 @@ func (x *RPCError) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCError.ProtoReflect.Descriptor instead. func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} + return file_messages_proto_rawDescGZIP(), []int{37} } func (x *RPCError) GetMessage() string { @@ -3266,7 +3313,7 @@ type GetCurrentNetworkRequestMessage struct { func (x *GetCurrentNetworkRequestMessage) Reset() { *x = GetCurrentNetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3279,7 +3326,7 @@ func (x *GetCurrentNetworkRequestMessage) String() string { func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3292,7 +3339,7 @@ func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} + return file_messages_proto_rawDescGZIP(), []int{38} } type GetCurrentNetworkResponseMessage struct { @@ -3307,7 +3354,7 @@ type GetCurrentNetworkResponseMessage struct { func (x *GetCurrentNetworkResponseMessage) Reset() { *x = GetCurrentNetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3320,7 +3367,7 @@ func (x *GetCurrentNetworkResponseMessage) String() string { func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3333,7 +3380,7 @@ func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} + return file_messages_proto_rawDescGZIP(), []int{39} } func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { @@ -3361,7 +3408,7 @@ type SubmitBlockRequestMessage struct { func (x *SubmitBlockRequestMessage) Reset() { *x = SubmitBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3374,7 +3421,7 @@ func (x *SubmitBlockRequestMessage) String() string { func (*SubmitBlockRequestMessage) ProtoMessage() {} func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3387,7 +3434,7 @@ func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} + return file_messages_proto_rawDescGZIP(), []int{40} } func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { @@ -3408,7 +3455,7 @@ type SubmitBlockResponseMessage struct { func (x *SubmitBlockResponseMessage) Reset() { *x = SubmitBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3421,7 +3468,7 @@ func (x *SubmitBlockResponseMessage) String() string { func (*SubmitBlockResponseMessage) ProtoMessage() {} func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3434,7 +3481,7 @@ func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} + return file_messages_proto_rawDescGZIP(), []int{41} } func (x *SubmitBlockResponseMessage) GetError() *RPCError { @@ -3455,7 +3502,7 @@ type GetBlockTemplateRequestMessage struct { func (x *GetBlockTemplateRequestMessage) Reset() { *x = GetBlockTemplateRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3468,7 +3515,7 @@ func (x *GetBlockTemplateRequestMessage) String() string { func (*GetBlockTemplateRequestMessage) ProtoMessage() {} func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3481,7 +3528,7 @@ func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} + return file_messages_proto_rawDescGZIP(), []int{42} } func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { @@ -3504,7 +3551,7 @@ type GetBlockTemplateResponseMessage struct { func (x *GetBlockTemplateResponseMessage) Reset() { *x = GetBlockTemplateResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3517,7 +3564,7 @@ func (x *GetBlockTemplateResponseMessage) String() string { func (*GetBlockTemplateResponseMessage) ProtoMessage() {} func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3530,7 +3577,7 @@ func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} + return file_messages_proto_rawDescGZIP(), []int{43} } func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { @@ -3563,7 +3610,7 @@ type NotifyBlockAddedRequestMessage struct { func (x *NotifyBlockAddedRequestMessage) Reset() { *x = NotifyBlockAddedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3576,7 +3623,7 @@ func (x *NotifyBlockAddedRequestMessage) String() string { func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3589,7 +3636,7 @@ func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} + return file_messages_proto_rawDescGZIP(), []int{44} } type NotifyBlockAddedResponseMessage struct { @@ -3603,7 +3650,7 @@ type NotifyBlockAddedResponseMessage struct { func (x *NotifyBlockAddedResponseMessage) Reset() { *x = NotifyBlockAddedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3616,7 +3663,7 @@ func (x *NotifyBlockAddedResponseMessage) String() string { func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3629,7 +3676,7 @@ func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} + return file_messages_proto_rawDescGZIP(), []int{45} } func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { @@ -3650,7 +3697,7 @@ type BlockAddedNotificationMessage struct { func (x *BlockAddedNotificationMessage) Reset() { *x = BlockAddedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3663,7 +3710,7 @@ func (x *BlockAddedNotificationMessage) String() string { func (*BlockAddedNotificationMessage) ProtoMessage() {} func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3676,7 +3723,7 @@ func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} + return file_messages_proto_rawDescGZIP(), []int{46} } func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { @@ -3695,7 +3742,7 @@ type GetPeerAddressesRequestMessage struct { func (x *GetPeerAddressesRequestMessage) Reset() { *x = GetPeerAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3708,7 +3755,7 @@ func (x *GetPeerAddressesRequestMessage) String() string { func (*GetPeerAddressesRequestMessage) ProtoMessage() {} func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3721,7 +3768,7 @@ func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} + return file_messages_proto_rawDescGZIP(), []int{47} } type GetPeerAddressesResponseMessage struct { @@ -3737,7 +3784,7 @@ type GetPeerAddressesResponseMessage struct { func (x *GetPeerAddressesResponseMessage) Reset() { *x = GetPeerAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3750,7 +3797,7 @@ func (x *GetPeerAddressesResponseMessage) String() string { func (*GetPeerAddressesResponseMessage) ProtoMessage() {} func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3763,7 +3810,7 @@ func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} + return file_messages_proto_rawDescGZIP(), []int{48} } func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { @@ -3798,7 +3845,7 @@ type GetPeerAddressesKnownAddressMessage struct { func (x *GetPeerAddressesKnownAddressMessage) Reset() { *x = GetPeerAddressesKnownAddressMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3811,7 +3858,7 @@ func (x *GetPeerAddressesKnownAddressMessage) String() string { func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3824,7 +3871,7 @@ func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} + return file_messages_proto_rawDescGZIP(), []int{49} } func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { @@ -3843,7 +3890,7 @@ type GetSelectedTipHashRequestMessage struct { func (x *GetSelectedTipHashRequestMessage) Reset() { *x = GetSelectedTipHashRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3856,7 +3903,7 @@ func (x *GetSelectedTipHashRequestMessage) String() string { func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3869,7 +3916,7 @@ func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} + return file_messages_proto_rawDescGZIP(), []int{50} } type GetSelectedTipHashResponseMessage struct { @@ -3884,7 +3931,7 @@ type GetSelectedTipHashResponseMessage struct { func (x *GetSelectedTipHashResponseMessage) Reset() { *x = GetSelectedTipHashResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3897,7 +3944,7 @@ func (x *GetSelectedTipHashResponseMessage) String() string { func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3910,7 +3957,7 @@ func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} + return file_messages_proto_rawDescGZIP(), []int{51} } func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { @@ -3940,7 +3987,7 @@ type MempoolEntry struct { func (x *MempoolEntry) Reset() { *x = MempoolEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3953,7 +4000,7 @@ func (x *MempoolEntry) String() string { func (*MempoolEntry) ProtoMessage() {} func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3966,7 +4013,7 @@ func (x *MempoolEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} + return file_messages_proto_rawDescGZIP(), []int{52} } func (x *MempoolEntry) GetFee() uint64 { @@ -3994,7 +4041,7 @@ type GetMempoolEntryRequestMessage struct { func (x *GetMempoolEntryRequestMessage) Reset() { *x = GetMempoolEntryRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4007,7 +4054,7 @@ func (x *GetMempoolEntryRequestMessage) String() string { func (*GetMempoolEntryRequestMessage) ProtoMessage() {} func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4020,7 +4067,7 @@ func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} + return file_messages_proto_rawDescGZIP(), []int{53} } func (x *GetMempoolEntryRequestMessage) GetTxId() string { @@ -4042,7 +4089,7 @@ type GetMempoolEntryResponseMessage struct { func (x *GetMempoolEntryResponseMessage) Reset() { *x = GetMempoolEntryResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4055,7 +4102,7 @@ func (x *GetMempoolEntryResponseMessage) String() string { func (*GetMempoolEntryResponseMessage) ProtoMessage() {} func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4068,7 +4115,7 @@ func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} + return file_messages_proto_rawDescGZIP(), []int{54} } func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { @@ -4094,7 +4141,7 @@ type GetMempoolEntriesRequestMessage struct { func (x *GetMempoolEntriesRequestMessage) Reset() { *x = GetMempoolEntriesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4107,7 +4154,7 @@ func (x *GetMempoolEntriesRequestMessage) String() string { func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4120,7 +4167,7 @@ func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} + return file_messages_proto_rawDescGZIP(), []int{55} } type GetMempoolEntriesResponseMessage struct { @@ -4135,7 +4182,7 @@ type GetMempoolEntriesResponseMessage struct { func (x *GetMempoolEntriesResponseMessage) Reset() { *x = GetMempoolEntriesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4148,7 +4195,7 @@ func (x *GetMempoolEntriesResponseMessage) String() string { func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4161,7 +4208,7 @@ func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} + return file_messages_proto_rawDescGZIP(), []int{56} } func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { @@ -4187,7 +4234,7 @@ type GetConnectedPeerInfoRequestMessage struct { func (x *GetConnectedPeerInfoRequestMessage) Reset() { *x = GetConnectedPeerInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4200,7 +4247,7 @@ func (x *GetConnectedPeerInfoRequestMessage) String() string { func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4213,7 +4260,7 @@ func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} + return file_messages_proto_rawDescGZIP(), []int{57} } type GetConnectedPeerInfoResponseMessage struct { @@ -4228,7 +4275,7 @@ type GetConnectedPeerInfoResponseMessage struct { func (x *GetConnectedPeerInfoResponseMessage) Reset() { *x = GetConnectedPeerInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4241,7 +4288,7 @@ func (x *GetConnectedPeerInfoResponseMessage) String() string { func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4254,7 +4301,7 @@ func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} + return file_messages_proto_rawDescGZIP(), []int{58} } func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { @@ -4289,7 +4336,7 @@ type GetConnectedPeerInfoMessage struct { func (x *GetConnectedPeerInfoMessage) Reset() { *x = GetConnectedPeerInfoMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4302,7 +4349,7 @@ func (x *GetConnectedPeerInfoMessage) String() string { func (*GetConnectedPeerInfoMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4315,7 +4362,7 @@ func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} + return file_messages_proto_rawDescGZIP(), []int{59} } func (x *GetConnectedPeerInfoMessage) GetId() string { @@ -4386,7 +4433,7 @@ type AddPeerRequestMessage struct { func (x *AddPeerRequestMessage) Reset() { *x = AddPeerRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4399,7 +4446,7 @@ func (x *AddPeerRequestMessage) String() string { func (*AddPeerRequestMessage) ProtoMessage() {} func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4412,7 +4459,7 @@ func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} + return file_messages_proto_rawDescGZIP(), []int{60} } func (x *AddPeerRequestMessage) GetAddress() string { @@ -4440,7 +4487,7 @@ type AddPeerResponseMessage struct { func (x *AddPeerResponseMessage) Reset() { *x = AddPeerResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4453,7 +4500,7 @@ func (x *AddPeerResponseMessage) String() string { func (*AddPeerResponseMessage) ProtoMessage() {} func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4466,7 +4513,7 @@ func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} + return file_messages_proto_rawDescGZIP(), []int{61} } func (x *AddPeerResponseMessage) GetError() *RPCError { @@ -4487,7 +4534,7 @@ type SubmitTransactionRequestMessage struct { func (x *SubmitTransactionRequestMessage) Reset() { *x = SubmitTransactionRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4500,7 +4547,7 @@ func (x *SubmitTransactionRequestMessage) String() string { func (*SubmitTransactionRequestMessage) ProtoMessage() {} func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4513,7 +4560,7 @@ func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} + return file_messages_proto_rawDescGZIP(), []int{62} } func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { @@ -4535,7 +4582,7 @@ type SubmitTransactionResponseMessage struct { func (x *SubmitTransactionResponseMessage) Reset() { *x = SubmitTransactionResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4548,7 +4595,7 @@ func (x *SubmitTransactionResponseMessage) String() string { func (*SubmitTransactionResponseMessage) ProtoMessage() {} func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4561,7 +4608,7 @@ func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} + return file_messages_proto_rawDescGZIP(), []int{63} } func (x *SubmitTransactionResponseMessage) GetTransactionId() string { @@ -4587,7 +4634,7 @@ type NotifyVirtualSelectedParentChainChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4600,7 +4647,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4613,7 +4660,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() p // Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} + return file_messages_proto_rawDescGZIP(), []int{64} } type NotifyVirtualSelectedParentChainChangedResponseMessage struct { @@ -4627,7 +4674,7 @@ type NotifyVirtualSelectedParentChainChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4640,7 +4687,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4653,7 +4700,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() // Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} + return file_messages_proto_rawDescGZIP(), []int{65} } func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { @@ -4675,7 +4722,7 @@ type VirtualSelectedParentChainChangedNotificationMessage struct { func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { *x = VirtualSelectedParentChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4688,7 +4735,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4701,7 +4748,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() pr // Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} + return file_messages_proto_rawDescGZIP(), []int{66} } func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { @@ -4730,7 +4777,7 @@ type ChainBlock struct { func (x *ChainBlock) Reset() { *x = ChainBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4743,7 +4790,7 @@ func (x *ChainBlock) String() string { func (*ChainBlock) ProtoMessage() {} func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4756,7 +4803,7 @@ func (x *ChainBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} + return file_messages_proto_rawDescGZIP(), []int{67} } func (x *ChainBlock) GetHash() string { @@ -4785,7 +4832,7 @@ type AcceptedBlock struct { func (x *AcceptedBlock) Reset() { *x = AcceptedBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4798,7 +4845,7 @@ func (x *AcceptedBlock) String() string { func (*AcceptedBlock) ProtoMessage() {} func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4811,7 +4858,7 @@ func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} + return file_messages_proto_rawDescGZIP(), []int{68} } func (x *AcceptedBlock) GetHash() string { @@ -4841,7 +4888,7 @@ type GetBlockRequestMessage struct { func (x *GetBlockRequestMessage) Reset() { *x = GetBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4854,7 +4901,7 @@ func (x *GetBlockRequestMessage) String() string { func (*GetBlockRequestMessage) ProtoMessage() {} func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4867,7 +4914,7 @@ func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} + return file_messages_proto_rawDescGZIP(), []int{69} } func (x *GetBlockRequestMessage) GetHash() string { @@ -4904,7 +4951,7 @@ type GetBlockResponseMessage struct { func (x *GetBlockResponseMessage) Reset() { *x = GetBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4917,7 +4964,7 @@ func (x *GetBlockResponseMessage) String() string { func (*GetBlockResponseMessage) ProtoMessage() {} func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4930,7 +4977,7 @@ func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} + return file_messages_proto_rawDescGZIP(), []int{70} } func (x *GetBlockResponseMessage) GetBlockHash() string { @@ -4980,7 +5027,7 @@ type BlockVerboseData struct { func (x *BlockVerboseData) Reset() { *x = BlockVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4993,7 +5040,7 @@ func (x *BlockVerboseData) String() string { func (*BlockVerboseData) ProtoMessage() {} func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5006,7 +5053,7 @@ func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} + return file_messages_proto_rawDescGZIP(), []int{71} } func (x *BlockVerboseData) GetHash() string { @@ -5145,7 +5192,7 @@ type TransactionVerboseData struct { func (x *TransactionVerboseData) Reset() { *x = TransactionVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5158,7 +5205,7 @@ func (x *TransactionVerboseData) String() string { func (*TransactionVerboseData) ProtoMessage() {} func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5171,7 +5218,7 @@ func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} + return file_messages_proto_rawDescGZIP(), []int{72} } func (x *TransactionVerboseData) GetTxId() string { @@ -5286,7 +5333,7 @@ type TransactionVerboseInput struct { func (x *TransactionVerboseInput) Reset() { *x = TransactionVerboseInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5299,7 +5346,7 @@ func (x *TransactionVerboseInput) String() string { func (*TransactionVerboseInput) ProtoMessage() {} func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5312,7 +5359,7 @@ func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} + return file_messages_proto_rawDescGZIP(), []int{73} } func (x *TransactionVerboseInput) GetTxId() string { @@ -5355,7 +5402,7 @@ type ScriptSig struct { func (x *ScriptSig) Reset() { *x = ScriptSig{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5368,7 +5415,7 @@ func (x *ScriptSig) String() string { func (*ScriptSig) ProtoMessage() {} func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5381,7 +5428,7 @@ func (x *ScriptSig) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} + return file_messages_proto_rawDescGZIP(), []int{74} } func (x *ScriptSig) GetAsm() string { @@ -5411,7 +5458,7 @@ type TransactionVerboseOutput struct { func (x *TransactionVerboseOutput) Reset() { *x = TransactionVerboseOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5424,7 +5471,7 @@ func (x *TransactionVerboseOutput) String() string { func (*TransactionVerboseOutput) ProtoMessage() {} func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5437,7 +5484,7 @@ func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} + return file_messages_proto_rawDescGZIP(), []int{75} } func (x *TransactionVerboseOutput) GetValue() uint64 { @@ -5475,7 +5522,7 @@ type ScriptPubKeyResult struct { func (x *ScriptPubKeyResult) Reset() { *x = ScriptPubKeyResult{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5488,7 +5535,7 @@ func (x *ScriptPubKeyResult) String() string { func (*ScriptPubKeyResult) ProtoMessage() {} func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5501,7 +5548,7 @@ func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptPubKeyResult.ProtoReflect.Descriptor instead. func (*ScriptPubKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} + return file_messages_proto_rawDescGZIP(), []int{76} } func (x *ScriptPubKeyResult) GetAsm() string { @@ -5543,7 +5590,7 @@ type GetSubnetworkRequestMessage struct { func (x *GetSubnetworkRequestMessage) Reset() { *x = GetSubnetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5556,7 +5603,7 @@ func (x *GetSubnetworkRequestMessage) String() string { func (*GetSubnetworkRequestMessage) ProtoMessage() {} func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5569,7 +5616,7 @@ func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} + return file_messages_proto_rawDescGZIP(), []int{77} } func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { @@ -5591,7 +5638,7 @@ type GetSubnetworkResponseMessage struct { func (x *GetSubnetworkResponseMessage) Reset() { *x = GetSubnetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5604,7 +5651,7 @@ func (x *GetSubnetworkResponseMessage) String() string { func (*GetSubnetworkResponseMessage) ProtoMessage() {} func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5617,7 +5664,7 @@ func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} + return file_messages_proto_rawDescGZIP(), []int{78} } func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { @@ -5645,7 +5692,7 @@ type GetVirtualSelectedParentChainFromBlockRequestMessage struct { func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5658,7 +5705,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5671,7 +5718,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() pr // Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} + return file_messages_proto_rawDescGZIP(), []int{79} } func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { @@ -5694,7 +5741,7 @@ type GetVirtualSelectedParentChainFromBlockResponseMessage struct { func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5707,7 +5754,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5720,7 +5767,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() p // Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} + return file_messages_proto_rawDescGZIP(), []int{80} } func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { @@ -5758,7 +5805,7 @@ type GetBlocksRequestMessage struct { func (x *GetBlocksRequestMessage) Reset() { *x = GetBlocksRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5771,7 +5818,7 @@ func (x *GetBlocksRequestMessage) String() string { func (*GetBlocksRequestMessage) ProtoMessage() {} func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5784,7 +5831,7 @@ func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} + return file_messages_proto_rawDescGZIP(), []int{81} } func (x *GetBlocksRequestMessage) GetLowHash() string { @@ -5829,7 +5876,7 @@ type GetBlocksResponseMessage struct { func (x *GetBlocksResponseMessage) Reset() { *x = GetBlocksResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5842,7 +5889,7 @@ func (x *GetBlocksResponseMessage) String() string { func (*GetBlocksResponseMessage) ProtoMessage() {} func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5855,7 +5902,7 @@ func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} + return file_messages_proto_rawDescGZIP(), []int{82} } func (x *GetBlocksResponseMessage) GetBlockHashes() []string { @@ -5895,7 +5942,7 @@ type GetBlockCountRequestMessage struct { func (x *GetBlockCountRequestMessage) Reset() { *x = GetBlockCountRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5908,7 +5955,7 @@ func (x *GetBlockCountRequestMessage) String() string { func (*GetBlockCountRequestMessage) ProtoMessage() {} func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5921,7 +5968,7 @@ func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} + return file_messages_proto_rawDescGZIP(), []int{83} } type GetBlockCountResponseMessage struct { @@ -5937,7 +5984,7 @@ type GetBlockCountResponseMessage struct { func (x *GetBlockCountResponseMessage) Reset() { *x = GetBlockCountResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5950,7 +5997,7 @@ func (x *GetBlockCountResponseMessage) String() string { func (*GetBlockCountResponseMessage) ProtoMessage() {} func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5963,7 +6010,7 @@ func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} + return file_messages_proto_rawDescGZIP(), []int{84} } func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { @@ -5996,7 +6043,7 @@ type GetBlockDagInfoRequestMessage struct { func (x *GetBlockDagInfoRequestMessage) Reset() { *x = GetBlockDagInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6009,7 +6056,7 @@ func (x *GetBlockDagInfoRequestMessage) String() string { func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6022,7 +6069,7 @@ func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} + return file_messages_proto_rawDescGZIP(), []int{85} } type GetBlockDagInfoResponseMessage struct { @@ -6043,7 +6090,7 @@ type GetBlockDagInfoResponseMessage struct { func (x *GetBlockDagInfoResponseMessage) Reset() { *x = GetBlockDagInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6056,7 +6103,7 @@ func (x *GetBlockDagInfoResponseMessage) String() string { func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6069,7 +6116,7 @@ func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} + return file_messages_proto_rawDescGZIP(), []int{86} } func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { @@ -6139,7 +6186,7 @@ type ResolveFinalityConflictRequestMessage struct { func (x *ResolveFinalityConflictRequestMessage) Reset() { *x = ResolveFinalityConflictRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6152,7 +6199,7 @@ func (x *ResolveFinalityConflictRequestMessage) String() string { func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6165,7 +6212,7 @@ func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} + return file_messages_proto_rawDescGZIP(), []int{87} } func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { @@ -6186,7 +6233,7 @@ type ResolveFinalityConflictResponseMessage struct { func (x *ResolveFinalityConflictResponseMessage) Reset() { *x = ResolveFinalityConflictResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6199,7 +6246,7 @@ func (x *ResolveFinalityConflictResponseMessage) String() string { func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6212,7 +6259,7 @@ func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} + return file_messages_proto_rawDescGZIP(), []int{88} } func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { @@ -6231,7 +6278,7 @@ type NotifyFinalityConflictsRequestMessage struct { func (x *NotifyFinalityConflictsRequestMessage) Reset() { *x = NotifyFinalityConflictsRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6244,7 +6291,7 @@ func (x *NotifyFinalityConflictsRequestMessage) String() string { func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6257,7 +6304,7 @@ func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} + return file_messages_proto_rawDescGZIP(), []int{89} } type NotifyFinalityConflictsResponseMessage struct { @@ -6271,7 +6318,7 @@ type NotifyFinalityConflictsResponseMessage struct { func (x *NotifyFinalityConflictsResponseMessage) Reset() { *x = NotifyFinalityConflictsResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6284,7 +6331,7 @@ func (x *NotifyFinalityConflictsResponseMessage) String() string { func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6297,7 +6344,7 @@ func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} + return file_messages_proto_rawDescGZIP(), []int{90} } func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { @@ -6318,7 +6365,7 @@ type FinalityConflictNotificationMessage struct { func (x *FinalityConflictNotificationMessage) Reset() { *x = FinalityConflictNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6331,7 +6378,7 @@ func (x *FinalityConflictNotificationMessage) String() string { func (*FinalityConflictNotificationMessage) ProtoMessage() {} func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6344,7 +6391,7 @@ func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{90} + return file_messages_proto_rawDescGZIP(), []int{91} } func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { @@ -6365,7 +6412,7 @@ type FinalityConflictResolvedNotificationMessage struct { func (x *FinalityConflictResolvedNotificationMessage) Reset() { *x = FinalityConflictResolvedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6378,7 +6425,7 @@ func (x *FinalityConflictResolvedNotificationMessage) String() string { func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[92] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6391,7 +6438,7 @@ func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflec // Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{91} + return file_messages_proto_rawDescGZIP(), []int{92} } func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { @@ -6410,7 +6457,7 @@ type ShutDownRequestMessage struct { func (x *ShutDownRequestMessage) Reset() { *x = ShutDownRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6423,7 +6470,7 @@ func (x *ShutDownRequestMessage) String() string { func (*ShutDownRequestMessage) ProtoMessage() {} func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[93] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6436,7 +6483,7 @@ func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{92} + return file_messages_proto_rawDescGZIP(), []int{93} } type ShutDownResponseMessage struct { @@ -6450,7 +6497,7 @@ type ShutDownResponseMessage struct { func (x *ShutDownResponseMessage) Reset() { *x = ShutDownResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6463,7 +6510,7 @@ func (x *ShutDownResponseMessage) String() string { func (*ShutDownResponseMessage) ProtoMessage() {} func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[94] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6476,7 +6523,7 @@ func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{93} + return file_messages_proto_rawDescGZIP(), []int{94} } func (x *ShutDownResponseMessage) GetError() *RPCError { @@ -6499,7 +6546,7 @@ type GetHeadersRequestMessage struct { func (x *GetHeadersRequestMessage) Reset() { *x = GetHeadersRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6512,7 +6559,7 @@ func (x *GetHeadersRequestMessage) String() string { func (*GetHeadersRequestMessage) ProtoMessage() {} func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[95] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6525,7 +6572,7 @@ func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{94} + return file_messages_proto_rawDescGZIP(), []int{95} } func (x *GetHeadersRequestMessage) GetStartHash() string { @@ -6561,7 +6608,7 @@ type GetHeadersResponseMessage struct { func (x *GetHeadersResponseMessage) Reset() { *x = GetHeadersResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6574,7 +6621,7 @@ func (x *GetHeadersResponseMessage) String() string { func (*GetHeadersResponseMessage) ProtoMessage() {} func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[96] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6587,7 +6634,7 @@ func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{95} + return file_messages_proto_rawDescGZIP(), []int{96} } func (x *GetHeadersResponseMessage) GetHeaders() []string { @@ -6615,7 +6662,7 @@ type NotifyUtxosChangedRequestMessage struct { func (x *NotifyUtxosChangedRequestMessage) Reset() { *x = NotifyUtxosChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6628,7 +6675,7 @@ func (x *NotifyUtxosChangedRequestMessage) String() string { func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[97] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6641,7 +6688,7 @@ func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{96} + return file_messages_proto_rawDescGZIP(), []int{97} } func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { @@ -6662,7 +6709,7 @@ type NotifyUtxosChangedResponseMessage struct { func (x *NotifyUtxosChangedResponseMessage) Reset() { *x = NotifyUtxosChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6675,7 +6722,7 @@ func (x *NotifyUtxosChangedResponseMessage) String() string { func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[98] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6688,7 +6735,7 @@ func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{97} + return file_messages_proto_rawDescGZIP(), []int{98} } func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { @@ -6710,7 +6757,7 @@ type UtxosChangedNotificationMessage struct { func (x *UtxosChangedNotificationMessage) Reset() { *x = UtxosChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6723,7 +6770,7 @@ func (x *UtxosChangedNotificationMessage) String() string { func (*UtxosChangedNotificationMessage) ProtoMessage() {} func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[99] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6736,7 +6783,7 @@ func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{98} + return file_messages_proto_rawDescGZIP(), []int{99} } func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { @@ -6766,7 +6813,7 @@ type UtxosByAddressesEntry struct { func (x *UtxosByAddressesEntry) Reset() { *x = UtxosByAddressesEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6779,7 +6826,7 @@ func (x *UtxosByAddressesEntry) String() string { func (*UtxosByAddressesEntry) ProtoMessage() {} func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[100] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6792,7 +6839,7 @@ func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{99} + return file_messages_proto_rawDescGZIP(), []int{100} } func (x *UtxosByAddressesEntry) GetAddress() string { @@ -6834,7 +6881,7 @@ type RpcTransaction struct { func (x *RpcTransaction) Reset() { *x = RpcTransaction{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6847,7 +6894,7 @@ func (x *RpcTransaction) String() string { func (*RpcTransaction) ProtoMessage() {} func (x *RpcTransaction) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[101] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6860,7 +6907,7 @@ func (x *RpcTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. func (*RpcTransaction) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{100} + return file_messages_proto_rawDescGZIP(), []int{101} } func (x *RpcTransaction) GetVersion() int32 { @@ -6932,7 +6979,7 @@ type RpcTransactionInput struct { func (x *RpcTransactionInput) Reset() { *x = RpcTransactionInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6945,7 +6992,7 @@ func (x *RpcTransactionInput) String() string { func (*RpcTransactionInput) ProtoMessage() {} func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[102] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6958,7 +7005,7 @@ func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. func (*RpcTransactionInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{101} + return file_messages_proto_rawDescGZIP(), []int{102} } func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { @@ -6994,7 +7041,7 @@ type RpcTransactionOutput struct { func (x *RpcTransactionOutput) Reset() { *x = RpcTransactionOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7007,7 +7054,7 @@ func (x *RpcTransactionOutput) String() string { func (*RpcTransactionOutput) ProtoMessage() {} func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[103] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7020,7 +7067,7 @@ func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{102} + return file_messages_proto_rawDescGZIP(), []int{103} } func (x *RpcTransactionOutput) GetAmount() uint64 { @@ -7049,7 +7096,7 @@ type RpcOutpoint struct { func (x *RpcOutpoint) Reset() { *x = RpcOutpoint{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7062,7 +7109,7 @@ func (x *RpcOutpoint) String() string { func (*RpcOutpoint) ProtoMessage() {} func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[104] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7075,7 +7122,7 @@ func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. func (*RpcOutpoint) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{103} + return file_messages_proto_rawDescGZIP(), []int{104} } func (x *RpcOutpoint) GetTransactionId() string { @@ -7106,7 +7153,7 @@ type RpcUtxoEntry struct { func (x *RpcUtxoEntry) Reset() { *x = RpcUtxoEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7119,7 +7166,7 @@ func (x *RpcUtxoEntry) String() string { func (*RpcUtxoEntry) ProtoMessage() {} func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[105] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7132,7 +7179,7 @@ func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{104} + return file_messages_proto_rawDescGZIP(), []int{105} } func (x *RpcUtxoEntry) GetAmount() uint64 { @@ -7174,7 +7221,7 @@ type GetUtxosByAddressesRequestMessage struct { func (x *GetUtxosByAddressesRequestMessage) Reset() { *x = GetUtxosByAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7187,7 +7234,7 @@ func (x *GetUtxosByAddressesRequestMessage) String() string { func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[106] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7200,7 +7247,7 @@ func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{105} + return file_messages_proto_rawDescGZIP(), []int{106} } func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { @@ -7222,7 +7269,7 @@ type GetUtxosByAddressesResponseMessage struct { func (x *GetUtxosByAddressesResponseMessage) Reset() { *x = GetUtxosByAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7235,7 +7282,7 @@ func (x *GetUtxosByAddressesResponseMessage) String() string { func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[107] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7248,7 +7295,7 @@ func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{106} + return file_messages_proto_rawDescGZIP(), []int{107} } func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { @@ -7274,7 +7321,7 @@ type GetVirtualSelectedParentBlueScoreRequestMessage struct { func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7287,7 +7334,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[108] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7300,7 +7347,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protore // Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{107} + return file_messages_proto_rawDescGZIP(), []int{108} } type GetVirtualSelectedParentBlueScoreResponseMessage struct { @@ -7315,7 +7362,7 @@ type GetVirtualSelectedParentBlueScoreResponseMessage struct { func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[108] + mi := &file_messages_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7328,7 +7375,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[108] + mi := &file_messages_proto_msgTypes[109] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7341,7 +7388,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protor // Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{108} + return file_messages_proto_rawDescGZIP(), []int{109} } func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { @@ -7367,7 +7414,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[109] + mi := &file_messages_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7380,7 +7427,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() str func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[109] + mi := &file_messages_proto_msgTypes[110] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7393,7 +7440,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{109} + return file_messages_proto_rawDescGZIP(), []int{110} } type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { @@ -7407,7 +7454,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[110] + mi := &file_messages_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7420,7 +7467,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() st func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[110] + mi := &file_messages_proto_msgTypes[111] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7433,7 +7480,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflec // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{110} + return file_messages_proto_rawDescGZIP(), []int{111} } func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { @@ -7454,7 +7501,7 @@ type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[111] + mi := &file_messages_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7467,7 +7514,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() stri func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[111] + mi := &file_messages_proto_msgTypes[112] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7480,7 +7527,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect( // Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{111} + return file_messages_proto_rawDescGZIP(), []int{112} } func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { @@ -7494,7 +7541,7 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xd3, 0x45, 0x0a, 0x0d, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xd6, 0x45, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, @@ -7582,1279 +7629,1285 @@ var file_messages_proto_rawDesc = []byte{ 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, - 0x12, 0x41, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, - 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x12, 0x77, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, + 0x12, 0x77, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, + 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x16, 0x69, 0x62, 0x64, + 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, + 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, + 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, + 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, + 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, + 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x56, + 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x16, - 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, - 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, - 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, - 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, - 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, - 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, - 0x64, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, - 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, 0x69, 0x62, 0x64, - 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, - 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, - 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, - 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, - 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, + 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x69, 0x62, + 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, + 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, - 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x69, 0x0a, 0x18, 0x67, - 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, + 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, + 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, + 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x69, + 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, + 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, - 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, - 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, - 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, - 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, - 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, - 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, - 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, + 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, + 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, + 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, + 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, + 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, + 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, + 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, - 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, - 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, - 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, - 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, - 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, - 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, - 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, - 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x14, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x15, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x1e, 0x72, 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, 0x12, - 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, - 0x72, 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, 0x12, - 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, - 0x6e, 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, 0x18, - 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, - 0x66, 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, 0x18, 0x91, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x24, 0x66, - 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, - 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, - 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, - 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, - 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, - 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, - 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, - 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, - 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, - 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, - 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x14, 0x67, + 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x15, + 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, - 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, + 0x65, 0x6e, 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, 0x48, + 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, + 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, + 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, + 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, + 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, + 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, + 0x1e, 0x6e, 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, 0x12, + 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, + 0x6e, 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, 0x12, + 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, + 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, + 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, + 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, + 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, + 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, + 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, - 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, - 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x6a, 0x0a, - 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, 0x53, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, - 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, - 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3e, 0x0a, - 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0d, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x11, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, - 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, - 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, - 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, - 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, - 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, - 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, - 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, - 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, - 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, - 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, - 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, - 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, - 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, - 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, - 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, - 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, - 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, - 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, - 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, + 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, - 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, - 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, - 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, - 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, - 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, - 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, + 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, + 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, + 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, + 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, + 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, - 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, - 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, + 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, + 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, + 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, + 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, + 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, + 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, + 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, + 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, + 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, + 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, + 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, + 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, + 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, + 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, + 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, + 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, + 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, + 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, + 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, + 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, + 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, + 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, + 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, + 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, - 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 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, 0x40, 0x0a, 0x1e, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, - 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x01, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, - 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, - 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, - 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, - 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, - 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, - 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, - 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, - 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, 0x0a, 0x1b, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, - 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, - 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, - 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, - 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, - 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, - 0x72, 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, 0x5e, 0x0a, 0x1f, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, + 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x6f, 0x72, 0x22, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, + 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, + 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, + 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, + 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, + 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 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, 0x39, + 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, + 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 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, 0x24, + 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, + 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, + 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, + 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, + 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, + 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, + 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 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, + 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 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, 0xb3, + 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 0xdb, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, + 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, - 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, + 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 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, 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, 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, + 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, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 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, 0xdb, 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, 0x12, 0x22, 0x0a, 0x0c, - 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, - 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 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, - 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, 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, + 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, - 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, - 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, - 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, - 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, - 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, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, - 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, - 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, - 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, - 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, - 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, - 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, - 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 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, 0x82, 0x01, 0x0a, 0x38, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 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, - 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, + 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, + 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, + 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, + 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, + 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, + 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, + 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, + 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, + 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, + 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, + 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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 ( @@ -8869,7 +8922,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 112) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 113) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage @@ -8907,82 +8960,83 @@ var file_messages_proto_goTypes = []interface{}{ (*IBDRootHashMessage)(nil), // 33: protowire.IBDRootHashMessage (*IbdBlockLocatorMessage)(nil), // 34: protowire.IbdBlockLocatorMessage (*IbdBlockLocatorHighestHashMessage)(nil), // 35: protowire.IbdBlockLocatorHighestHashMessage - (*RPCError)(nil), // 36: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 37: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 38: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 39: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 40: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 41: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 42: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 43: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 44: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 45: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 46: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 47: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 48: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 49: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 50: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 51: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 52: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 53: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 54: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 55: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 56: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 57: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 58: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 59: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 60: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 61: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 62: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 63: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 64: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 65: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*ChainBlock)(nil), // 66: protowire.ChainBlock - (*AcceptedBlock)(nil), // 67: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 68: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 69: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 70: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 71: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 72: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 73: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 74: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 75: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 76: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 77: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 78: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 79: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 80: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 81: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 82: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 83: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 84: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 85: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 86: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 87: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 88: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 89: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 90: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 91: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 92: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 93: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 94: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 95: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 96: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 97: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 98: protowire.UtxosChangedNotificationMessage - (*UtxosByAddressesEntry)(nil), // 99: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 100: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 101: protowire.RpcTransactionInput - (*RpcTransactionOutput)(nil), // 102: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 103: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 104: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 105: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 106: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 107: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 108: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 109: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 110: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 111: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*BlockHeadersMessage)(nil), // 36: protowire.BlockHeadersMessage + (*RPCError)(nil), // 37: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 38: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 39: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 40: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 41: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 42: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 43: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 44: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 45: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 46: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 47: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 48: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 49: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 50: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 51: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 52: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 53: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 54: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 55: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 56: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 57: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 58: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 59: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 60: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 61: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 62: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 63: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 64: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 65: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 66: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*ChainBlock)(nil), // 67: protowire.ChainBlock + (*AcceptedBlock)(nil), // 68: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 69: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 70: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 71: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 72: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 73: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 74: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 75: protowire.TransactionVerboseOutput + (*ScriptPubKeyResult)(nil), // 76: protowire.ScriptPubKeyResult + (*GetSubnetworkRequestMessage)(nil), // 77: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 78: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 79: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 80: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 81: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 82: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 83: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 84: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 85: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 86: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 87: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 88: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 89: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 90: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 91: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 92: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 93: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 94: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 95: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 96: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 97: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 98: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 99: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 100: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 101: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 102: protowire.RpcTransactionInput + (*RpcTransactionOutput)(nil), // 103: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 104: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 105: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 106: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 107: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 108: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 109: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 110: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 111: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 112: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -9005,73 +9059,73 @@ var file_messages_proto_depIdxs = []int32{ 26, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage 20, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage 27, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 11, // 20: protowire.KaspadMessage.blockHeader:type_name -> protowire.BlockHeaderMessage - 28, // 21: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage - 29, // 22: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage - 30, // 23: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 31, // 24: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 32, // 25: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage - 33, // 26: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage - 34, // 27: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage - 35, // 28: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage - 37, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 38, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 39, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 40, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 41, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 42, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 43, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 44, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 45, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 46, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 47, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 49, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 50, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 52, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 53, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 56, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 57, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 59, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 60, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 61, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 62, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 63, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 64, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 65, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 68, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 69, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 76, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 77, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 78, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 79, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 80, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 81, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 82, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 83, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 84, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 85, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 86, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 87, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 88, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 89, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 90, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 91, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 54, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 55, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 92, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 93, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 94, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 95, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 96, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 97, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 98, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 105, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 106, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 107, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 108, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 109, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 110, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 111, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 28, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage + 29, // 21: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage + 30, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage + 31, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage + 32, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage + 33, // 25: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage + 34, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage + 35, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage + 36, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage + 38, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 39, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 40, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 41, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 42, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 43, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 44, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 45, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 46, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 47, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 48, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 50, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 51, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 53, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 54, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 57, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 58, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 60, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 61, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 62, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 63, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 64, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 65, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 66, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 69, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 70, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 77, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 78, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 79, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 80, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 81, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 82, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 83, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 84, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 85, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 86, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 87, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 88, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 89, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 90, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 91, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 92, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 55, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 56, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 93, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 94, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 95, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 96, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 97, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 98, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 99, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 106, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 107, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 108, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 109, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 110, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 111, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 112, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage 4, // 87: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId 3, // 88: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress 6, // 89: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput @@ -9105,69 +9159,70 @@ var file_messages_proto_depIdxs = []int32{ 12, // 117: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash 12, // 118: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash 12, // 119: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash - 36, // 120: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 121: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 36, // 122: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 123: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 36, // 124: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 36, // 125: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 126: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 48, // 127: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 48, // 128: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 36, // 129: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 36, // 130: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 71, // 131: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 51, // 132: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 36, // 133: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 51, // 134: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 36, // 135: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 58, // 136: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 36, // 137: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 36, // 138: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 100, // 139: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 36, // 140: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 36, // 141: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 66, // 142: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 67, // 143: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 70, // 144: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 36, // 145: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 71, // 146: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 72, // 147: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 74, // 148: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 73, // 149: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 75, // 150: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 36, // 151: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 66, // 152: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 36, // 153: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 70, // 154: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 36, // 155: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 36, // 156: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 36, // 157: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 36, // 158: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 36, // 159: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 36, // 160: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 36, // 161: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 36, // 162: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 99, // 163: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 99, // 164: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 103, // 165: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 104, // 166: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 101, // 167: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 102, // 168: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 103, // 169: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 99, // 170: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 36, // 171: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 36, // 172: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 36, // 173: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 0, // 174: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 175: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 176: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 177: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 176, // [176:178] is the sub-list for method output_type - 174, // [174:176] is the sub-list for method input_type - 174, // [174:174] is the sub-list for extension type_name - 174, // [174:174] is the sub-list for extension extendee - 0, // [0:174] is the sub-list for field type_name + 11, // 120: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage + 37, // 121: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 10, // 122: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 37, // 123: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 10, // 124: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 37, // 125: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 37, // 126: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 10, // 127: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 49, // 128: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 49, // 129: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 37, // 130: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 37, // 131: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 72, // 132: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 52, // 133: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 37, // 134: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 52, // 135: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 37, // 136: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 59, // 137: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 37, // 138: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 37, // 139: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 101, // 140: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 37, // 141: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 37, // 142: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 67, // 143: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 68, // 144: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 71, // 145: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 37, // 146: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 72, // 147: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 73, // 148: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 75, // 149: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 74, // 150: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 76, // 151: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult + 37, // 152: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 67, // 153: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 37, // 154: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 71, // 155: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 37, // 156: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 37, // 157: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 37, // 158: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 37, // 159: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 37, // 160: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 37, // 161: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 37, // 162: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 37, // 163: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 100, // 164: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 100, // 165: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 104, // 166: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 105, // 167: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 102, // 168: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 103, // 169: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 104, // 170: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 100, // 171: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 37, // 172: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 37, // 173: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 37, // 174: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 0, // 175: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 176: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 177: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 178: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 177, // [177:179] is the sub-list for method output_type + 175, // [175:177] is the sub-list for method input_type + 175, // [175:175] is the sub-list for extension type_name + 175, // [175:175] is the sub-list for extension extendee + 0, // [0:175] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -9609,7 +9664,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCError); i { + switch v := v.(*BlockHeadersMessage); i { case 0: return &v.state case 1: @@ -9621,7 +9676,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkRequestMessage); i { + switch v := v.(*RPCError); i { case 0: return &v.state case 1: @@ -9633,7 +9688,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkResponseMessage); i { + switch v := v.(*GetCurrentNetworkRequestMessage); i { case 0: return &v.state case 1: @@ -9645,7 +9700,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockRequestMessage); i { + switch v := v.(*GetCurrentNetworkResponseMessage); i { case 0: return &v.state case 1: @@ -9657,7 +9712,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockResponseMessage); i { + switch v := v.(*SubmitBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9669,7 +9724,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateRequestMessage); i { + switch v := v.(*SubmitBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9681,7 +9736,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateResponseMessage); i { + switch v := v.(*GetBlockTemplateRequestMessage); i { case 0: return &v.state case 1: @@ -9693,7 +9748,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedRequestMessage); i { + switch v := v.(*GetBlockTemplateResponseMessage); i { case 0: return &v.state case 1: @@ -9705,7 +9760,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedResponseMessage); i { + switch v := v.(*NotifyBlockAddedRequestMessage); i { case 0: return &v.state case 1: @@ -9717,7 +9772,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockAddedNotificationMessage); i { + switch v := v.(*NotifyBlockAddedResponseMessage); i { case 0: return &v.state case 1: @@ -9729,7 +9784,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesRequestMessage); i { + switch v := v.(*BlockAddedNotificationMessage); i { case 0: return &v.state case 1: @@ -9741,7 +9796,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesResponseMessage); i { + switch v := v.(*GetPeerAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -9753,7 +9808,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesKnownAddressMessage); i { + switch v := v.(*GetPeerAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -9765,7 +9820,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashRequestMessage); i { + switch v := v.(*GetPeerAddressesKnownAddressMessage); i { case 0: return &v.state case 1: @@ -9777,7 +9832,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashResponseMessage); i { + switch v := v.(*GetSelectedTipHashRequestMessage); i { case 0: return &v.state case 1: @@ -9789,7 +9844,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MempoolEntry); i { + switch v := v.(*GetSelectedTipHashResponseMessage); i { case 0: return &v.state case 1: @@ -9801,7 +9856,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryRequestMessage); i { + switch v := v.(*MempoolEntry); i { case 0: return &v.state case 1: @@ -9813,7 +9868,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryResponseMessage); i { + switch v := v.(*GetMempoolEntryRequestMessage); i { case 0: return &v.state case 1: @@ -9825,7 +9880,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesRequestMessage); i { + switch v := v.(*GetMempoolEntryResponseMessage); i { case 0: return &v.state case 1: @@ -9837,7 +9892,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesResponseMessage); i { + switch v := v.(*GetMempoolEntriesRequestMessage); i { case 0: return &v.state case 1: @@ -9849,7 +9904,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoRequestMessage); i { + switch v := v.(*GetMempoolEntriesResponseMessage); i { case 0: return &v.state case 1: @@ -9861,7 +9916,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoResponseMessage); i { + switch v := v.(*GetConnectedPeerInfoRequestMessage); i { case 0: return &v.state case 1: @@ -9873,7 +9928,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoMessage); i { + switch v := v.(*GetConnectedPeerInfoResponseMessage); i { case 0: return &v.state case 1: @@ -9885,7 +9940,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerRequestMessage); i { + switch v := v.(*GetConnectedPeerInfoMessage); i { case 0: return &v.state case 1: @@ -9897,7 +9952,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerResponseMessage); i { + switch v := v.(*AddPeerRequestMessage); i { case 0: return &v.state case 1: @@ -9909,7 +9964,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionRequestMessage); i { + switch v := v.(*AddPeerResponseMessage); i { case 0: return &v.state case 1: @@ -9921,7 +9976,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionResponseMessage); i { + switch v := v.(*SubmitTransactionRequestMessage); i { case 0: return &v.state case 1: @@ -9933,7 +9988,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { + switch v := v.(*SubmitTransactionResponseMessage); i { case 0: return &v.state case 1: @@ -9945,7 +10000,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { case 0: return &v.state case 1: @@ -9957,7 +10012,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { case 0: return &v.state case 1: @@ -9969,7 +10024,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainBlock); i { + switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -9981,7 +10036,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptedBlock); i { + switch v := v.(*ChainBlock); i { case 0: return &v.state case 1: @@ -9993,7 +10048,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockRequestMessage); i { + switch v := v.(*AcceptedBlock); i { case 0: return &v.state case 1: @@ -10005,7 +10060,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockResponseMessage); i { + switch v := v.(*GetBlockRequestMessage); i { case 0: return &v.state case 1: @@ -10017,7 +10072,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockVerboseData); i { + switch v := v.(*GetBlockResponseMessage); i { case 0: return &v.state case 1: @@ -10029,7 +10084,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseData); i { + switch v := v.(*BlockVerboseData); i { case 0: return &v.state case 1: @@ -10041,7 +10096,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseInput); i { + switch v := v.(*TransactionVerboseData); i { case 0: return &v.state case 1: @@ -10053,7 +10108,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptSig); i { + switch v := v.(*TransactionVerboseInput); i { case 0: return &v.state case 1: @@ -10065,7 +10120,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseOutput); i { + switch v := v.(*ScriptSig); i { case 0: return &v.state case 1: @@ -10077,7 +10132,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPubKeyResult); i { + switch v := v.(*TransactionVerboseOutput); i { case 0: return &v.state case 1: @@ -10089,7 +10144,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkRequestMessage); i { + switch v := v.(*ScriptPubKeyResult); i { case 0: return &v.state case 1: @@ -10101,7 +10156,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkResponseMessage); i { + switch v := v.(*GetSubnetworkRequestMessage); i { case 0: return &v.state case 1: @@ -10113,7 +10168,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { + switch v := v.(*GetSubnetworkResponseMessage); i { case 0: return &v.state case 1: @@ -10125,7 +10180,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { case 0: return &v.state case 1: @@ -10137,7 +10192,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { case 0: return &v.state case 1: @@ -10149,7 +10204,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksResponseMessage); i { + switch v := v.(*GetBlocksRequestMessage); i { case 0: return &v.state case 1: @@ -10161,7 +10216,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountRequestMessage); i { + switch v := v.(*GetBlocksResponseMessage); i { case 0: return &v.state case 1: @@ -10173,7 +10228,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountResponseMessage); i { + switch v := v.(*GetBlockCountRequestMessage); i { case 0: return &v.state case 1: @@ -10185,7 +10240,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoRequestMessage); i { + switch v := v.(*GetBlockCountResponseMessage); i { case 0: return &v.state case 1: @@ -10197,7 +10252,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoResponseMessage); i { + switch v := v.(*GetBlockDagInfoRequestMessage); i { case 0: return &v.state case 1: @@ -10209,7 +10264,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictRequestMessage); i { + switch v := v.(*GetBlockDagInfoResponseMessage); i { case 0: return &v.state case 1: @@ -10221,7 +10276,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictResponseMessage); i { + switch v := v.(*ResolveFinalityConflictRequestMessage); i { case 0: return &v.state case 1: @@ -10233,7 +10288,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsRequestMessage); i { + switch v := v.(*ResolveFinalityConflictResponseMessage); i { case 0: return &v.state case 1: @@ -10245,7 +10300,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsResponseMessage); i { + switch v := v.(*NotifyFinalityConflictsRequestMessage); i { case 0: return &v.state case 1: @@ -10257,7 +10312,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictNotificationMessage); i { + switch v := v.(*NotifyFinalityConflictsResponseMessage); i { case 0: return &v.state case 1: @@ -10269,7 +10324,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + switch v := v.(*FinalityConflictNotificationMessage); i { case 0: return &v.state case 1: @@ -10281,7 +10336,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownRequestMessage); i { + switch v := v.(*FinalityConflictResolvedNotificationMessage); i { case 0: return &v.state case 1: @@ -10293,7 +10348,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownResponseMessage); i { + switch v := v.(*ShutDownRequestMessage); i { case 0: return &v.state case 1: @@ -10305,7 +10360,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersRequestMessage); i { + switch v := v.(*ShutDownResponseMessage); i { case 0: return &v.state case 1: @@ -10317,7 +10372,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersResponseMessage); i { + switch v := v.(*GetHeadersRequestMessage); i { case 0: return &v.state case 1: @@ -10329,7 +10384,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedRequestMessage); i { + switch v := v.(*GetHeadersResponseMessage); i { case 0: return &v.state case 1: @@ -10341,7 +10396,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedResponseMessage); i { + switch v := v.(*NotifyUtxosChangedRequestMessage); i { case 0: return &v.state case 1: @@ -10353,7 +10408,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosChangedNotificationMessage); i { + switch v := v.(*NotifyUtxosChangedResponseMessage); i { case 0: return &v.state case 1: @@ -10365,7 +10420,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosByAddressesEntry); i { + switch v := v.(*UtxosChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -10377,7 +10432,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransaction); i { + switch v := v.(*UtxosByAddressesEntry); i { case 0: return &v.state case 1: @@ -10389,7 +10444,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionInput); i { + switch v := v.(*RpcTransaction); i { case 0: return &v.state case 1: @@ -10401,7 +10456,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionOutput); i { + switch v := v.(*RpcTransactionInput); i { case 0: return &v.state case 1: @@ -10413,7 +10468,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcOutpoint); i { + switch v := v.(*RpcTransactionOutput); i { case 0: return &v.state case 1: @@ -10425,7 +10480,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcUtxoEntry); i { + switch v := v.(*RpcOutpoint); i { case 0: return &v.state case 1: @@ -10437,7 +10492,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesRequestMessage); i { + switch v := v.(*RpcUtxoEntry); i { case 0: return &v.state case 1: @@ -10449,7 +10504,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesResponseMessage); i { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -10461,7 +10516,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -10473,7 +10528,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { case 0: return &v.state case 1: @@ -10485,7 +10540,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { case 0: return &v.state case 1: @@ -10497,7 +10552,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { case 0: return &v.state case 1: @@ -10509,6 +10564,18 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[112].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { case 0: return &v.state @@ -10542,7 +10609,6 @@ func file_messages_proto_init() { (*KaspadMessage_Version)(nil), (*KaspadMessage_TransactionNotFound)(nil), (*KaspadMessage_Reject)(nil), - (*KaspadMessage_BlockHeader)(nil), (*KaspadMessage_RequestIBDRootUTXOSetAndBlock)(nil), (*KaspadMessage_IbdRootUTXOSetAndBlock)(nil), (*KaspadMessage_RequestIBDBlocks)(nil), @@ -10551,6 +10617,7 @@ func file_messages_proto_init() { (*KaspadMessage_IbdRootHash)(nil), (*KaspadMessage_IbdBlockLocator)(nil), (*KaspadMessage_IbdBlockLocatorHighestHash)(nil), + (*KaspadMessage_BlockHeaders)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), @@ -10616,7 +10683,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 112, + NumMessages: 113, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 77673afd8..283ab4448 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -25,7 +25,6 @@ message KaspadMessage { VersionMessage version = 20; TransactionNotFoundMessage transactionNotFound = 21; RejectMessage reject = 22; - BlockHeaderMessage blockHeader = 23; RequestIBDRootUTXOSetAndBlockMessage requestIBDRootUTXOSetAndBlock = 24; IBDRootUTXOSetAndBlockMessage ibdRootUTXOSetAndBlock = 25; RequestIBDBlocksMessage requestIBDBlocks = 26; @@ -34,6 +33,7 @@ message KaspadMessage { IBDRootHashMessage ibdRootHash = 29; IbdBlockLocatorMessage ibdBlockLocator = 30; IbdBlockLocatorHighestHashMessage ibdBlockLocatorHighestHash = 31; + BlockHeadersMessage blockHeaders = 32; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; @@ -325,6 +325,10 @@ message IbdBlockLocatorHighestHashMessage { } // IbdBlockLocatorHighestHashMessage end +message BlockHeadersMessage { + repeated BlockHeaderMessage blockHeaders = 1; +} + service P2P { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block_headers.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block_headers.go new file mode 100644 index 000000000..dcf577a91 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_block_headers.go @@ -0,0 +1,34 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_BlockHeaders) toAppMessage() (appmessage.Message, error) { + blockHeaders := make([]*appmessage.MsgBlockHeader, len(x.BlockHeaders.BlockHeaders)) + for i, blockHeader := range x.BlockHeaders.BlockHeaders { + var err error + blockHeaders[i], err = blockHeader.toAppMessage() + if err != nil { + return nil, err + } + } + + return &appmessage.BlockHeadersMessage{ + BlockHeaders: blockHeaders, + }, nil +} + +func (x *KaspadMessage_BlockHeaders) fromAppMessage(blockHeadersMessage *appmessage.BlockHeadersMessage) error { + blockHeaders := make([]*BlockHeaderMessage, len(blockHeadersMessage.BlockHeaders)) + for i, blockHeader := range blockHeadersMessage.BlockHeaders { + blockHeaders[i] = &BlockHeaderMessage{} + err := blockHeaders[i].fromAppMessage(blockHeader) + if err != nil { + return err + } + } + + x.BlockHeaders = &BlockHeadersMessage{ + BlockHeaders: blockHeaders, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go index 6de033e1d..17487ad28 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go @@ -6,15 +6,6 @@ import ( "github.com/pkg/errors" ) -func (x *KaspadMessage_BlockHeader) toAppMessage() (appmessage.Message, error) { - return x.BlockHeader.toAppMessage() -} - -func (x *KaspadMessage_BlockHeader) fromAppMessage(msgBlockHeader *appmessage.MsgBlockHeader) error { - x.BlockHeader = new(BlockHeaderMessage) - return x.BlockHeader.fromAppMessage(msgBlockHeader) -} - func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) { if len(x.ParentHashes) > appmessage.MaxBlockParents { return nil, errors.Errorf("block header has %d parents, but the maximum allowed amount "+ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index b6985e7df..fff7537c2 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -195,13 +195,6 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgBlockHeader: - payload := new(KaspadMessage_BlockHeader) - err := payload.fromAppMessage(message) - if err != nil { - return nil, err - } - return payload, nil case *appmessage.MsgRequestIBDRootUTXOSetAndBlock: payload := new(KaspadMessage_RequestIBDRootUTXOSetAndBlock) err := payload.fromAppMessage(message) @@ -258,6 +251,13 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.BlockHeadersMessage: + payload := new(KaspadMessage_BlockHeaders) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil default: return nil, nil } From 778375c4afca3edc482ee2b50ac9d2968982454b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 4 Jan 2021 14:15:51 +0200 Subject: [PATCH 202/351] Add recoverability for UTXO index (#1342) * Add recoverability for UTXO index * Add comment * Rename UTXOOutpointPair->OutpointUTXOPair * Get rid of the db transaction on resetStore and collect all keys before deleting * Use VirtualSelectedParent instead of selected tip * Fix error --- app/component_manager.go | 5 +- domain/consensus/consensus.go | 22 ++++ .../consensus/model/externalapi/consensus.go | 2 + domain/consensus/model/externalapi/utxo.go | 7 ++ domain/utxoindex/store.go | 107 +++++++++++++++++- domain/utxoindex/utxoindex.go | 78 ++++++++++++- 6 files changed, 210 insertions(+), 11 deletions(-) create mode 100644 domain/consensus/model/externalapi/utxo.go diff --git a/app/component_manager.go b/app/component_manager.go index f3efe34e9..b2889740d 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -96,7 +96,10 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, var utxoIndex *utxoindex.UTXOIndex if cfg.UTXOIndex { - utxoIndex = utxoindex.New(domain.Consensus(), db) + utxoIndex, err = utxoindex.New(domain.Consensus(), db, cfg.ActiveNetParams.GenesisHash) + if err != nil { + return nil, err + } log.Infof("UTXO index started") } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 614d19b97..f4e77bf90 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -372,3 +372,25 @@ func (s *consensus) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { return s.headersSelectedTipStore.HeadersSelectedTip(s.databaseContext) } + +func (s *consensus) GetVirtualUTXOSet() ([]*externalapi.OutpointUTXOPair, error) { + s.lock.Lock() + defer s.lock.Unlock() + + iterator, err := s.consensusStateStore.VirtualUTXOSetIterator(s.databaseContext) + if err != nil { + return nil, err + } + + pairs := make([]*externalapi.OutpointUTXOPair, 0) + for iterator.Next() { + outpoint, entry, err := iterator.Get() + if err != nil { + return nil, err + } + + pairs = append(pairs, &externalapi.OutpointUTXOPair{Outpoint: outpoint, Entry: entry}) + } + + return pairs, nil +} diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 8921d9a28..72b51ab4f 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -26,4 +26,6 @@ type Consensus interface { GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) IsInSelectedParentChainOf(blockHashA *DomainHash, blockHashB *DomainHash) (bool, error) GetHeadersSelectedTip() (*DomainHash, error) + + GetVirtualUTXOSet() ([]*OutpointUTXOPair, error) } diff --git a/domain/consensus/model/externalapi/utxo.go b/domain/consensus/model/externalapi/utxo.go new file mode 100644 index 000000000..4af652fc0 --- /dev/null +++ b/domain/consensus/model/externalapi/utxo.go @@ -0,0 +1,7 @@ +package externalapi + +// OutpointUTXOPair is a pair of outpoint and UTXO entry +type OutpointUTXOPair struct { + Outpoint *DomainOutpoint + Entry UTXOEntry +} diff --git a/domain/utxoindex/store.go b/domain/utxoindex/store.go index 67d985038..b049c8a6f 100644 --- a/domain/utxoindex/store.go +++ b/domain/utxoindex/store.go @@ -10,11 +10,13 @@ import ( ) var utxoIndexBucket = database.MakeBucket([]byte("utxo-index")) +var utxoIndexLastVirtualSelectedParentKey = database.MakeBucket().Key([]byte("utxo-index-last-virtual-selected-parent")) type utxoIndexStore struct { - database database.Database - toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs - toRemove map[ScriptPublicKeyString]UTXOOutpoints + database database.Database + toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs + toRemove map[ScriptPublicKeyString]UTXOOutpoints + virtualSelectedParent *externalapi.DomainHash } func newUTXOIndexStore(database database.Database) *utxoIndexStore { @@ -96,6 +98,7 @@ func (uis *utxoIndexStore) remove(scriptPublicKey []byte, outpoint *externalapi. func (uis *utxoIndexStore) discard() { uis.toAdd = make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs) uis.toRemove = make(map[ScriptPublicKeyString]UTXOOutpoints) + uis.virtualSelectedParent = nil } func (uis *utxoIndexStore) commit() error { @@ -142,6 +145,11 @@ func (uis *utxoIndexStore) commit() error { } } + err = dbTransaction.Put(utxoIndexLastVirtualSelectedParentKey, uis.virtualSelectedParent.ByteSlice()) + if err != nil { + return err + } + err = dbTransaction.Commit() if err != nil { return err @@ -222,7 +230,7 @@ func (uis *utxoIndexStore) stagedData() ( } func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) { - if len(uis.toAdd) > 0 || len(uis.toRemove) > 0 { + if uis.isAnythingStaged() { return nil, errors.Errorf("cannot get utxo outpoint entry pairs while staging isn't empty") } @@ -253,3 +261,94 @@ func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey []byte) (UT } return utxoOutpointEntryPairs, nil } + +func (uis *utxoIndexStore) getLastVirtualSelectedParent() (*externalapi.DomainHash, bool, error) { + if uis.isAnythingStaged() { + return nil, false, errors.Errorf("cannot get last virtual selected parent while staging isn't empty") + } + + hasLastVirtualSelectedParent, err := uis.database.Has(utxoIndexLastVirtualSelectedParentKey) + if err != nil { + return nil, false, err + } + + if !hasLastVirtualSelectedParent { + return nil, false, nil + } + + lastVirtualSelectedParentBytes, err := uis.database.Get(utxoIndexLastVirtualSelectedParentKey) + if err != nil { + return nil, false, err + } + + lastVirtualSelectedParent, err := externalapi.NewDomainHashFromByteSlice(lastVirtualSelectedParentBytes) + if err != nil { + return nil, false, err + } + + return lastVirtualSelectedParent, true, nil +} + +func (uis *utxoIndexStore) isAnythingStaged() bool { + return len(uis.toAdd) > 0 || len(uis.toRemove) > 0 || uis.virtualSelectedParent != nil +} + +func (uis *utxoIndexStore) replaceUTXOSet(utxoSet []*externalapi.OutpointUTXOPair, + virtualSelectedParent *externalapi.DomainHash) error { + + onEnd := logger.LogAndMeasureExecutionTime(log, "utxoIndexStore.replaceUTXOSet") + defer onEnd() + + if uis.isAnythingStaged() { + return errors.Errorf("cannot replace utxo set while something is staged") + } + + err := uis.resetStore() + if err != nil { + return err + } + + uis.virtualSelectedParent = virtualSelectedParent + for _, pair := range utxoSet { + err := uis.add(pair.Entry.ScriptPublicKey(), pair.Outpoint, pair.Entry) + if err != nil { + return err + } + } + + return uis.commit() +} + +func (uis *utxoIndexStore) resetStore() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "utxoIndexStore.resetStore") + defer onEnd() + + cursor, err := uis.database.Cursor(utxoIndexBucket) + if err != nil { + return err + } + + keysToDelete := make([]*database.Key, 0) + for cursor.Next() { + key, err := cursor.Key() + if err != nil { + return err + } + + keysToDelete = append(keysToDelete, key) + } + + for _, key := range keysToDelete { + err = uis.database.Delete(key) + if err != nil { + return err + } + } + + err = uis.database.Delete(utxoIndexLastVirtualSelectedParentKey) + if err != nil { + return err + } + + return nil +} diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go index e4292e567..c538a29ac 100644 --- a/domain/utxoindex/utxoindex.go +++ b/domain/utxoindex/utxoindex.go @@ -7,25 +7,80 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" "sync" ) // UTXOIndex maintains an index between transaction scriptPublicKeys // and UTXOs type UTXOIndex struct { - consensus externalapi.Consensus - store *utxoIndexStore + consensus externalapi.Consensus + store *utxoIndexStore + genesisHash *externalapi.DomainHash mutex sync.Mutex } // New creates a new UTXO index -func New(consensus externalapi.Consensus, database database.Database) *UTXOIndex { +func New(consensus externalapi.Consensus, database database.Database, genesisHash *externalapi.DomainHash) (*UTXOIndex, error) { store := newUTXOIndexStore(database) - return &UTXOIndex{ - consensus: consensus, - store: store, + utxoIndex := &UTXOIndex{ + consensus: consensus, + store: store, + genesisHash: genesisHash, } + + isSynced, err := utxoIndex.isSynced() + if err != nil { + return nil, err + } + + if !isSynced { + err := utxoIndex.recover() + if err != nil { + return nil, err + } + } + + return utxoIndex, nil +} + +func (ui *UTXOIndex) recover() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.recover") + defer onEnd() + + // Since the RPC and P2P should be down while initializing the + // UTXO index, we can assume that the virtual selected parent + // won't be changed while fetching the virtual selected parent. + virtualSelectedParent, err := ui.consensus.GetVirtualSelectedParent() + if err != nil { + return err + } + + virtualUTXOSet, err := ui.consensus.GetVirtualUTXOSet() + if err != nil { + return err + } + + return ui.store.replaceUTXOSet(virtualUTXOSet, virtualSelectedParent) +} + +func (ui *UTXOIndex) isSynced() (bool, error) { + virtualSelectedParent, err := ui.consensus.GetVirtualSelectedParent() + if err != nil { + return false, err + } + + lastVirtualSelectedParent, hasLastVirtualSelectedParent, err := ui.store.getLastVirtualSelectedParent() + if err != nil { + return false, err + } + + if !hasLastVirtualSelectedParent { + return virtualSelectedParent.Equal(ui.genesisHash), nil + } + + return virtualSelectedParent.Equal(lastVirtualSelectedParent), nil } // Update updates the UTXO index with the given DAG selected parent chain changes @@ -37,6 +92,17 @@ func (ui *UTXOIndex) Update(chainChanges *externalapi.SelectedParentChainChanges defer ui.mutex.Unlock() log.Tracef("Updating UTXO index with chainChanges: %+v", chainChanges) + if len(chainChanges.Added) == 0 { + if len(chainChanges.Removed) != 0 { + return nil, errors.Errorf("len(chainChanges.Added) is 0 while len(chainChanges.Removed) is %d", len(chainChanges.Removed)) + } + + return nil, nil + } + + virtualSelectedParent := chainChanges.Added[len(chainChanges.Added)-1] + ui.store.virtualSelectedParent = virtualSelectedParent + for _, removedBlockHash := range chainChanges.Removed { err := ui.removeBlock(removedBlockHash) if err != nil { From 789a7379bddba937ac3f09daa7dab8dca054f385 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 4 Jan 2021 15:55:08 +0200 Subject: [PATCH 203/351] Require only inputs not be prefilled (#1345) * bug invalidateAndInsertPruningPoint: if ValidateAndInsertBlock returned a non-RuleError error - the error was ignored * Convert checkNoPrefilledFields into checkNoPrefilledInputs * Add log line * clone pruning point when passing to validateBlockTransactionsAgainstPastUTXO --- .../validateandinsertpruningpoint.go | 16 +++++++--------- .../blockvalidator/block_body_in_isolation.go | 16 ++-------------- .../consensusstatemanager/calculate_past_utxo.go | 4 +++- .../update_pruning_utxo_set.go | 6 +++++- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go index db0144053..b09e1ea81 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go @@ -36,14 +36,12 @@ func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externa log.Infof("Inserting the new pruning point %s", newPruningPointHash) _, err = bp.validateAndInsertBlock(newPruningPoint, true) - if err != nil { - if errors.As(err, &ruleerrors.RuleError{}) { - // This should never happen because we already validated the block with bp.validateBlockAndDiscardChanges. - // We use Errorf so it won't be identified later on to be a rule error and will eventually cause - // the program to panic. - return errors.Errorf("validateAndInsertBlock returned unexpected rule error while processing "+ - "the pruning point: %+v", err) - } + if err != nil && errors.As(err, &ruleerrors.RuleError{}) { + // This should never happen because we already validated the block with bp.validateBlockAndDiscardChanges. + // We use Errorf so it won't be identified later on to be a rule error and will eventually cause + // the program to panic. + return errors.Errorf("validateAndInsertBlock returned unexpected rule error while processing "+ + "the pruning point: %+v", err) } - return nil + return err } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 4c3cf18d2..3c1bdb48b 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -23,7 +23,7 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa return err } - err = v.checkNoPrefilledFields(block) + err = v.checkNoPrefilledInputs(block) if err != nil { return err } @@ -230,20 +230,8 @@ func (v *blockValidator) checkBlockSize(block *externalapi.DomainBlock) error { return nil } -func (v *blockValidator) checkNoPrefilledFields(block *externalapi.DomainBlock) error { +func (v *blockValidator) checkNoPrefilledInputs(block *externalapi.DomainBlock) error { for _, tx := range block.Transactions { - if tx.Fee != 0 { - return errors.Errorf("transaction %s has a prefilled fee", consensushashing.TransactionID(tx)) - } - - if tx.Mass != 0 { - return errors.Errorf("transaction %s has a prefilled mass", consensushashing.TransactionID(tx)) - } - - if tx.ID != nil { - return errors.Errorf("transaction %s has a prefilled ID", consensushashing.TransactionID(tx)) - } - for i, input := range tx.Inputs { if input.UTXOEntry != nil { return errors.Errorf("input %d in transaction %s has a prefilled UTXO entry", diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 711afe6ba..349f1ba5d 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -115,7 +115,9 @@ func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.Dom log.Debugf("applyMergeSetBlocks start for block %s", blockHash) defer log.Tracef("applyMergeSetBlocks end for block %s", blockHash) - mergeSetBlocks, err := csm.blockStore.Blocks(csm.databaseContext, ghostdagData.MergeSet()) + mergeSetHashes := ghostdagData.MergeSet() + log.Debugf("Merge set for block %s is %v", blockHash, mergeSetHashes) + mergeSetBlocks, err := csm.blockStore.Blocks(csm.databaseContext, mergeSetHashes) if err != nil { return nil, nil, err } diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index 12f02844b..f20d9a215 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -108,7 +108,11 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap // Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid // against the provided UTXO set. log.Debugf("Validating that the pruning point is UTXO valid") - err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint, utxo.NewUTXODiff()) + + // validateBlockTransactionsAgainstPastUTXO pre-fills the block's transactions inputs, which + // are assumed to not be pre-filled during further validations. + // Therefore - clone newPruningPoint before passing it to validateBlockTransactionsAgainstPastUTXO + err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint.Clone(), utxo.NewUTXODiff()) if err != nil { return err } From 0fb97a4f37d8268390872e1581e5e94ff8707724 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 4 Jan 2021 17:04:13 +0200 Subject: [PATCH 204/351] Add logs (#1346) * Add logs * Fix logInterval to const --- domain/consensus/consensus.go | 4 ++++ domain/utxoindex/store.go | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index f4e77bf90..d45addf63 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -2,6 +2,7 @@ package consensus import ( "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/kaspanet/kaspad/infrastructure/logger" "sync" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -374,6 +375,9 @@ func (s *consensus) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { } func (s *consensus) GetVirtualUTXOSet() ([]*externalapi.OutpointUTXOPair, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "consensus.GetVirtualUTXOSet") + defer onEnd() + s.lock.Lock() defer s.lock.Unlock() diff --git a/domain/utxoindex/store.go b/domain/utxoindex/store.go index b049c8a6f..e2e8e4b9f 100644 --- a/domain/utxoindex/store.go +++ b/domain/utxoindex/store.go @@ -309,11 +309,15 @@ func (uis *utxoIndexStore) replaceUTXOSet(utxoSet []*externalapi.OutpointUTXOPai } uis.virtualSelectedParent = virtualSelectedParent - for _, pair := range utxoSet { + for i, pair := range utxoSet { err := uis.add(pair.Entry.ScriptPublicKey(), pair.Outpoint, pair.Entry) if err != nil { return err } + const logInterval = 10_000 + if i%logInterval == 0 { + log.Debugf("Recovered %d UTXO entries out of %d", i+1, len(utxoSet)) + } } return uis.commit() From e509cb1597aa7bab8ec3e75f2f5537a079befbb5 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 5 Jan 2021 12:13:02 +0200 Subject: [PATCH 205/351] Smal performance improvements to BlueWindow (#1343) * Convert BlockGHOSTDAGData from an interface to a public struct with getters * Move hashes.Less to externalapi so it can access the hashes directly without copying * Reduce calls to ghostdagstore.Get in blueWindow * Simplify the logic in RequiredDifficulty and reuse big.Int * Remove bigintpool as its no longer used * Use ChooseSelectedParent in RequiredDifficulty instead of looping over the parents * Remove comment --- .../serialization/block_ghostdag_data.go | 7 +- .../ghostdagdatastore/ghostdagdatastore.go | 16 ++-- domain/consensus/model/externalapi/hash.go | 18 +++++ domain/consensus/model/ghostdag.go | 80 ++++++++++++++++--- ...erface_datastructures_ghostdagdatastore.go | 4 +- .../interface_processes_ghostdagmanager.go | 4 +- .../calculate_past_utxo.go | 2 +- .../consensusstatemanager/multisets.go | 2 +- .../dagtraversalmanager/block_heap.go | 19 +++-- .../processes/dagtraversalmanager/window.go | 11 +-- .../difficultymanager/blockwindow.go | 18 ++--- .../difficultymanager/difficultymanager.go | 38 +++------ .../processes/ghostdag2/ghostdagimpl.go | 8 +- .../processes/ghostdagmanager/compare.go | 8 +- .../processes/ghostdagmanager/ghostdag.go | 27 +++++-- .../ghostdagmanager/ghostdag_data.go | 69 ---------------- .../ghostdagmanager/ghostdag_test.go | 12 +-- domain/consensus/utils/hashes/compare.go | 31 ------- .../consensus/utils/transactionid/compare.go | 3 +- util/bigintpool/pool.go | 25 ------ 20 files changed, 170 insertions(+), 232 deletions(-) delete mode 100644 domain/consensus/processes/ghostdagmanager/ghostdag_data.go delete mode 100644 domain/consensus/utils/hashes/compare.go delete mode 100644 util/bigintpool/pool.go diff --git a/domain/consensus/database/serialization/block_ghostdag_data.go b/domain/consensus/database/serialization/block_ghostdag_data.go index 29f9df9d6..f6afc6e29 100644 --- a/domain/consensus/database/serialization/block_ghostdag_data.go +++ b/domain/consensus/database/serialization/block_ghostdag_data.go @@ -3,12 +3,11 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" "math/big" ) // BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData -func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) *DbBlockGhostdagData { +func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) *DbBlockGhostdagData { var selectedParent *DbHash if blockGHOSTDAGData.SelectedParent() != nil { selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent()) @@ -25,7 +24,7 @@ func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDA } // DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData -func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (model.BlockGHOSTDAGData, error) { +func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (*model.BlockGHOSTDAGData, error) { var selectedParent *externalapi.DomainHash if dbBlockGHOSTDAGData.SelectedParent != nil { var err error @@ -50,7 +49,7 @@ func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdag return nil, err } - return ghostdagmanager.NewBlockGHOSTDAGData( + return model.NewBlockGHOSTDAGData( dbBlockGHOSTDAGData.BlueScore, new(big.Int).SetBytes(dbBlockGHOSTDAGData.BlueWork), selectedParent, diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index c8b1a7c01..8c61ba06d 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -13,20 +13,20 @@ var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data")) // ghostdagDataStore represents a store of BlockGHOSTDAGData type ghostdagDataStore struct { - staging map[externalapi.DomainHash]model.BlockGHOSTDAGData + staging map[externalapi.DomainHash]*model.BlockGHOSTDAGData cache *lrucache.LRUCache } // New instantiates a new GHOSTDAGDataStore func New(cacheSize int) model.GHOSTDAGDataStore { return &ghostdagDataStore{ - staging: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData), + staging: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), cache: lrucache.New(cacheSize), } } // Stage stages the given blockGHOSTDAGData for the given blockHash -func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) { +func (gds *ghostdagDataStore) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { gds.staging[*blockHash] = blockGHOSTDAGData } @@ -35,7 +35,7 @@ func (gds *ghostdagDataStore) IsStaged() bool { } func (gds *ghostdagDataStore) Discard() { - gds.staging = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) + gds.staging = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) } func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { @@ -56,13 +56,13 @@ func (gds *ghostdagDataStore) Commit(dbTx model.DBTransaction) error { } // Get gets the blockGHOSTDAGData associated with the given blockHash -func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) { +func (gds *ghostdagDataStore) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { if blockGHOSTDAGData, ok := gds.staging[*blockHash]; ok { return blockGHOSTDAGData, nil } if blockGHOSTDAGData, ok := gds.cache.Get(blockHash); ok { - return blockGHOSTDAGData.(model.BlockGHOSTDAGData), nil + return blockGHOSTDAGData.(*model.BlockGHOSTDAGData), nil } blockGHOSTDAGDataBytes, err := dbContext.Get(gds.hashAsKey(blockHash)) @@ -82,11 +82,11 @@ func (gds *ghostdagDataStore) hashAsKey(hash *externalapi.DomainHash) model.DBKe return bucket.Key(hash.ByteSlice()) } -func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData model.BlockGHOSTDAGData) ([]byte, error) { +func (gds *ghostdagDataStore) serializeBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) ([]byte, error) { return proto.Marshal(serialization.BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData)) } -func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (model.BlockGHOSTDAGData, error) { +func (gds *ghostdagDataStore) deserializeBlockGHOSTDAGData(blockGHOSTDAGDataBytes []byte) (*model.BlockGHOSTDAGData, error) { dbBlockGHOSTDAGData := &serialization.DbBlockGhostdagData{} err := proto.Unmarshal(blockGHOSTDAGDataBytes, dbBlockGHOSTDAGData) if err != nil { diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index 02317d888..b6baa24e7 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -105,3 +105,21 @@ func HashesEqual(a, b []*DomainHash) bool { } return true } + +func cmp(a, b *DomainHash) int { + // We compare the hashes backwards because Hash is stored as a little endian byte array. + for i := DomainHashSize - 1; i >= 0; i-- { + switch { + case a.hashArray[i] < b.hashArray[i]: + return -1 + case a.hashArray[i] > b.hashArray[i]: + return 1 + } + } + return 0 +} + +// Less returns true iff hash a is less than hash b +func Less(a, b *DomainHash) bool { + return cmp(a, b) < 0 +} diff --git a/domain/consensus/model/ghostdag.go b/domain/consensus/model/ghostdag.go index efe5be5c9..5b77cd83d 100644 --- a/domain/consensus/model/ghostdag.go +++ b/domain/consensus/model/ghostdag.go @@ -6,16 +6,74 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// BlockGHOSTDAGData represents GHOSTDAG data for some block -type BlockGHOSTDAGData interface { - BlueScore() uint64 - BlueWork() *big.Int - SelectedParent() *externalapi.DomainHash - MergeSetBlues() []*externalapi.DomainHash - MergeSetReds() []*externalapi.DomainHash - MergeSet() []*externalapi.DomainHash - BluesAnticoneSizes() map[externalapi.DomainHash]KType -} - // KType defines the size of GHOSTDAG consensus algorithm K parameter. type KType byte + +// BlockGHOSTDAGData represents GHOSTDAG data for some block +type BlockGHOSTDAGData struct { + blueScore uint64 + blueWork *big.Int + selectedParent *externalapi.DomainHash + mergeSetBlues []*externalapi.DomainHash + mergeSetReds []*externalapi.DomainHash + bluesAnticoneSizes map[externalapi.DomainHash]KType +} + +// NewBlockGHOSTDAGData creates a new instance of BlockGHOSTDAGData +func NewBlockGHOSTDAGData( + blueScore uint64, + blueWork *big.Int, + selectedParent *externalapi.DomainHash, + mergeSetBlues []*externalapi.DomainHash, + mergeSetReds []*externalapi.DomainHash, + bluesAnticoneSizes map[externalapi.DomainHash]KType) *BlockGHOSTDAGData { + + return &BlockGHOSTDAGData{ + blueScore: blueScore, + blueWork: blueWork, + selectedParent: selectedParent, + mergeSetBlues: mergeSetBlues, + mergeSetReds: mergeSetReds, + bluesAnticoneSizes: bluesAnticoneSizes, + } +} + +// BlueScore returns the BlueScore of the block +func (bgd *BlockGHOSTDAGData) BlueScore() uint64 { + return bgd.blueScore +} + +// BlueWork returns the BlueWork of the block +func (bgd *BlockGHOSTDAGData) BlueWork() *big.Int { + return bgd.blueWork +} + +// SelectedParent returns the SelectedParent of the block +func (bgd *BlockGHOSTDAGData) SelectedParent() *externalapi.DomainHash { + return bgd.selectedParent +} + +// MergeSetBlues returns the MergeSetBlues of the block (not a copy) +func (bgd *BlockGHOSTDAGData) MergeSetBlues() []*externalapi.DomainHash { + return bgd.mergeSetBlues +} + +// MergeSetReds returns the MergeSetReds of the block (not a copy) +func (bgd *BlockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash { + return bgd.mergeSetReds +} + +// BluesAnticoneSizes returns a map between the blocks in its MergeSetBlues and the size of their anticone +func (bgd *BlockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]KType { + return bgd.bluesAnticoneSizes +} + +// MergeSet returns the whole MergeSet of the block (equivalent to MergeSetBlues+MergeSetReds) +func (bgd *BlockGHOSTDAGData) MergeSet() []*externalapi.DomainHash { + mergeSet := make([]*externalapi.DomainHash, len(bgd.mergeSetBlues)+len(bgd.mergeSetReds)) + copy(mergeSet, bgd.mergeSetBlues) + if len(bgd.mergeSetReds) > 0 { + copy(mergeSet[len(bgd.mergeSetBlues):], bgd.mergeSetReds) + } + return mergeSet +} diff --git a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go index 4e20e3408..13522feb1 100644 --- a/domain/consensus/model/interface_datastructures_ghostdagdatastore.go +++ b/domain/consensus/model/interface_datastructures_ghostdagdatastore.go @@ -5,7 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // GHOSTDAGDataStore represents a store of BlockGHOSTDAGData type GHOSTDAGDataStore interface { Store - Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData BlockGHOSTDAGData) + Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *BlockGHOSTDAGData) IsStaged() bool - Get(dbContext DBReader, blockHash *externalapi.DomainHash) (BlockGHOSTDAGData, error) + Get(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockGHOSTDAGData, error) } diff --git a/domain/consensus/model/interface_processes_ghostdagmanager.go b/domain/consensus/model/interface_processes_ghostdagmanager.go index 1222d5565..f7cbab390 100644 --- a/domain/consensus/model/interface_processes_ghostdagmanager.go +++ b/domain/consensus/model/interface_processes_ghostdagmanager.go @@ -6,6 +6,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type GHOSTDAGManager interface { GHOSTDAG(blockHash *externalapi.DomainHash) error ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) - Less(blockHashA *externalapi.DomainHash, ghostdagDataA BlockGHOSTDAGData, - blockHashB *externalapi.DomainHash, ghostdagDataB BlockGHOSTDAGData) bool + Less(blockHashA *externalapi.DomainHash, ghostdagDataA *BlockGHOSTDAGData, + blockHashB *externalapi.DomainHash, ghostdagDataB *BlockGHOSTDAGData) bool } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 349f1ba5d..eccd1cc80 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -109,7 +109,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH } func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.DomainHash, - selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData model.BlockGHOSTDAGData) ( + selectedParentPastUTXODiff model.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData) ( externalapi.AcceptanceData, model.MutableUTXODiff, error) { log.Debugf("applyMergeSetBlocks start for block %s", blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index 644e4f687..8099ed49b 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -10,7 +10,7 @@ import ( ) func (csm *consensusStateManager) calculateMultiset( - acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData model.BlockGHOSTDAGData) (model.Multiset, error) { + acceptanceData externalapi.AcceptanceData, blockGHOSTDAGData *model.BlockGHOSTDAGData) (model.Multiset, error) { log.Debugf("calculateMultiset start for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) defer log.Debugf("calculateMultiset end for block with selected parent %s", blockGHOSTDAGData.SelectedParent()) diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go index a305e97f2..46b099c3b 100644 --- a/domain/consensus/processes/dagtraversalmanager/block_heap.go +++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go @@ -9,7 +9,7 @@ import ( type blockHeapNode struct { hash *externalapi.DomainHash - ghostdagData model.BlockGHOSTDAGData + ghostdagData *model.BlockGHOSTDAGData } func (left *blockHeapNode) less(right *blockHeapNode, gm model.GHOSTDAGManager) bool { @@ -152,12 +152,8 @@ func (sbh *sizedUpBlockHeap) pop() *externalapi.DomainHash { return heap.Pop(&sbh.impl).(*blockHeapNode).hash } -// tryPush tries to push the block onto the heap, if the heap is full and it's less than the minimum it rejects it -func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, error) { - ghostdagData, err := sbh.ghostdagStore.Get(sbh.dbContext, blockHash) - if err != nil { - return false, err - } +// tryPushWithGHOSTDAGData is just like tryPush but the caller provides the ghostdagData of the block. +func (sbh *sizedUpBlockHeap) tryPushWithGHOSTDAGData(blockHash *externalapi.DomainHash, ghostdagData *model.BlockGHOSTDAGData) (bool, error) { node := &blockHeapNode{ hash: blockHash, ghostdagData: ghostdagData, @@ -173,3 +169,12 @@ func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, e heap.Push(&sbh.impl, node) return true, nil } + +// tryPush tries to push the block onto the heap, if the heap is full and it's less than the minimum it rejects it +func (sbh *sizedUpBlockHeap) tryPush(blockHash *externalapi.DomainHash) (bool, error) { + ghostdagData, err := sbh.ghostdagStore.Get(sbh.dbContext, blockHash) + if err != nil { + return false, err + } + return sbh.tryPushWithGHOSTDAGData(blockHash, ghostdagData) +} diff --git a/domain/consensus/processes/dagtraversalmanager/window.go b/domain/consensus/processes/dagtraversalmanager/window.go index b2c6439c9..a8d806a78 100644 --- a/domain/consensus/processes/dagtraversalmanager/window.go +++ b/domain/consensus/processes/dagtraversalmanager/window.go @@ -18,7 +18,11 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash windowHeap := dtm.newSizedUpHeap(windowSize) for windowHeap.len() <= windowSize && currentGHOSTDAGData.SelectedParent() != nil { - added, err := windowHeap.tryPush(currentGHOSTDAGData.SelectedParent()) + selectedParentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentGHOSTDAGData.SelectedParent()) + if err != nil { + return nil, err + } + added, err := windowHeap.tryPushWithGHOSTDAGData(currentGHOSTDAGData.SelectedParent(), selectedParentGHOSTDAGData) if err != nil { return nil, err } @@ -55,10 +59,7 @@ func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash } } currentHash = currentGHOSTDAGData.SelectedParent() - currentGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) - if err != nil { - return nil, err - } + currentGHOSTDAGData = selectedParentGHOSTDAGData } window := make([]*externalapi.DomainHash, 0, windowSize) diff --git a/domain/consensus/processes/difficultymanager/blockwindow.go b/domain/consensus/processes/difficultymanager/blockwindow.go index 3f795f140..9f070f286 100644 --- a/domain/consensus/processes/difficultymanager/blockwindow.go +++ b/domain/consensus/processes/difficultymanager/blockwindow.go @@ -3,7 +3,6 @@ package difficultymanager import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/util" - "github.com/kaspanet/kaspad/util/bigintpool" "github.com/pkg/errors" "math" "math/big" @@ -72,19 +71,14 @@ func (window *blockWindow) remove(n int) { *window = (*window)[:len(*window)-1] } -func (window blockWindow) averageTarget(averageTarget *big.Int) { - averageTarget.SetInt64(0) - - target := bigintpool.Acquire(0) - defer bigintpool.Release(target) +func (window blockWindow) averageTarget() *big.Int { + averageTarget := new(big.Int) + targetTmp := new(big.Int) for _, block := range window { - util.CompactToBigWithDestination(block.Bits, target) - averageTarget.Add(averageTarget, target) + util.CompactToBigWithDestination(block.Bits, targetTmp) + averageTarget.Add(averageTarget, targetTmp) } - - windowLen := bigintpool.Acquire(int64(len(window))) - defer bigintpool.Release(windowLen) - averageTarget.Div(averageTarget, windowLen) + return averageTarget.Div(averageTarget, big.NewInt(int64(len(window)))) } func (window blockWindow) medianTimestamp() (int64, error) { diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index 87939a8da..c82a6716a 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -7,7 +7,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/util" - "github.com/kaspanet/kaspad/util/bigintpool" ) // DifficultyManager provides a method to resolve the @@ -74,24 +73,13 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas } // find bluestParent - bluestParent := parents[0] - bluestGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, bluestParent) + bluestParent, err := dm.ghostdagManager.ChooseSelectedParent(parents...) if err != nil { return 0, err } - for i := 1; i < len(parents); i++ { - parentGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, parents[i]) - if err != nil { - return 0, err - } - newBluest, err := dm.ghostdagManager.ChooseSelectedParent(bluestParent, parents[i]) - if err != nil { - return 0, err - } - if bluestParent != newBluest { - bluestParent = newBluest - bluestGhostDAG = parentGhostDAG - } + bluestGhostDAG, err := dm.ghostdagStore.Get(dm.databaseContext, bluestParent) + if err != nil { + return 0, err } // Not enough blocks for building a difficulty window. @@ -113,20 +101,12 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas // averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize)) // The result uses integer division which means it will be slightly // rounded down. - newTarget := bigintpool.Acquire(0) - defer bigintpool.Release(newTarget) - windowTimeStampDifference := bigintpool.Acquire(windowMaxTimeStamp - windowMinTimestamp) - defer bigintpool.Release(windowTimeStampDifference) - targetTimePerBlock := bigintpool.Acquire(dm.targetTimePerBlock.Milliseconds()) - defer bigintpool.Release(targetTimePerBlock) - difficultyAdjustmentWindowSize := bigintpool.Acquire(int64(dm.difficultyAdjustmentWindowSize)) - defer bigintpool.Release(difficultyAdjustmentWindowSize) - - targetsWindow.averageTarget(newTarget) + div := new(big.Int) + newTarget := targetsWindow.averageTarget() newTarget. - Mul(newTarget, windowTimeStampDifference). - Div(newTarget, targetTimePerBlock). - Div(newTarget, difficultyAdjustmentWindowSize) + Mul(newTarget, div.SetInt64(windowMaxTimeStamp-windowMinTimestamp)). + Div(newTarget, div.SetInt64(dm.targetTimePerBlock.Milliseconds())). + Div(newTarget, div.SetUint64(uint64(dm.difficultyAdjustmentWindowSize))) if newTarget.Cmp(dm.powMax) > 0 { return util.BigToCompact(dm.powMax), nil } diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index 23773708b..0b6fee8eb 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -3,8 +3,6 @@ package ghostdag2 import ( "sort" - "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" - "math/big" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -116,7 +114,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error myWork.Add(myWork, util.CalcWork(header.Bits())) } - e := ghostdagmanager.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil) + e := model.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil) gh.dataStore.Stage(blockCandidate, e) return nil } @@ -391,13 +389,13 @@ func (gh *ghostdagHelper) sortByBlueWork(arr []*externalapi.DomainHash) error { /* --------------------------------------------- */ -func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) { +func (gh *ghostdagHelper) BlockData(blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { return gh.dataStore.Get(gh.dbAccess, blockHash) } func (gh *ghostdagHelper) ChooseSelectedParent(blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) { panic("implement me") } -func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool { +func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { panic("implement me") } diff --git a/domain/consensus/processes/ghostdagmanager/compare.go b/domain/consensus/processes/ghostdagmanager/compare.go index d5143513c..3b0b3777a 100644 --- a/domain/consensus/processes/ghostdagmanager/compare.go +++ b/domain/consensus/processes/ghostdagmanager/compare.go @@ -3,7 +3,6 @@ package ghostdagmanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) func (gm *ghostdagManager) findSelectedParent(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, error) { @@ -53,16 +52,15 @@ func (gm *ghostdagManager) ChooseSelectedParent(blockHashes ...*externalapi.Doma return selectedParent, nil } -func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA model.BlockGHOSTDAGData, - blockHashB *externalapi.DomainHash, ghostdagDataB model.BlockGHOSTDAGData) bool { - +func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, + blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool { switch ghostdagDataA.BlueWork().Cmp(ghostdagDataB.BlueWork()) { case -1: return true case 1: return false case 0: - return hashes.Less(blockHashA, blockHashB) + return externalapi.Less(blockHashA, blockHashB) default: panic("big.Int.Cmp is defined to always return -1/1/0 and nothing else") } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index 6eb056b6a..488dbf088 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -8,6 +8,19 @@ import ( "math/big" ) +type blockGHOSTDAGData struct { + blueScore uint64 + blueWork *big.Int + selectedParent *externalapi.DomainHash + mergeSetBlues []*externalapi.DomainHash + mergeSetReds []*externalapi.DomainHash + bluesAnticoneSizes map[externalapi.DomainHash]model.KType +} + +func (bg *blockGHOSTDAGData) toModel() *model.BlockGHOSTDAGData { + return model.NewBlockGHOSTDAGData(bg.blueScore, bg.blueWork, bg.selectedParent, bg.mergeSetBlues, bg.mergeSetReds, bg.bluesAnticoneSizes) +} + // GHOSTDAG runs the GHOSTDAG protocol and calculates the block BlockGHOSTDAGData by the given parents. // The function calculates MergeSetBlues by iterating over the blocks in // the anticone of the new block selected parent (which is the parent with the @@ -57,7 +70,7 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { } for _, blueCandidate := range mergeSetWithoutSelectedParent { - isBlue, candidateAnticoneSize, candidateBluesAnticoneSizes, err := gm.checkBlueCandidate(newBlockData, blueCandidate) + isBlue, candidateAnticoneSize, candidateBluesAnticoneSizes, err := gm.checkBlueCandidate(newBlockData.toModel(), blueCandidate) if err != nil { return err } @@ -96,22 +109,22 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { newBlockData.blueWork.SetUint64(0) } - gm.ghostdagDataStore.Stage(blockHash, newBlockData) + gm.ghostdagDataStore.Stage(blockHash, newBlockData.toModel()) return nil } type chainBlockData struct { hash *externalapi.DomainHash - blockData model.BlockGHOSTDAGData + blockData *model.BlockGHOSTDAGData } -func (gm *ghostdagManager) checkBlueCandidate(newBlockData *blockGHOSTDAGData, blueCandidate *externalapi.DomainHash) ( +func (gm *ghostdagManager) checkBlueCandidate(newBlockData *model.BlockGHOSTDAGData, blueCandidate *externalapi.DomainHash) ( isBlue bool, candidateAnticoneSize model.KType, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, err error) { // The maximum length of node.blues can be K+1 because // it contains the selected parent. - if model.KType(len(newBlockData.mergeSetBlues)) == gm.k+1 { + if model.KType(len(newBlockData.MergeSetBlues())) == gm.k+1 { return false, 0, nil, nil } @@ -153,7 +166,7 @@ func (gm *ghostdagManager) checkBlueCandidate(newBlockData *blockGHOSTDAGData, b return true, candidateAnticoneSize, candidateBluesAnticoneSizes, nil } -func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.BlockGHOSTDAGData, +func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData *model.BlockGHOSTDAGData, chainBlock chainBlockData, blueCandidate *externalapi.DomainHash, candidateBluesAnticoneSizes map[externalapi.DomainHash]model.KType, candidateAnticoneSize *model.KType) (isBlue, isRed bool, err error) { @@ -218,7 +231,7 @@ func (gm *ghostdagManager) checkBlueCandidateWithChainBlock(newBlockData model.B // blueAnticoneSize returns the blue anticone size of 'block' from the worldview of 'context'. // Expects 'block' to be in the blue set of 'context' -func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context model.BlockGHOSTDAGData) (model.KType, error) { +func (gm *ghostdagManager) blueAnticoneSize(block *externalapi.DomainHash, context *model.BlockGHOSTDAGData) (model.KType, error) { for current := context; current != nil; { if blueAnticoneSize, ok := current.BluesAnticoneSizes()[*block]; ok { return blueAnticoneSize, nil diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go b/domain/consensus/processes/ghostdagmanager/ghostdag_data.go deleted file mode 100644 index 49fc39090..000000000 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_data.go +++ /dev/null @@ -1,69 +0,0 @@ -package ghostdagmanager - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "math/big" -) - -type blockGHOSTDAGData struct { - blueScore uint64 - blueWork *big.Int - selectedParent *externalapi.DomainHash - mergeSetBlues []*externalapi.DomainHash - mergeSetReds []*externalapi.DomainHash - bluesAnticoneSizes map[externalapi.DomainHash]model.KType -} - -// NewBlockGHOSTDAGData creates a new instance of model.BlockGHOSTDAGData -func NewBlockGHOSTDAGData( - blueScore uint64, - blueWork *big.Int, - selectedParent *externalapi.DomainHash, - mergeSetBlues []*externalapi.DomainHash, - mergeSetReds []*externalapi.DomainHash, - bluesAnticoneSizes map[externalapi.DomainHash]model.KType) model.BlockGHOSTDAGData { - - return &blockGHOSTDAGData{ - blueScore: blueScore, - blueWork: blueWork, - selectedParent: selectedParent, - mergeSetBlues: mergeSetBlues, - mergeSetReds: mergeSetReds, - bluesAnticoneSizes: bluesAnticoneSizes, - } -} - -func (bgd *blockGHOSTDAGData) BlueScore() uint64 { - return bgd.blueScore -} - -func (bgd *blockGHOSTDAGData) BlueWork() *big.Int { - return bgd.blueWork -} - -func (bgd *blockGHOSTDAGData) SelectedParent() *externalapi.DomainHash { - return bgd.selectedParent -} - -func (bgd *blockGHOSTDAGData) MergeSetBlues() []*externalapi.DomainHash { - return bgd.mergeSetBlues -} - -func (bgd *blockGHOSTDAGData) MergeSetReds() []*externalapi.DomainHash { - return bgd.mergeSetReds -} - -func (bgd *blockGHOSTDAGData) BluesAnticoneSizes() map[externalapi.DomainHash]model.KType { - return bgd.bluesAnticoneSizes -} - -func (bgd *blockGHOSTDAGData) MergeSet() []*externalapi.DomainHash { - mergeSet := make([]*externalapi.DomainHash, len(bgd.mergeSetBlues)+len(bgd.mergeSetReds)) - copy(mergeSet, bgd.mergeSetBlues) - if len(bgd.mergeSetReds) > 0 { - copy(mergeSet[len(bgd.mergeSetBlues):], bgd.mergeSetReds) - } - - return mergeSet -} diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index f5485da2f..f11de5c5e 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -63,14 +63,14 @@ func TestGHOSTDAG(t *testing.T) { } ghostdagDataStore := &GHOSTDAGDataStoreImpl{ - dagMap: make(map[externalapi.DomainHash]model.BlockGHOSTDAGData), + dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), } blockHeadersStore := &blockHeadersStore{ dagMap: make(map[externalapi.DomainHash]externalapi.BlockHeader), } - blockGHOSTDAGDataGenesis := ghostdagmanager.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil) + blockGHOSTDAGDataGenesis := model.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil) genesisHeader := params.GenesisBlock.Header genesisWork := util.CalcWork(genesisHeader.Bits()) @@ -160,7 +160,7 @@ func TestGHOSTDAG(t *testing.T) { } dagTopology.parentsMap = make(map[externalapi.DomainHash][]*externalapi.DomainHash) dagTopology.parentsMap[genesisHash] = nil - ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]model.BlockGHOSTDAGData) + ghostdagDataStore.dagMap = make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData) ghostdagDataStore.dagMap[genesisHash] = blockGHOSTDAGDataGenesis blockHeadersStore.dagMap = make(map[externalapi.DomainHash]externalapi.BlockHeader) blockHeadersStore.dagMap[genesisHash] = genesisHeader @@ -202,10 +202,10 @@ func StringToDomainHashSlice(stringIDArr []string) []*externalapi.DomainHash { /* ---------------------- */ type GHOSTDAGDataStoreImpl struct { - dagMap map[externalapi.DomainHash]model.BlockGHOSTDAGData + dagMap map[externalapi.DomainHash]*model.BlockGHOSTDAGData } -func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData model.BlockGHOSTDAGData) { +func (ds *GHOSTDAGDataStoreImpl) Stage(blockHash *externalapi.DomainHash, blockGHOSTDAGData *model.BlockGHOSTDAGData) { ds.dagMap[*blockHash] = blockGHOSTDAGData } @@ -221,7 +221,7 @@ func (ds *GHOSTDAGDataStoreImpl) Commit(dbTx model.DBTransaction) error { panic("implement me") } -func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (model.BlockGHOSTDAGData, error) { +func (ds *GHOSTDAGDataStoreImpl) Get(dbContext model.DBReader, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) { v, ok := ds.dagMap[*blockHash] if ok { return v, nil diff --git a/domain/consensus/utils/hashes/compare.go b/domain/consensus/utils/hashes/compare.go deleted file mode 100644 index fdf16db18..000000000 --- a/domain/consensus/utils/hashes/compare.go +++ /dev/null @@ -1,31 +0,0 @@ -package hashes - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// cmp compares two hashes and returns: -// -// -1 if a < b -// 0 if a == b -// +1 if a > b -// -func cmp(a, b *externalapi.DomainHash) int { - aBytes := a.ByteArray() - bBytes := b.ByteArray() - // We compare the hashes backwards because Hash is stored as a little endian byte array. - for i := externalapi.DomainHashSize - 1; i >= 0; i-- { - switch { - case aBytes[i] < bBytes[i]: - return -1 - case aBytes[i] > bBytes[i]: - return 1 - } - } - return 0 -} - -// Less returns true iff hash a is less than hash b -func Less(a, b *externalapi.DomainHash) bool { - return cmp(a, b) < 0 -} diff --git a/domain/consensus/utils/transactionid/compare.go b/domain/consensus/utils/transactionid/compare.go index 918c54206..ab28853c2 100644 --- a/domain/consensus/utils/transactionid/compare.go +++ b/domain/consensus/utils/transactionid/compare.go @@ -2,10 +2,9 @@ package transactionid import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" ) // Less returns true iff transaction ID a is less than hash b func Less(a, b *externalapi.DomainTransactionID) bool { - return hashes.Less((*externalapi.DomainHash)(a), (*externalapi.DomainHash)(b)) + return externalapi.Less((*externalapi.DomainHash)(a), (*externalapi.DomainHash)(b)) } diff --git a/util/bigintpool/pool.go b/util/bigintpool/pool.go deleted file mode 100644 index d2eab80ff..000000000 --- a/util/bigintpool/pool.go +++ /dev/null @@ -1,25 +0,0 @@ -package bigintpool - -import ( - "math/big" - "sync" -) - -var bigIntPool = sync.Pool{ - New: func() interface{} { - return big.NewInt(0) - }, -} - -// Acquire acquires a big.Int from the pool and -// initializes it to x. -func Acquire(x int64) *big.Int { - bigInt := bigIntPool.Get().(*big.Int) - bigInt.SetInt64(x) - return bigInt -} - -// Release returns the given big.Int to the pool. -func Release(toRelease *big.Int) { - bigIntPool.Put(toRelease) -} From 119e7374e167c6ac092b6729aac7d57e925d75bf Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 5 Jan 2021 12:51:48 +0200 Subject: [PATCH 206/351] Move common log message to trace (#1348) --- .../processes/consensusstatemanager/pick_virtual_parents.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 85e9ba96f..459c313dd 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -166,7 +166,7 @@ func (csm *consensusStateManager) mergeSetIncrease( for queue.Len() > 0 { current := queue.Pop() - log.Debugf("Attempting to increment the merge set size increase for block %s", current) + log.Tracef("Attempting to increment the merge set size increase for block %s", current) isInPastOfSelectedVirtualParents, err := csm.dagTopologyManager.IsAncestorOfAny( current, selectedVirtualParents.ToSlice()) @@ -174,7 +174,7 @@ func (csm *consensusStateManager) mergeSetIncrease( return 0, err } if isInPastOfSelectedVirtualParents { - log.Debugf("Skipping block %s because it's in the past of one "+ + log.Tracef("Skipping block %s because it's in the past of one "+ "(or more) of the selected virtual parents", current) continue } From 72a7ca53e64fa1edb1aa66a0e93886d4d88b8914 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 5 Jan 2021 14:13:33 +0200 Subject: [PATCH 207/351] Save and expose the database in TestConsensus (#1349) --- domain/consensus/factory.go | 1 + domain/consensus/model/testapi/test_consensus.go | 2 ++ domain/consensus/test_consensus.go | 2 ++ domain/consensus/test_consensus_getters.go | 5 +++++ 4 files changed, 10 insertions(+) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 37bef61f5..dec61335c 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -379,6 +379,7 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD tstConsensus := &testConsensus{ dagParams: dagParams, consensus: consensusAsImplementation, + database: db, testConsensusStateManager: testConsensusStateManager, testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation. reachabilityManager), diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index c8bb736a9..8b3f9d1fd 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/db/database" ) // TestConsensus wraps the Consensus interface with some methods that are needed by tests only @@ -12,6 +13,7 @@ type TestConsensus interface { DAGParams() *dagconfig.Params DatabaseContext() model.DBManager + Database() database.Database BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index c6e1809f6..c5b4856ec 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -6,11 +6,13 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/db/database" ) type testConsensus struct { *consensus dagParams *dagconfig.Params + database database.Database testBlockBuilder testapi.TestBlockBuilder testReachabilityManager testapi.TestReachabilityManager diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 0390be5b6..8cb6a5219 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -3,12 +3,17 @@ package consensus import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/infrastructure/db/database" ) func (tc *testConsensus) DatabaseContext() model.DBManager { return tc.databaseContext } +func (tc *testConsensus) Database() database.Database { + return tc.database +} + func (tc *testConsensus) AcceptanceDataStore() model.AcceptanceDataStore { return tc.acceptanceDataStore } From 70d515a5a9c4bfb9bc6fe7cfb052b4c0347df1b2 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 5 Jan 2021 14:14:40 +0200 Subject: [PATCH 208/351] PruningManager: Delete tips that are in pruningPoint.Anticone from the tips list (#1351) --- domain/consensus/processes/pruningmanager/pruningmanager.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index dee42b5bf..883d4453a 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -217,6 +217,7 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) if err != nil { return err } + newTips := make([]*externalapi.DomainHash, 0, len(dagTips)) virtualParents, err := pm.dagTopologyManager.Parents(model.VirtualBlockHash) if err != nil { return err @@ -232,9 +233,11 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) if err != nil { return err } + } else { + newTips = append(newTips, tip) } } - + pm.consensusStateStore.StageTips(newTips) // Add P.Parents parents, err := pm.dagTopologyManager.Parents(pruningPoint) if err != nil { From 8a309a7d2abcd9cf96b36957988636e33be79c45 Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:50:09 +0200 Subject: [PATCH 209/351] Upgradability mechanisms script version (#1313) * '' * '' * '' * Changes genesis block version to 0. * a * a * All tests are done. * All tests passed for changed block version from int32 to uint16 * Adds validation of rejecting blocks with unknown versions. * Changes txn version from int32 to uint16. * . * Adds comments to exported functions. * Change functions name from ConvertFromRpcScriptPubKeyToRPCScriptPubKey to ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey and from ConvertFromRPCScriptPubKeyToRpcScriptPubKey to ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey * change comment to "ScriptPublicKey represents a Kaspad ScriptPublicKey" * delete part (tx.Version < 0) that cannot be exist on the if statement. * Revert protobuf version. * Fix a comment. * Fix a comment. * Rename a variable. * Rename a variable. * Remove a const. * Rename a type. * Rename a field. * Rename a field. * Remove commented-out code. * Remove dangerous nil case in DomainTransactionOutput.Clone(). * Remove a constant. * Fix a string. * Fix wrong totalScriptPubKeySize in transactionMassStandalonePart. * Remove a constant. * Remove an unused error. * Fix a serialization error. * Specify version types to be uint16 explicitly. * Use constants.ScriptPublicKeyVersion. * Fix a bad test. * Remove some whitespace. * Add a case to utxoEntry.Equal(). * Rename scriptPubKey to scriptPublicKey. * Remove a TODO. * Rename constants. * Rename a variable. * Add version to parseShortForm. Co-authored-by: tal Co-authored-by: stasatdaglabs --- app/appmessage/domainconverters.go | 10 +- app/appmessage/p2p_msgblock_test.go | 40 +- app/appmessage/p2p_msgblockheader.go | 4 +- app/appmessage/p2p_msgtx.go | 32 +- app/appmessage/p2p_msgtx_test.go | 52 +- app/appmessage/rpc_get_block.go | 5 +- app/appmessage/rpc_submit_transaction.go | 20 +- app/rpc/rpccontext/utxos_by_addresses.go | 8 +- app/rpc/rpccontext/verbosedata.go | 9 +- cmd/wallet/send.go | 2 +- domain/consensus/consensus_test.go | 7 +- .../database/serialization/acceptancedata.go | 5 +- .../database/serialization/blockheader.go | 8 +- .../database/serialization/dbobjects.pb.go | 571 +-- .../database/serialization/dbobjects.proto | 15 +- .../database/serialization/transaction.go | 17 +- .../database/serialization/utxo_collection.go | 7 +- .../database/serialization/utxo_entry.go | 25 +- .../consensusstatestore/utxo_serialization.go | 3 +- .../model/acceptancedata_equal_clone_test.go | 144 +- domain/consensus/model/externalapi/block.go | 2 +- .../consensus/model/externalapi/coinbase.go | 9 +- .../model/externalapi/coinbase_clone_test.go | 4 +- .../model/externalapi/transaction.go | 20 +- .../transaction_equal_clone_test.go | 156 +- .../consensus/model/externalapi/utxoentry.go | 4 +- .../processes/blockbuilder/block_builder.go | 2 +- .../blockbuilder/test_block_builder.go | 2 +- .../block_body_in_isolation_test.go | 153 +- .../block_header_in_isolation.go | 14 + .../blockvalidator/header_estimated_size.go | 2 +- .../coinbasemanager/coinbasemanager.go | 4 +- .../processes/coinbasemanager/payload.go | 35 +- .../resolve_block_status_test.go | 6 +- .../virtual_parents_test.go | 4 +- .../dagtraversalmanager/window_test.go | 60 +- .../ghostdagmanager/ghostdag_test.go | 2 +- .../processes/pruningmanager/pruning_test.go | 4 +- .../processes/transactionvalidator/mass.go | 3 +- .../transaction_in_isolation.go | 5 + .../transaction_in_isolation_test.go | 6 +- domain/consensus/ruleerrors/rule_error.go | 6 + .../consensus/ruleerrors/rule_error_test.go | 2 +- .../utils/blockheader/blockheader.go | 6 +- .../utils/consensushashing/transaction.go | 9 +- domain/consensus/utils/constants/constants.go | 11 +- .../transaction_estimated_size.go | 5 +- .../consensus/utils/serialization/common.go | 6 + .../utils/testutils/create_transaction.go | 2 +- .../utils/testutils/op_true_script.go | 9 +- .../consensus/utils/transactionhelper/new.go | 4 +- domain/consensus/utils/txscript/engine.go | 18 +- .../consensus/utils/txscript/engine_test.go | 15 +- .../consensus/utils/txscript/example_test.go | 10 +- .../utils/txscript/reference_test.go | 14 +- domain/consensus/utils/txscript/script.go | 49 +- .../consensus/utils/txscript/script_test.go | 28 +- domain/consensus/utils/txscript/sign.go | 47 +- domain/consensus/utils/txscript/sign_test.go | 75 +- domain/consensus/utils/txscript/standard.go | 24 +- .../consensus/utils/txscript/standard_test.go | 124 +- .../consensus/utils/utxo/diff_algebra_test.go | 12 +- domain/consensus/utils/utxo/serialization.go | 18 +- .../utils/utxo/serialization_test.go | 8 +- domain/consensus/utils/utxo/utxo_entry.go | 24 +- .../consensus/utils/utxo/utxo_entry_test.go | 14 +- domain/dagconfig/genesis.go | 100 +- domain/miningmanager/mempool/mempool.go | 4 +- domain/miningmanager/mempool/policy.go | 14 +- domain/miningmanager/mempool/policy_test.go | 68 +- domain/utxoindex/model.go | 20 +- domain/utxoindex/store.go | 17 +- domain/utxoindex/utxoindex.go | 2 +- .../grpcserver/protowire/messages.pb.go | 3080 +++++++++-------- .../grpcserver/protowire/messages.proto | 31 +- .../server/grpcserver/protowire/p2p_header.go | 8 +- .../grpcserver/protowire/p2p_transaction.go | 20 +- .../grpcserver/protowire/rpc_get_block.go | 33 +- .../protowire/rpc_get_utxos_by_addresses.go | 6 +- .../protowire/rpc_notify_utxos_changed.go | 36 +- .../protowire/rpc_submit_transaction.go | 45 +- testing/integration/tx_relay_test.go | 2 +- testing/integration/utxo_index_test.go | 27 +- 83 files changed, 3045 insertions(+), 2489 deletions(-) diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 7496623d4..0c8cc88e0 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -187,13 +187,13 @@ func RPCTransactionToDomainTransaction(rpcTransaction *RPCTransaction) (*externa } outputs := make([]*externalapi.DomainTransactionOutput, len(rpcTransaction.Outputs)) for i, output := range rpcTransaction.Outputs { - scriptPublicKey, err := hex.DecodeString(output.ScriptPubKey) + scriptPublicKey, err := hex.DecodeString(output.ScriptPublicKey.Script) if err != nil { return nil, err } outputs[i] = &externalapi.DomainTransactionOutput{ Value: output.Amount, - ScriptPublicKey: scriptPublicKey, + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: scriptPublicKey, Version: output.ScriptPublicKey.Version}, } } @@ -248,10 +248,10 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio } outputs := make([]*RPCTransactionOutput, len(transaction.Outputs)) for i, output := range transaction.Outputs { - scriptPublicKey := hex.EncodeToString(output.ScriptPublicKey) + scriptPublicKey := hex.EncodeToString(output.ScriptPublicKey.Script) outputs[i] = &RPCTransactionOutput{ - Amount: output.Value, - ScriptPubKey: scriptPublicKey, + Amount: output.Value, + ScriptPublicKey: &RPCScriptPublicKey{Script: scriptPublicKey, Version: output.ScriptPublicKey.Version}, } } subnetworkID := hex.EncodeToString(transaction.SubnetworkID[:]) diff --git a/app/appmessage/p2p_msgblock_test.go b/app/appmessage/p2p_msgblock_test.go index 347b10556..bdc7c3be2 100644 --- a/app/appmessage/p2p_msgblock_test.go +++ b/app/appmessage/p2p_msgblock_test.go @@ -5,15 +5,15 @@ package appmessage import ( + "github.com/davecgh/go-spew/spew" + "github.com/kaspanet/kaspad/util/mstime" "math" "reflect" "testing" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" - "github.com/davecgh/go-spew/spew" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util/mstime" ) // TestBlock tests the MsgBlock API. @@ -127,10 +127,10 @@ func TestConvertToPartial(t *testing.T) { } } -// blockOne is the first block in the mainnet block DAG. +//blockOne is the first block in the mainnet block DAG. var blockOne = MsgBlock{ Header: MsgBlockHeader{ - Version: 1, + Version: 0, ParentHashes: []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash}, HashMerkleRoot: mainnetGenesisMerkleRoot, AcceptedIDMerkleRoot: exampleAcceptedIDMerkleRoot, @@ -156,19 +156,21 @@ var blockOne = MsgBlock{ []*TxOut{ { Value: 0x12a05f200, - ScriptPubKey: []byte{ - 0x41, // OP_DATA_65 - 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, - 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, - 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, - 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, - 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, - 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, - 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, - 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, - 0xee, // 65-byte signature - 0xac, // OP_CHECKSIG - }, + ScriptPubKey: &externalapi.ScriptPublicKey{ + Script: []byte{ + 0x41, // OP_DATA_65 + 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, + 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, + 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, + 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, + 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, + 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, + 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, + 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, + 0xee, // 65-byte signature + 0xac, // OP_CHECKSIG + }, + Version: 0}, }, }), }, @@ -176,7 +178,7 @@ var blockOne = MsgBlock{ // Block one serialized bytes. var blockOneBytes = []byte{ - 0x01, 0x00, 0x00, 0x00, // Version 1 + 0x00, 0x00, // Version 0 0x02, // NumParentBlocks 0xdc, 0x5f, 0x5b, 0x5b, 0x1d, 0xc2, 0xa7, 0x25, // mainnetGenesisHash 0x49, 0xd5, 0x1d, 0x4d, 0xee, 0xd7, 0xa4, 0x8b, @@ -202,7 +204,7 @@ var blockOneBytes = []byte{ 0xff, 0xff, 0x00, 0x1d, // Bits 0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce 0x01, // TxnCount - 0x01, 0x00, 0x00, 0x00, // Version + 0x00, 0x00, 0x00, 0x00, // Version 0x01, // Varint for number of transaction inputs 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/app/appmessage/p2p_msgblockheader.go b/app/appmessage/p2p_msgblockheader.go index d0bb04494..f095a2dc7 100644 --- a/app/appmessage/p2p_msgblockheader.go +++ b/app/appmessage/p2p_msgblockheader.go @@ -37,7 +37,7 @@ type MsgBlockHeader struct { baseMessage // Version of the block. This is not the same as the protocol version. - Version int32 + Version uint16 // Hashes of the parent block headers in the blockDAG. ParentHashes []*externalapi.DomainHash @@ -90,7 +90,7 @@ func (h *MsgBlockHeader) Command() MessageCommand { // NewBlockHeader returns a new MsgBlockHeader using the provided version, previous // block hash, hash merkle root, accepted ID merkle root, difficulty bits, and nonce used to generate the // block with defaults or calclulated values for the remaining fields. -func NewBlockHeader(version int32, parentHashes []*externalapi.DomainHash, hashMerkleRoot *externalapi.DomainHash, +func NewBlockHeader(version uint16, parentHashes []*externalapi.DomainHash, hashMerkleRoot *externalapi.DomainHash, acceptedIDMerkleRoot *externalapi.DomainHash, utxoCommitment *externalapi.DomainHash, bits uint32, nonce uint64) *MsgBlockHeader { // Limit the timestamp to one millisecond precision since the protocol diff --git a/app/appmessage/p2p_msgtx.go b/app/appmessage/p2p_msgtx.go index 1e65d91ea..7cd9de738 100644 --- a/app/appmessage/p2p_msgtx.go +++ b/app/appmessage/p2p_msgtx.go @@ -38,8 +38,8 @@ const ( maxTxInPerMessage = (MaxMessagePayload / minTxInPayload) + 1 // MinTxOutPayload is the minimum payload size for a transaction output. - // Value 8 bytes + Varint for ScriptPubKey length 1 byte. - MinTxOutPayload = 9 + // Value 8 bytes + version 2 bytes + Varint for ScriptPublicKey length 1 byte. + MinTxOutPayload = 11 // maxTxOutPerMessage is the maximum number of transactions outputs that // a transaction which fits into a message could possibly have. @@ -107,12 +107,12 @@ func NewTxIn(prevOut *Outpoint, signatureScript []byte, sequence uint64) *TxIn { // TxOut defines a kaspa transaction output. type TxOut struct { Value uint64 - ScriptPubKey []byte + ScriptPubKey *externalapi.ScriptPublicKey } // NewTxOut returns a new kaspa transaction output with the provided // transaction value and public key script. -func NewTxOut(value uint64, scriptPubKey []byte) *TxOut { +func NewTxOut(value uint64, scriptPubKey *externalapi.ScriptPublicKey) *TxOut { return &TxOut{ Value: value, ScriptPubKey: scriptPubKey, @@ -127,7 +127,7 @@ func NewTxOut(value uint64, scriptPubKey []byte) *TxOut { // inputs and outputs. type MsgTx struct { baseMessage - Version int32 + Version uint16 TxIn []*TxIn TxOut []*TxOut LockTime uint64 @@ -217,20 +217,20 @@ func (msg *MsgTx) Copy() *MsgTx { // Deep copy the old TxOut data. for _, oldTxOut := range msg.TxOut { - // Deep copy the old ScriptPubKey - var newScript []byte + // Deep copy the old ScriptPublicKey + var newScript externalapi.ScriptPublicKey oldScript := oldTxOut.ScriptPubKey - oldScriptLen := len(oldScript) + oldScriptLen := len(oldScript.Script) if oldScriptLen > 0 { - newScript = make([]byte, oldScriptLen) - copy(newScript, oldScript[:oldScriptLen]) + newScript = externalapi.ScriptPublicKey{Script: make([]byte, oldScriptLen), Version: oldScript.Version} + copy(newScript.Script, oldScript.Script[:oldScriptLen]) } // Create new txOut with the deep copied data and append it to // new Tx. newTxOut := TxOut{ Value: oldTxOut.Value, - ScriptPubKey: newScript, + ScriptPubKey: &newScript, } newTx.TxOut = append(newTx.TxOut, &newTxOut) } @@ -269,7 +269,7 @@ func (msg *MsgTx) IsSubnetworkCompatible(subnetworkID *externalapi.DomainSubnetw // The payload hash is calculated automatically according to provided payload. // Also, the lock time is set to zero to indicate the transaction is valid // immediately as opposed to some time in future. -func newMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, subnetworkID *externalapi.DomainSubnetworkID, +func newMsgTx(version uint16, txIn []*TxIn, txOut []*TxOut, subnetworkID *externalapi.DomainSubnetworkID, gas uint64, payload []byte, lockTime uint64) *MsgTx { if txIn == nil { @@ -298,12 +298,12 @@ func newMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, subnetworkID *externa } // NewNativeMsgTx returns a new tx message in the native subnetwork -func NewNativeMsgTx(version int32, txIn []*TxIn, txOut []*TxOut) *MsgTx { +func NewNativeMsgTx(version uint16, txIn []*TxIn, txOut []*TxOut) *MsgTx { return newMsgTx(version, txIn, txOut, &subnetworks.SubnetworkIDNative, 0, nil, 0) } // NewSubnetworkMsgTx returns a new tx message in the specified subnetwork with specified gas and payload -func NewSubnetworkMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, subnetworkID *externalapi.DomainSubnetworkID, +func NewSubnetworkMsgTx(version uint16, txIn []*TxIn, txOut []*TxOut, subnetworkID *externalapi.DomainSubnetworkID, gas uint64, payload []byte) *MsgTx { return newMsgTx(version, txIn, txOut, subnetworkID, gas, payload, 0) @@ -312,12 +312,12 @@ func NewSubnetworkMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, subnetworkI // NewNativeMsgTxWithLocktime returns a new tx message in the native subnetwork with a locktime. // // See newMsgTx for further documntation of the parameters -func NewNativeMsgTxWithLocktime(version int32, txIn []*TxIn, txOut []*TxOut, locktime uint64) *MsgTx { +func NewNativeMsgTxWithLocktime(version uint16, txIn []*TxIn, txOut []*TxOut, locktime uint64) *MsgTx { return newMsgTx(version, txIn, txOut, &subnetworks.SubnetworkIDNative, 0, nil, locktime) } // NewRegistryMsgTx creates a new MsgTx that registers a new subnetwork -func NewRegistryMsgTx(version int32, txIn []*TxIn, txOut []*TxOut, gasLimit uint64) *MsgTx { +func NewRegistryMsgTx(version uint16, txIn []*TxIn, txOut []*TxOut, gasLimit uint64) *MsgTx { payload := make([]byte, 8) binary.LittleEndian.PutUint64(payload, gasLimit) diff --git a/app/appmessage/p2p_msgtx_test.go b/app/appmessage/p2p_msgtx_test.go index a8704e3df..ec2bf7c27 100644 --- a/app/appmessage/p2p_msgtx_test.go +++ b/app/appmessage/p2p_msgtx_test.go @@ -82,26 +82,28 @@ func TestTx(t *testing.T) { // Ensure we get the same transaction output back out. txValue := uint64(5000000000) - scriptPubKey := []byte{ - 0x41, // OP_DATA_65 - 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, - 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, - 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, - 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, - 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, - 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, - 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, - 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, - 0xa6, // 65-byte signature - 0xac, // OP_CHECKSIG - } + scriptPubKey := &externalapi.ScriptPublicKey{ + Script: []byte{ + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + }, + Version: 0} txOut := NewTxOut(txValue, scriptPubKey) if txOut.Value != txValue { t.Errorf("NewTxOut: wrong scriptPubKey - got %v, want %v", txOut.Value, txValue) } - if !bytes.Equal(txOut.ScriptPubKey, scriptPubKey) { + if !bytes.Equal(txOut.ScriptPubKey.Script, scriptPubKey.Script) { t.Errorf("NewTxOut: wrong scriptPubKey - got %v, want %v", spew.Sdump(txOut.ScriptPubKey), spew.Sdump(scriptPubKey)) @@ -131,8 +133,8 @@ func TestTx(t *testing.T) { // TestTxHash tests the ability to generate the hash of a transaction accurately. func TestTxHashAndID(t *testing.T) { - txHash1Str := "cf09b7b8ea6c3429515e7e7c8b9531d449f7ca869fad030126495c2c791eacc2" - txID1Str := "378b6f83f103241a92b00533746b64800dadedeb1e48c097cf2757eea512ce47" + txHash1Str := "4bee9ee495bd93a755de428376bd582a2bb6ec37c041753b711c0606d5745c13" + txID1Str := "f868bd20e816256b80eac976821be4589d24d21141bd1cec6e8005d0c16c6881" wantTxID1, err := transactionid.FromString(txID1Str) if err != nil { t.Fatalf("NewTxIDFromStr: %v", err) @@ -153,7 +155,7 @@ func TestTxHashAndID(t *testing.T) { } txOut := &TxOut{ Value: 5000000000, - ScriptPubKey: []byte{ + ScriptPubKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x41, // OP_DATA_65 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, @@ -165,9 +167,9 @@ func TestTxHashAndID(t *testing.T) { 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, 0xa6, // 65-byte signature 0xac, // OP_CHECKSIG - }, + }, Version: 0}, } - tx1 := NewSubnetworkMsgTx(1, []*TxIn{txIn}, []*TxOut{txOut}, &subnetworks.SubnetworkIDCoinbase, 0, nil) + tx1 := NewSubnetworkMsgTx(0, []*TxIn{txIn}, []*TxOut{txOut}, &subnetworks.SubnetworkIDCoinbase, 0, nil) // Ensure the hash produced is expected. tx1Hash := tx1.TxHash() @@ -183,14 +185,14 @@ func TestTxHashAndID(t *testing.T) { spew.Sprint(tx1ID), spew.Sprint(wantTxID1)) } - hash2Str := "0c60a073b56ff0510307e3efbb5e1881c3b1b97b4f0a69e4220042a15596766b" + hash2Str := "cb1bdb4a83d4885535fb3cceb5c96597b7df903db83f0ffcd779d703affd8efd" wantHash2, err := externalapi.NewDomainHashFromString(hash2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) return } - id2Str := "68ec13739c0088c1ebca9d14d9daa4ccb24db4e4be021fa2aaad71e2326091af" + id2Str := "ca080073d4ddf5b84443a0964af633f3c70a5b290fd3bc35a7e6f93fd33f9330" wantID2, err := transactionid.FromString(id2Str) if err != nil { t.Errorf("NewTxIDFromStr: %v", err) @@ -218,17 +220,17 @@ func TestTxHashAndID(t *testing.T) { txOuts := []*TxOut{ { Value: 244623243, - ScriptPubKey: []byte{ + ScriptPubKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, 0xA9, 0x14, 0xBA, 0xDE, 0xEC, 0xFD, 0xEF, 0x05, 0x07, 0x24, 0x7F, 0xC8, 0xF7, 0x42, 0x41, 0xD7, 0x3B, 0xC0, 0x39, 0x97, 0x2D, 0x7B, 0x88, 0xAC, - }, + }, Version: 0}, }, { Value: 44602432, - ScriptPubKey: []byte{ + ScriptPubKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, 0xA9, 0x14, 0xC1, 0x09, 0x32, 0x48, 0x3F, 0xEC, 0x93, 0xED, 0x51, 0xF5, 0xFE, 0x95, 0xE7, 0x25, 0x59, 0xF2, 0xCC, 0x70, 0x43, 0xF9, 0x88, 0xAC, - }, + }, Version: 0}, }, } tx2 := NewSubnetworkMsgTx(1, txIns, txOuts, &externalapi.DomainSubnetworkID{1, 2, 3}, 0, payload) diff --git a/app/appmessage/rpc_get_block.go b/app/appmessage/rpc_get_block.go index be5269607..9742da509 100644 --- a/app/appmessage/rpc_get_block.go +++ b/app/appmessage/rpc_get_block.go @@ -45,7 +45,7 @@ func NewGetBlockResponseMessage() *GetBlockResponseMessage { // BlockVerboseData holds verbose data about a block type BlockVerboseData struct { Hash string - Version int32 + Version uint16 VersionHex string HashMerkleRoot string AcceptedIDMerkleRoot string @@ -67,7 +67,7 @@ type TransactionVerboseData struct { TxID string Hash string Size uint64 - Version int32 + Version uint16 LockTime uint64 SubnetworkID string Gas uint64 @@ -103,7 +103,6 @@ type TransactionVerboseOutput struct { // ScriptPubKeyResult holds data about a script public key type ScriptPubKeyResult struct { - Asm string Hex string Type string Address string diff --git a/app/appmessage/rpc_submit_transaction.go b/app/appmessage/rpc_submit_transaction.go index ba63da336..741c02cf2 100644 --- a/app/appmessage/rpc_submit_transaction.go +++ b/app/appmessage/rpc_submit_transaction.go @@ -43,7 +43,7 @@ func NewSubmitTransactionResponseMessage(transactionID string) *SubmitTransactio // RPCTransaction is a kaspad transaction representation meant to be // used over RPC type RPCTransaction struct { - Version int32 + Version uint16 Inputs []*RPCTransactionInput Outputs []*RPCTransactionOutput LockTime uint64 @@ -61,11 +61,17 @@ type RPCTransactionInput struct { Sequence uint64 } +// RPCScriptPublicKey is a kaspad ScriptPublicKey representation +type RPCScriptPublicKey struct { + Version uint16 + Script string +} + // RPCTransactionOutput is a kaspad transaction output representation // meant to be used over RPC type RPCTransactionOutput struct { - Amount uint64 - ScriptPubKey string + Amount uint64 + ScriptPublicKey *RPCScriptPublicKey } // RPCOutpoint is a kaspad outpoint representation meant to be used @@ -78,8 +84,8 @@ type RPCOutpoint struct { // RPCUTXOEntry is a kaspad utxo entry representation meant to be used // over RPC type RPCUTXOEntry struct { - Amount uint64 - ScriptPubKey string - BlockBlueScore uint64 - IsCoinbase bool + Amount uint64 + ScriptPublicKey *RPCScriptPublicKey + BlockBlueScore uint64 + IsCoinbase bool } diff --git a/app/rpc/rpccontext/utxos_by_addresses.go b/app/rpc/rpccontext/utxos_by_addresses.go index 7fd2458e7..cea7db747 100644 --- a/app/rpc/rpccontext/utxos_by_addresses.go +++ b/app/rpc/rpccontext/utxos_by_addresses.go @@ -19,10 +19,10 @@ func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pair Index: outpoint.Index, }, UTXOEntry: &appmessage.RPCUTXOEntry{ - Amount: utxoEntry.Amount(), - ScriptPubKey: hex.EncodeToString(utxoEntry.ScriptPublicKey()), - BlockBlueScore: utxoEntry.BlockBlueScore(), - IsCoinbase: utxoEntry.IsCoinbase(), + Amount: utxoEntry.Amount(), + ScriptPublicKey: &appmessage.RPCScriptPublicKey{Script: hex.EncodeToString(utxoEntry.ScriptPublicKey().Script), Version: utxoEntry.ScriptPublicKey().Version}, + BlockBlueScore: utxoEntry.BlockBlueScore(), + IsCoinbase: utxoEntry.IsCoinbase(), }, }) } diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 574e9ee9e..7f09bac8f 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -3,6 +3,7 @@ package rpccontext import ( "encoding/hex" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "math" "math/big" "strconv" @@ -133,7 +134,7 @@ func (ctx *Context) buildTransactionVerboseInputs(tx *externalapi.DomainTransact // The disassembled string will contain [error] inline // if the script doesn't fully parse, so ignore the // error here. - disbuf, _ := txscript.DisasmString(transactionInput.SignatureScript) + disbuf, _ := txscript.DisasmString(constants.MaxScriptPublicKeyVersion, transactionInput.SignatureScript) input := &appmessage.TransactionVerboseInput{} input.TxID = transactionInput.PreviousOutpoint.TransactionID.String() @@ -154,9 +155,6 @@ func (ctx *Context) buildTransactionVerboseInputs(tx *externalapi.DomainTransact func (ctx *Context) buildTransactionVerboseOutputs(tx *externalapi.DomainTransaction, filterAddrMap map[string]struct{}) []*appmessage.TransactionVerboseOutput { outputs := make([]*appmessage.TransactionVerboseOutput, len(tx.Outputs)) for i, transactionOutput := range tx.Outputs { - // The disassembled string will contain [error] inline if the - // script doesn't fully parse, so ignore the error here. - disbuf, _ := txscript.DisasmString(transactionOutput.ScriptPublicKey) // Ignore the error here since an error means the script // couldn't parse and there is no additional information about @@ -187,8 +185,7 @@ func (ctx *Context) buildTransactionVerboseOutputs(tx *externalapi.DomainTransac output.Value = transactionOutput.Value output.ScriptPubKey = &appmessage.ScriptPubKeyResult{ Address: encodedAddr, - Asm: disbuf, - Hex: hex.EncodeToString(transactionOutput.ScriptPublicKey), + Hex: hex.EncodeToString(transactionOutput.ScriptPublicKey.Script), Type: scriptClass.String(), } outputs[i] = output diff --git a/cmd/wallet/send.go b/cmd/wallet/send.go index b757cbaf2..4c4163224 100644 --- a/cmd/wallet/send.go +++ b/cmd/wallet/send.go @@ -170,7 +170,7 @@ func generateTransaction(keyPair *secp256k1.SchnorrKeyPair, selectedUTXOs []*app outputs := []*externalapi.DomainTransactionOutput{mainOutput, changeOutput} domainTransaction := &externalapi.DomainTransaction{ - Version: constants.TransactionVersion, + Version: constants.MaxTransactionVersion, Inputs: inputs, Outputs: outputs, LockTime: 0, diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index 6632d1244..cc38ca06e 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -44,7 +44,12 @@ func TestConsensus_GetBlockInfo(t *testing.T) { t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusInvalid, info.BlockStatus) } - emptyCoinbase := externalapi.DomainCoinbaseData{} + emptyCoinbase := externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } validBlock, err := consensus.BuildBlock(&emptyCoinbase, nil) if err != nil { t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err) diff --git a/domain/consensus/database/serialization/acceptancedata.go b/domain/consensus/database/serialization/acceptancedata.go index 89e2a028e..4024c03b1 100644 --- a/domain/consensus/database/serialization/acceptancedata.go +++ b/domain/consensus/database/serialization/acceptancedata.go @@ -55,7 +55,10 @@ func DbAcceptanceDataToDomainAcceptanceData(dbAcceptanceData *DbAcceptanceData) domainTransactionInputUTXOEntries := make([]externalapi.UTXOEntry, len(dbTransactionAcceptanceData.TransactionInputUtxoEntries)) for k, transactionInputUTXOEntry := range dbTransactionAcceptanceData.TransactionInputUtxoEntries { - domainTransactionInputUTXOEntry := DBUTXOEntryToUTXOEntry(transactionInputUTXOEntry) + domainTransactionInputUTXOEntry, err := DBUTXOEntryToUTXOEntry(transactionInputUTXOEntry) + if err != nil { + return nil, err + } domainTransactionInputUTXOEntries[k] = domainTransactionInputUTXOEntry // For consistency's sake, we fill up the transaction input's diff --git a/domain/consensus/database/serialization/blockheader.go b/domain/consensus/database/serialization/blockheader.go index 5a1bce9ad..30275c2e2 100644 --- a/domain/consensus/database/serialization/blockheader.go +++ b/domain/consensus/database/serialization/blockheader.go @@ -3,12 +3,13 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/pkg/errors" ) // DomainBlockHeaderToDbBlockHeader converts BlockHeader to DbBlockHeader func DomainBlockHeaderToDbBlockHeader(domainBlockHeader externalapi.BlockHeader) *DbBlockHeader { return &DbBlockHeader{ - Version: domainBlockHeader.Version(), + Version: uint32(domainBlockHeader.Version()), ParentHashes: DomainHashesToDbHashes(domainBlockHeader.ParentHashes()), HashMerkleRoot: DomainHashToDbHash(domainBlockHeader.HashMerkleRoot()), AcceptedIDMerkleRoot: DomainHashToDbHash(domainBlockHeader.AcceptedIDMerkleRoot()), @@ -37,9 +38,12 @@ func DbBlockHeaderToDomainBlockHeader(dbBlockHeader *DbBlockHeader) (externalapi if err != nil { return nil, err } + if dbBlockHeader.Version > 0xffff { + return nil, errors.Errorf("Invalid header version - bigger then uint16") + } return blockheader.NewImmutableBlockHeader( - dbBlockHeader.Version, + uint16(dbBlockHeader.Version), parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index f1e1fcaa0..2f5cfc592 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -85,7 +85,7 @@ type DbBlockHeader struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` ParentHashes []*DbHash `protobuf:"bytes,2,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` HashMerkleRoot *DbHash `protobuf:"bytes,3,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` AcceptedIDMerkleRoot *DbHash `protobuf:"bytes,4,opt,name=acceptedIDMerkleRoot,proto3" json:"acceptedIDMerkleRoot,omitempty"` @@ -127,7 +127,7 @@ func (*DbBlockHeader) Descriptor() ([]byte, []int) { return file_dbobjects_proto_rawDescGZIP(), []int{1} } -func (x *DbBlockHeader) GetVersion() int32 { +func (x *DbBlockHeader) GetVersion() uint32 { if x != nil { return x.Version } @@ -235,7 +235,7 @@ type DbTransaction struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` Inputs []*DbTransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` Outputs []*DbTransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` @@ -277,7 +277,7 @@ func (*DbTransaction) Descriptor() ([]byte, []int) { return file_dbobjects_proto_rawDescGZIP(), []int{3} } -func (x *DbTransaction) GetVersion() int32 { +func (x *DbTransaction) GetVersion() uint32 { if x != nil { return x.Version } @@ -503,8 +503,8 @@ type DbTransactionOutput struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - ScriptPublicKey []byte `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + ScriptPublicKey *DbScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` } func (x *DbTransactionOutput) Reset() { @@ -546,7 +546,7 @@ func (x *DbTransactionOutput) GetValue() uint64 { return 0 } -func (x *DbTransactionOutput) GetScriptPublicKey() []byte { +func (x *DbTransactionOutput) GetScriptPublicKey() *DbScriptPublicKey { if x != nil { return x.ScriptPublicKey } @@ -1166,21 +1166,76 @@ func (x *DbUtxoCollectionItem) GetUtxoEntry() *DbUtxoEntry { return nil } +type DbScriptPublicKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Script []byte `protobuf:"bytes,1,opt,name=script,proto3" json:"script,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` +} + +func (x *DbScriptPublicKey) Reset() { + *x = DbScriptPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_dbobjects_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DbScriptPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DbScriptPublicKey) ProtoMessage() {} + +func (x *DbScriptPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_dbobjects_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DbScriptPublicKey.ProtoReflect.Descriptor instead. +func (*DbScriptPublicKey) Descriptor() ([]byte, []int) { + return file_dbobjects_proto_rawDescGZIP(), []int{19} +} + +func (x *DbScriptPublicKey) GetScript() []byte { + if x != nil { + return x.Script + } + return nil +} + +func (x *DbScriptPublicKey) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + type DbUtxoEntry struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` - ScriptPublicKey []byte `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` - BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` - IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *DbScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` + BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` + IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` } func (x *DbUtxoEntry) Reset() { *x = DbUtxoEntry{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[19] + mi := &file_dbobjects_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1193,7 +1248,7 @@ func (x *DbUtxoEntry) String() string { func (*DbUtxoEntry) ProtoMessage() {} func (x *DbUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[19] + mi := &file_dbobjects_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1206,7 +1261,7 @@ func (x *DbUtxoEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use DbUtxoEntry.ProtoReflect.Descriptor instead. func (*DbUtxoEntry) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{19} + return file_dbobjects_proto_rawDescGZIP(), []int{20} } func (x *DbUtxoEntry) GetAmount() uint64 { @@ -1216,7 +1271,7 @@ func (x *DbUtxoEntry) GetAmount() uint64 { return 0 } -func (x *DbUtxoEntry) GetScriptPublicKey() []byte { +func (x *DbUtxoEntry) GetScriptPublicKey() *DbScriptPublicKey { if x != nil { return x.ScriptPublicKey } @@ -1251,7 +1306,7 @@ type DbReachabilityData struct { func (x *DbReachabilityData) Reset() { *x = DbReachabilityData{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[20] + mi := &file_dbobjects_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1264,7 +1319,7 @@ func (x *DbReachabilityData) String() string { func (*DbReachabilityData) ProtoMessage() {} func (x *DbReachabilityData) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[20] + mi := &file_dbobjects_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1277,7 +1332,7 @@ func (x *DbReachabilityData) ProtoReflect() protoreflect.Message { // Deprecated: Use DbReachabilityData.ProtoReflect.Descriptor instead. func (*DbReachabilityData) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{20} + return file_dbobjects_proto_rawDescGZIP(), []int{21} } func (x *DbReachabilityData) GetChildren() []*DbHash { @@ -1320,7 +1375,7 @@ type DbReachabilityInterval struct { func (x *DbReachabilityInterval) Reset() { *x = DbReachabilityInterval{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[21] + mi := &file_dbobjects_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1333,7 +1388,7 @@ func (x *DbReachabilityInterval) String() string { func (*DbReachabilityInterval) ProtoMessage() {} func (x *DbReachabilityInterval) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[21] + mi := &file_dbobjects_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1346,7 +1401,7 @@ func (x *DbReachabilityInterval) ProtoReflect() protoreflect.Message { // Deprecated: Use DbReachabilityInterval.ProtoReflect.Descriptor instead. func (*DbReachabilityInterval) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{21} + return file_dbobjects_proto_rawDescGZIP(), []int{22} } func (x *DbReachabilityInterval) GetStart() uint64 { @@ -1375,7 +1430,7 @@ type DbUtxoDiff struct { func (x *DbUtxoDiff) Reset() { *x = DbUtxoDiff{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[22] + mi := &file_dbobjects_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1388,7 +1443,7 @@ func (x *DbUtxoDiff) String() string { func (*DbUtxoDiff) ProtoMessage() {} func (x *DbUtxoDiff) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[22] + mi := &file_dbobjects_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1401,7 +1456,7 @@ func (x *DbUtxoDiff) ProtoReflect() protoreflect.Message { // Deprecated: Use DbUtxoDiff.ProtoReflect.Descriptor instead. func (*DbUtxoDiff) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{22} + return file_dbobjects_proto_rawDescGZIP(), []int{23} } func (x *DbUtxoDiff) GetToAdd() []*DbUtxoCollectionItem { @@ -1429,7 +1484,7 @@ type DbPruningPointUTXOSetBytes struct { func (x *DbPruningPointUTXOSetBytes) Reset() { *x = DbPruningPointUTXOSetBytes{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[23] + mi := &file_dbobjects_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1442,7 +1497,7 @@ func (x *DbPruningPointUTXOSetBytes) String() string { func (*DbPruningPointUTXOSetBytes) ProtoMessage() {} func (x *DbPruningPointUTXOSetBytes) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[23] + mi := &file_dbobjects_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1455,7 +1510,7 @@ func (x *DbPruningPointUTXOSetBytes) ProtoReflect() protoreflect.Message { // Deprecated: Use DbPruningPointUTXOSetBytes.ProtoReflect.Descriptor instead. func (*DbPruningPointUTXOSetBytes) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{23} + return file_dbobjects_proto_rawDescGZIP(), []int{24} } func (x *DbPruningPointUTXOSetBytes) GetBytes() []byte { @@ -1476,7 +1531,7 @@ type DbHeaderTips struct { func (x *DbHeaderTips) Reset() { *x = DbHeaderTips{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[24] + mi := &file_dbobjects_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1489,7 +1544,7 @@ func (x *DbHeaderTips) String() string { func (*DbHeaderTips) ProtoMessage() {} func (x *DbHeaderTips) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[24] + mi := &file_dbobjects_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1502,7 +1557,7 @@ func (x *DbHeaderTips) ProtoReflect() protoreflect.Message { // Deprecated: Use DbHeaderTips.ProtoReflect.Descriptor instead. func (*DbHeaderTips) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{24} + return file_dbobjects_proto_rawDescGZIP(), []int{25} } func (x *DbHeaderTips) GetTips() []*DbHash { @@ -1523,7 +1578,7 @@ type DbTips struct { func (x *DbTips) Reset() { *x = DbTips{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[25] + mi := &file_dbobjects_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1536,7 +1591,7 @@ func (x *DbTips) String() string { func (*DbTips) ProtoMessage() {} func (x *DbTips) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[25] + mi := &file_dbobjects_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1549,7 +1604,7 @@ func (x *DbTips) ProtoReflect() protoreflect.Message { // Deprecated: Use DbTips.ProtoReflect.Descriptor instead. func (*DbTips) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{25} + return file_dbobjects_proto_rawDescGZIP(), []int{26} } func (x *DbTips) GetTips() []*DbHash { @@ -1570,7 +1625,7 @@ type DbVirtualDiffParents struct { func (x *DbVirtualDiffParents) Reset() { *x = DbVirtualDiffParents{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[26] + mi := &file_dbobjects_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1583,7 +1638,7 @@ func (x *DbVirtualDiffParents) String() string { func (*DbVirtualDiffParents) ProtoMessage() {} func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[26] + mi := &file_dbobjects_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1596,7 +1651,7 @@ func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { // Deprecated: Use DbVirtualDiffParents.ProtoReflect.Descriptor instead. func (*DbVirtualDiffParents) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{26} + return file_dbobjects_proto_rawDescGZIP(), []int{27} } func (x *DbVirtualDiffParents) GetVirtualDiffParents() []*DbHash { @@ -1617,7 +1672,7 @@ type DbBlockCount struct { func (x *DbBlockCount) Reset() { *x = DbBlockCount{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[27] + mi := &file_dbobjects_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1630,7 +1685,7 @@ func (x *DbBlockCount) String() string { func (*DbBlockCount) ProtoMessage() {} func (x *DbBlockCount) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[27] + mi := &file_dbobjects_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1643,7 +1698,7 @@ func (x *DbBlockCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DbBlockCount.ProtoReflect.Descriptor instead. func (*DbBlockCount) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{27} + return file_dbobjects_proto_rawDescGZIP(), []int{28} } func (x *DbBlockCount) GetCount() uint64 { @@ -1664,7 +1719,7 @@ type DbBlockHeaderCount struct { func (x *DbBlockHeaderCount) Reset() { *x = DbBlockHeaderCount{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[28] + mi := &file_dbobjects_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1677,7 +1732,7 @@ func (x *DbBlockHeaderCount) String() string { func (*DbBlockHeaderCount) ProtoMessage() {} func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[28] + mi := &file_dbobjects_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1690,7 +1745,7 @@ func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DbBlockHeaderCount.ProtoReflect.Descriptor instead. func (*DbBlockHeaderCount) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{28} + return file_dbobjects_proto_rawDescGZIP(), []int{29} } func (x *DbBlockHeaderCount) GetCount() uint64 { @@ -1715,7 +1770,7 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x87, 0x03, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, @@ -1741,7 +1796,7 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x0a, 0x06, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0xe6, 0x02, 0x0a, 0x0d, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, @@ -1782,167 +1837,176 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x64, 0x65, 0x78, 0x22, 0x37, 0x0a, 0x0f, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x13, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x77, 0x0a, 0x13, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, + 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x22, 0x34, 0x0a, 0x0e, 0x44, 0x62, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x6a, 0x0a, 0x10, 0x44, 0x62, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x56, 0x0a, - 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb6, 0x01, 0x0a, 0x15, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, - 0x68, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x19, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x09, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0xed, - 0x01, 0x0a, 0x1b, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x3e, - 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, - 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, - 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, - 0x12, 0x5c, 0x0a, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x76, - 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, - 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, - 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, 0x73, 0x74, - 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, - 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, 0x6f, 0x72, - 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0d, - 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a, - 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, - 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, 0x75, 0x65, - 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, - 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, 0x65, 0x73, - 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, 0x6d, 0x0a, - 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, - 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x34, 0x0a, 0x0e, 0x44, 0x62, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x6a, 0x0a, 0x10, 0x44, + 0x62, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x56, 0x0a, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x13, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb6, 0x01, 0x0a, 0x15, 0x44, 0x62, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, + 0x61, 0x12, 0x68, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x09, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, + 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, + 0x22, 0xed, 0x01, 0x0a, 0x1b, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, + 0x12, 0x3e, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, + 0x65, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x1b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x22, 0x76, 0x0a, 0x10, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, + 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, - 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, 0x74, 0x69, - 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, - 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, 0x0a, 0x0a, - 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x75, - 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x75, - 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, - 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x87, - 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x38, - 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, - 0x73, 0x65, 0x22, 0xfe, 0x01, 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, - 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, + 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x44, 0x62, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x22, 0xdb, 0x02, 0x0a, 0x13, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x47, 0x68, 0x6f, + 0x73, 0x74, 0x64, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, + 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x57, + 0x6f, 0x72, 0x6b, 0x12, 0x3d, 0x0a, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, - 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x43, - 0x0a, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x73, 0x68, 0x52, 0x0e, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x11, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x74, 0x22, 0x40, 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, - 0x44, 0x69, 0x66, 0x66, 0x12, 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, - 0x3f, 0x0a, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x22, 0x32, 0x0a, 0x1a, 0x44, 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x52, 0x0d, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x39, 0x0a, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x65, + 0x72, 0x67, 0x65, 0x53, 0x65, 0x74, 0x52, 0x65, 0x64, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x62, 0x6c, + 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, + 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x52, 0x12, 0x62, 0x6c, 0x75, + 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x22, + 0x6d, 0x0a, 0x14, 0x44, 0x62, 0x42, 0x6c, 0x75, 0x65, 0x73, 0x41, 0x6e, 0x74, 0x69, 0x63, 0x6f, + 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x6e, + 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x28, + 0x0a, 0x0a, 0x44, 0x62, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x65, 0x74, 0x22, 0x46, 0x0a, 0x09, 0x44, 0x62, 0x55, 0x74, + 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x39, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x22, 0x87, 0x01, 0x0a, 0x14, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x38, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x45, 0x0a, 0x11, 0x44, 0x62, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0xb9, 0x01, 0x0a, 0x0b, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0xfe, 0x01, + 0x0a, 0x12, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, + 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x43, 0x0a, 0x11, 0x66, 0x75, 0x74, + 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x11, 0x66, 0x75, 0x74, + 0x75, 0x72, 0x65, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x22, 0x40, + 0x0a, 0x16, 0x44, 0x62, 0x52, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x65, 0x6e, 0x64, + 0x22, 0x88, 0x01, 0x0a, 0x0a, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x44, 0x69, 0x66, 0x66, 0x12, + 0x39, 0x0a, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, + 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x74, 0x65, 0x6d, 0x52, 0x05, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x12, 0x3f, 0x0a, 0x08, 0x74, 0x6f, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, + 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x44, + 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, + 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, + 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, + 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, - 0x33, 0x0a, 0x06, 0x44, 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, - 0x74, 0x69, 0x70, 0x73, 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, - 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x73, 0x22, 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x24, + 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1957,7 +2021,7 @@ func file_dbobjects_proto_rawDescGZIP() []byte { return file_dbobjects_proto_rawDescData } -var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 29) +var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 30) var file_dbobjects_proto_goTypes = []interface{}{ (*DbBlock)(nil), // 0: serialization.DbBlock (*DbBlockHeader)(nil), // 1: serialization.DbBlockHeader @@ -1978,16 +2042,17 @@ var file_dbobjects_proto_goTypes = []interface{}{ (*DbMultiset)(nil), // 16: serialization.DbMultiset (*DbUtxoSet)(nil), // 17: serialization.DbUtxoSet (*DbUtxoCollectionItem)(nil), // 18: serialization.DbUtxoCollectionItem - (*DbUtxoEntry)(nil), // 19: serialization.DbUtxoEntry - (*DbReachabilityData)(nil), // 20: serialization.DbReachabilityData - (*DbReachabilityInterval)(nil), // 21: serialization.DbReachabilityInterval - (*DbUtxoDiff)(nil), // 22: serialization.DbUtxoDiff - (*DbPruningPointUTXOSetBytes)(nil), // 23: serialization.DbPruningPointUTXOSetBytes - (*DbHeaderTips)(nil), // 24: serialization.DbHeaderTips - (*DbTips)(nil), // 25: serialization.DbTips - (*DbVirtualDiffParents)(nil), // 26: serialization.DbVirtualDiffParents - (*DbBlockCount)(nil), // 27: serialization.DbBlockCount - (*DbBlockHeaderCount)(nil), // 28: serialization.DbBlockHeaderCount + (*DbScriptPublicKey)(nil), // 19: serialization.DbScriptPublicKey + (*DbUtxoEntry)(nil), // 20: serialization.DbUtxoEntry + (*DbReachabilityData)(nil), // 21: serialization.DbReachabilityData + (*DbReachabilityInterval)(nil), // 22: serialization.DbReachabilityInterval + (*DbUtxoDiff)(nil), // 23: serialization.DbUtxoDiff + (*DbPruningPointUTXOSetBytes)(nil), // 24: serialization.DbPruningPointUTXOSetBytes + (*DbHeaderTips)(nil), // 25: serialization.DbHeaderTips + (*DbTips)(nil), // 26: serialization.DbTips + (*DbVirtualDiffParents)(nil), // 27: serialization.DbVirtualDiffParents + (*DbBlockCount)(nil), // 28: serialization.DbBlockCount + (*DbBlockHeaderCount)(nil), // 29: serialization.DbBlockHeaderCount } var file_dbobjects_proto_depIdxs = []int32{ 1, // 0: serialization.DbBlock.header:type_name -> serialization.DbBlockHeader @@ -2002,35 +2067,37 @@ var file_dbobjects_proto_depIdxs = []int32{ 2, // 9: serialization.DbTransaction.payloadHash:type_name -> serialization.DbHash 5, // 10: serialization.DbTransactionInput.previousOutpoint:type_name -> serialization.DbOutpoint 6, // 11: serialization.DbOutpoint.transactionID:type_name -> serialization.DbTransactionId - 10, // 12: serialization.DbAcceptanceData.blockAcceptanceData:type_name -> serialization.DbBlockAcceptanceData - 11, // 13: serialization.DbBlockAcceptanceData.transactionAcceptanceData:type_name -> serialization.DbTransactionAcceptanceData - 2, // 14: serialization.DbBlockAcceptanceData.blockHash:type_name -> serialization.DbHash - 3, // 15: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction - 19, // 16: serialization.DbTransactionAcceptanceData.transactionInputUtxoEntries:type_name -> serialization.DbUtxoEntry - 2, // 17: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash - 2, // 18: serialization.DbBlockRelations.children:type_name -> serialization.DbHash - 2, // 19: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash - 2, // 20: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash - 2, // 21: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash - 15, // 22: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes - 2, // 23: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash - 18, // 24: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem - 5, // 25: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint - 19, // 26: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry - 2, // 27: serialization.DbReachabilityData.children:type_name -> serialization.DbHash - 2, // 28: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash - 21, // 29: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval - 2, // 30: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash - 18, // 31: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem - 18, // 32: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem - 2, // 33: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash - 2, // 34: serialization.DbTips.tips:type_name -> serialization.DbHash - 2, // 35: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash - 36, // [36:36] is the sub-list for method output_type - 36, // [36:36] is the sub-list for method input_type - 36, // [36:36] is the sub-list for extension type_name - 36, // [36:36] is the sub-list for extension extendee - 0, // [0:36] is the sub-list for field type_name + 19, // 12: serialization.DbTransactionOutput.scriptPublicKey:type_name -> serialization.DbScriptPublicKey + 10, // 13: serialization.DbAcceptanceData.blockAcceptanceData:type_name -> serialization.DbBlockAcceptanceData + 11, // 14: serialization.DbBlockAcceptanceData.transactionAcceptanceData:type_name -> serialization.DbTransactionAcceptanceData + 2, // 15: serialization.DbBlockAcceptanceData.blockHash:type_name -> serialization.DbHash + 3, // 16: serialization.DbTransactionAcceptanceData.transaction:type_name -> serialization.DbTransaction + 20, // 17: serialization.DbTransactionAcceptanceData.transactionInputUtxoEntries:type_name -> serialization.DbUtxoEntry + 2, // 18: serialization.DbBlockRelations.parents:type_name -> serialization.DbHash + 2, // 19: serialization.DbBlockRelations.children:type_name -> serialization.DbHash + 2, // 20: serialization.DbBlockGhostdagData.selectedParent:type_name -> serialization.DbHash + 2, // 21: serialization.DbBlockGhostdagData.mergeSetBlues:type_name -> serialization.DbHash + 2, // 22: serialization.DbBlockGhostdagData.mergeSetReds:type_name -> serialization.DbHash + 15, // 23: serialization.DbBlockGhostdagData.bluesAnticoneSizes:type_name -> serialization.DbBluesAnticoneSizes + 2, // 24: serialization.DbBluesAnticoneSizes.blueHash:type_name -> serialization.DbHash + 18, // 25: serialization.DbUtxoSet.items:type_name -> serialization.DbUtxoCollectionItem + 5, // 26: serialization.DbUtxoCollectionItem.outpoint:type_name -> serialization.DbOutpoint + 20, // 27: serialization.DbUtxoCollectionItem.utxoEntry:type_name -> serialization.DbUtxoEntry + 19, // 28: serialization.DbUtxoEntry.scriptPublicKey:type_name -> serialization.DbScriptPublicKey + 2, // 29: serialization.DbReachabilityData.children:type_name -> serialization.DbHash + 2, // 30: serialization.DbReachabilityData.parent:type_name -> serialization.DbHash + 22, // 31: serialization.DbReachabilityData.interval:type_name -> serialization.DbReachabilityInterval + 2, // 32: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash + 18, // 33: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem + 18, // 34: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem + 2, // 35: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash + 2, // 36: serialization.DbTips.tips:type_name -> serialization.DbHash + 2, // 37: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash + 38, // [38:38] is the sub-list for method output_type + 38, // [38:38] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_dbobjects_proto_init() } @@ -2268,7 +2335,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbUtxoEntry); i { + switch v := v.(*DbScriptPublicKey); i { case 0: return &v.state case 1: @@ -2280,7 +2347,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbReachabilityData); i { + switch v := v.(*DbUtxoEntry); i { case 0: return &v.state case 1: @@ -2292,7 +2359,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbReachabilityInterval); i { + switch v := v.(*DbReachabilityData); i { case 0: return &v.state case 1: @@ -2304,7 +2371,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbUtxoDiff); i { + switch v := v.(*DbReachabilityInterval); i { case 0: return &v.state case 1: @@ -2316,7 +2383,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbPruningPointUTXOSetBytes); i { + switch v := v.(*DbUtxoDiff); i { case 0: return &v.state case 1: @@ -2328,7 +2395,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbHeaderTips); i { + switch v := v.(*DbPruningPointUTXOSetBytes); i { case 0: return &v.state case 1: @@ -2340,7 +2407,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbTips); i { + switch v := v.(*DbHeaderTips); i { case 0: return &v.state case 1: @@ -2352,7 +2419,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbVirtualDiffParents); i { + switch v := v.(*DbTips); i { case 0: return &v.state case 1: @@ -2364,7 +2431,7 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbBlockCount); i { + switch v := v.(*DbVirtualDiffParents); i { case 0: return &v.state case 1: @@ -2376,6 +2443,18 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DbBlockCount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dbobjects_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbBlockHeaderCount); i { case 0: return &v.state @@ -2394,7 +2473,7 @@ func file_dbobjects_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_dbobjects_proto_rawDesc, NumEnums: 0, - NumMessages: 29, + NumMessages: 30, NumExtensions: 0, NumServices: 0, }, diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index ddb972404..4f85e453c 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -9,7 +9,7 @@ message DbBlock { } message DbBlockHeader { - int32 version = 1; + uint32 version = 1; repeated DbHash parentHashes = 2; DbHash hashMerkleRoot = 3; DbHash acceptedIDMerkleRoot = 4; @@ -24,7 +24,7 @@ message DbHash { } message DbTransaction { - int32 version = 1; + uint32 version = 1; repeated DbTransactionInput inputs = 2; repeated DbTransactionOutput outputs = 3; uint64 lockTime = 4; @@ -51,7 +51,7 @@ message DbTransactionId { message DbTransactionOutput { uint64 value = 1; - bytes scriptPublicKey = 2; + DbScriptPublicKey scriptPublicKey = 2; } message DbSubnetworkId { @@ -110,9 +110,14 @@ message DbUtxoCollectionItem { DbUtxoEntry utxoEntry = 2; } +message DbScriptPublicKey { + bytes script = 1; + uint32 version = 2; +} + message DbUtxoEntry { uint64 amount = 1; - bytes scriptPublicKey = 2; + DbScriptPublicKey scriptPublicKey = 2; uint64 blockBlueScore = 3; bool isCoinbase = 4; } @@ -156,4 +161,4 @@ message DbBlockCount { message DbBlockHeaderCount { uint64 count = 1; -} +} \ No newline at end of file diff --git a/domain/consensus/database/serialization/transaction.go b/domain/consensus/database/serialization/transaction.go index 60d8a30eb..af8bf77fd 100644 --- a/domain/consensus/database/serialization/transaction.go +++ b/domain/consensus/database/serialization/transaction.go @@ -2,6 +2,7 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" ) // DomainTransactionToDbTransaction converts DomainTransaction to DbTransaction @@ -17,14 +18,15 @@ func DomainTransactionToDbTransaction(domainTransaction *externalapi.DomainTrans dbOutputs := make([]*DbTransactionOutput, len(domainTransaction.Outputs)) for i, domainTransactionOutput := range domainTransaction.Outputs { + dbScriptPublicKey := ScriptPublicKeyToDBScriptPublicKey(domainTransactionOutput.ScriptPublicKey) dbOutputs[i] = &DbTransactionOutput{ Value: domainTransactionOutput.Value, - ScriptPublicKey: domainTransactionOutput.ScriptPublicKey, + ScriptPublicKey: dbScriptPublicKey, } } return &DbTransaction{ - Version: domainTransaction.Version, + Version: uint32(domainTransaction.Version), Inputs: dbInputs, Outputs: dbOutputs, LockTime: domainTransaction.LockTime, @@ -61,14 +63,21 @@ func DbTransactionToDomainTransaction(dbTransaction *DbTransaction) (*externalap domainOutputs := make([]*externalapi.DomainTransactionOutput, len(dbTransaction.Outputs)) for i, dbTransactionOutput := range dbTransaction.Outputs { + scriptPublicKey, err := DBScriptPublicKeyToScriptPublicKey(dbTransactionOutput.ScriptPublicKey) + if err != nil { + return nil, err + } domainOutputs[i] = &externalapi.DomainTransactionOutput{ Value: dbTransactionOutput.Value, - ScriptPublicKey: dbTransactionOutput.ScriptPublicKey, + ScriptPublicKey: scriptPublicKey, } } + if dbTransaction.Version > 0xFFFF { + return nil, errors.Errorf("The transaction version is bigger then uint16.") + } return &externalapi.DomainTransaction{ - Version: dbTransaction.Version, + Version: uint16(dbTransaction.Version), Inputs: domainInputs, Outputs: domainOutputs, LockTime: dbTransaction.LockTime, diff --git a/domain/consensus/database/serialization/utxo_collection.go b/domain/consensus/database/serialization/utxo_collection.go index 703364f74..71a272d9b 100644 --- a/domain/consensus/database/serialization/utxo_collection.go +++ b/domain/consensus/database/serialization/utxo_collection.go @@ -33,8 +33,11 @@ func dbUTXOCollectionToUTXOCollection(items []*DbUtxoCollectionItem) (model.UTXO if err != nil { return nil, err } - - utxoMap[*outpoint] = DBUTXOEntryToUTXOEntry(item.UtxoEntry) + utxoEntry, err := DBUTXOEntryToUTXOEntry(item.UtxoEntry) + if err != nil { + return nil, err + } + utxoMap[*outpoint] = utxoEntry } return utxo.NewUTXOCollection(utxoMap), nil } diff --git a/domain/consensus/database/serialization/utxo_entry.go b/domain/consensus/database/serialization/utxo_entry.go index f8ec85873..d8db65f8b 100644 --- a/domain/consensus/database/serialization/utxo_entry.go +++ b/domain/consensus/database/serialization/utxo_entry.go @@ -3,19 +3,38 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/pkg/errors" ) +// ScriptPublicKeyToDBScriptPublicKey converts ScriptPublicKey to DBScriptPublicKey +func ScriptPublicKeyToDBScriptPublicKey(scriptPublicKey *externalapi.ScriptPublicKey) *DbScriptPublicKey { + return &DbScriptPublicKey{Script: scriptPublicKey.Script, Version: uint32(scriptPublicKey.Version)} +} + +// DBScriptPublicKeyToScriptPublicKey convert DbScriptPublicKey ro ScriptPublicKey +func DBScriptPublicKeyToScriptPublicKey(dbScriptPublicKey *DbScriptPublicKey) (*externalapi.ScriptPublicKey, error) { + if dbScriptPublicKey.Version > 0xFFFF { + return nil, errors.Errorf("The version on ScriptPublicKey is bigger then uint16.") + } + return &externalapi.ScriptPublicKey{Script: dbScriptPublicKey.Script, Version: uint16(dbScriptPublicKey.Version)}, nil +} + // UTXOEntryToDBUTXOEntry converts UTXOEntry to DbUtxoEntry func UTXOEntryToDBUTXOEntry(utxoEntry externalapi.UTXOEntry) *DbUtxoEntry { + dbScriptPublicKey := ScriptPublicKeyToDBScriptPublicKey(utxoEntry.ScriptPublicKey()) return &DbUtxoEntry{ Amount: utxoEntry.Amount(), - ScriptPublicKey: utxoEntry.ScriptPublicKey(), + ScriptPublicKey: dbScriptPublicKey, BlockBlueScore: utxoEntry.BlockBlueScore(), IsCoinbase: utxoEntry.IsCoinbase(), } } // DBUTXOEntryToUTXOEntry convert DbUtxoEntry ro UTXOEntry -func DBUTXOEntryToUTXOEntry(dbUtxoEntry *DbUtxoEntry) externalapi.UTXOEntry { - return utxo.NewUTXOEntry(dbUtxoEntry.Amount, dbUtxoEntry.ScriptPublicKey, dbUtxoEntry.IsCoinbase, dbUtxoEntry.BlockBlueScore) +func DBUTXOEntryToUTXOEntry(dbUtxoEntry *DbUtxoEntry) (externalapi.UTXOEntry, error) { + scriptPublicKey, err := DBScriptPublicKeyToScriptPublicKey(dbUtxoEntry.ScriptPublicKey) + if err != nil { + return nil, err + } + return utxo.NewUTXOEntry(dbUtxoEntry.Amount, scriptPublicKey, dbUtxoEntry.IsCoinbase, dbUtxoEntry.BlockBlueScore), nil } diff --git a/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go b/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go index 6da8fab33..387d98e95 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo_serialization.go @@ -30,6 +30,5 @@ func deserializeUTXOEntry(entryBytes []byte) (externalapi.UTXOEntry, error) { if err != nil { return nil, err } - - return serialization.DBUTXOEntryToUTXOEntry(dbEntry), nil + return serialization.DBUTXOEntryToUTXOEntry(dbEntry) } diff --git a/domain/consensus/model/acceptancedata_equal_clone_test.go b/domain/consensus/model/acceptancedata_equal_clone_test.go index 1e96b37e6..3add3b489 100644 --- a/domain/consensus/model/acceptancedata_equal_clone_test.go +++ b/domain/consensus/model/acceptancedata_equal_clone_test.go @@ -18,11 +18,11 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -42,7 +42,7 @@ func initTestTransactionAcceptanceDataForClone() []*externalapi.TransactionAccep }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }, } return tests @@ -67,11 +67,11 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -91,7 +91,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, } var testTransactionAcceptanceData1 = externalapi.TransactionAcceptanceData{ @@ -101,11 +101,11 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -124,7 +124,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, } // test 2: different transactions var testTransactionAcceptanceData2 = externalapi.TransactionAcceptanceData{ @@ -134,11 +134,11 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -157,7 +157,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, } //test 3: different Fee var testTransactionAcceptanceData3 = externalapi.TransactionAcceptanceData{ @@ -167,11 +167,11 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -191,7 +191,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 2, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, } //test 4: different isAccepted var testTransactionAcceptanceData4 = externalapi.TransactionAcceptanceData{ @@ -201,11 +201,11 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -225,7 +225,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, false, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, } //test 5: different TransactionInputUTXOEntries @@ -236,11 +236,11 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -260,7 +260,7 @@ func initTransactionAcceptanceDataForEqual() []testTransactionAcceptanceDataStru }, 1, false, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 4, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, } tests := []testTransactionAcceptanceDataStruct{ @@ -346,11 +346,11 @@ func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -370,7 +370,7 @@ func initTestBlockAcceptanceDataForClone() []*externalapi.BlockAcceptanceData { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}, }, } @@ -398,11 +398,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -422,7 +422,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}} //test 1: structs are equal var testBlockAcceptanceData1 = externalapi.BlockAcceptanceData{ @@ -435,11 +435,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -459,7 +459,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}} // test 2: different size var testBlockAcceptanceData2 = externalapi.BlockAcceptanceData{ @@ -472,11 +472,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -496,7 +496,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }, {}}} //test 3: different transactions, same size var testBlockAcceptanceData3 = externalapi.BlockAcceptanceData{ @@ -509,11 +509,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -533,7 +533,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, false, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}} // test 4 - different block hash @@ -547,11 +547,11 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -571,7 +571,7 @@ func iniBlockAcceptanceDataForEqual() []testBlockAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}} tests := []testBlockAcceptanceDataStruct{ @@ -655,11 +655,11 @@ func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -679,7 +679,7 @@ func initTestAcceptanceDataForClone() []externalapi.AcceptanceData { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}, }, } @@ -709,11 +709,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -733,7 +733,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}}} //test 1: structs are equal var testAcceptanceData1 = []*externalapi.BlockAcceptanceData{ @@ -746,11 +746,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -770,7 +770,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}}} // test 2: different size var testAcceptanceData2 = []*externalapi.BlockAcceptanceData{ @@ -783,11 +783,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -807,7 +807,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}}, {}} //test 3: different transactions, same size var testAcceptanceData3 = []*externalapi.BlockAcceptanceData{ @@ -820,11 +820,11 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -844,7 +844,7 @@ func initAcceptanceDataForEqual() []testAcceptanceDataStruct { }, 1, true, - []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + []externalapi.UTXOEntry{utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }}}} tests := []testAcceptanceDataStruct{ diff --git a/domain/consensus/model/externalapi/block.go b/domain/consensus/model/externalapi/block.go index c0244e6a1..60d7c539d 100644 --- a/domain/consensus/model/externalapi/block.go +++ b/domain/consensus/model/externalapi/block.go @@ -54,7 +54,7 @@ type BlockHeader interface { // BaseBlockHeader represents the header part of a Kaspa block type BaseBlockHeader interface { - Version() int32 + Version() uint16 ParentHashes() []*DomainHash HashMerkleRoot() *DomainHash AcceptedIDMerkleRoot() *DomainHash diff --git a/domain/consensus/model/externalapi/coinbase.go b/domain/consensus/model/externalapi/coinbase.go index 5770ed48a..63c6438a7 100644 --- a/domain/consensus/model/externalapi/coinbase.go +++ b/domain/consensus/model/externalapi/coinbase.go @@ -3,20 +3,21 @@ package externalapi // DomainCoinbaseData contains data by which a coinbase transaction // is built type DomainCoinbaseData struct { - ScriptPublicKey []byte + ScriptPublicKey *ScriptPublicKey ExtraData []byte } // Clone returns a clone of DomainCoinbaseData func (dcd *DomainCoinbaseData) Clone() *DomainCoinbaseData { - scriptPubKeyClone := make([]byte, len(dcd.ScriptPublicKey)) - copy(scriptPubKeyClone, dcd.ScriptPublicKey) + + scriptPubKeyClone := make([]byte, len(dcd.ScriptPublicKey.Script)) + copy(scriptPubKeyClone, dcd.ScriptPublicKey.Script) extraDataClone := make([]byte, len(dcd.ExtraData)) copy(extraDataClone, dcd.ExtraData) return &DomainCoinbaseData{ - ScriptPublicKey: scriptPubKeyClone, + ScriptPublicKey: &ScriptPublicKey{Script: scriptPubKeyClone, Version: dcd.ScriptPublicKey.Version}, ExtraData: extraDataClone, } } diff --git a/domain/consensus/model/externalapi/coinbase_clone_test.go b/domain/consensus/model/externalapi/coinbase_clone_test.go index b7c29bbc7..df465d2d7 100644 --- a/domain/consensus/model/externalapi/coinbase_clone_test.go +++ b/domain/consensus/model/externalapi/coinbase_clone_test.go @@ -9,10 +9,10 @@ func initTestCoinbaseDataStructsForClone() []*DomainCoinbaseData { tests := []*DomainCoinbaseData{ { - []byte{1, 2, 3, 4, 5, 6}, + &ScriptPublicKey{Script: []byte{1, 2, 3, 4, 5, 6}, Version: 0}, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, }, { - []byte{0, 0, 0, 0, 55}, + &ScriptPublicKey{Script: []byte{0, 0, 0, 0, 55}, Version: 0}, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index 781da21bf..e65c871cc 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -9,7 +9,7 @@ import ( // DomainTransaction represents a Kaspa transaction type DomainTransaction struct { - Version int32 + Version uint16 Inputs []*DomainTransactionInput Outputs []*DomainTransactionOutput LockTime uint64 @@ -223,15 +223,21 @@ func NewDomainOutpoint(id *DomainTransactionID, index uint32) *DomainOutpoint { } } +// ScriptPublicKey represents a Kaspad ScriptPublicKey +type ScriptPublicKey struct { + Script []byte + Version uint16 +} + // DomainTransactionOutput represents a Kaspad transaction output type DomainTransactionOutput struct { Value uint64 - ScriptPublicKey []byte + ScriptPublicKey *ScriptPublicKey } // If this doesn't compile, it means the type definition has been changed, so it's // an indication to update Equal and Clone accordingly. -var _ = DomainTransactionOutput{0, []byte{}} +var _ = DomainTransactionOutput{0, &ScriptPublicKey{Script: []byte{}, Version: 0}} // Equal returns whether output equals to other func (output *DomainTransactionOutput) Equal(other *DomainTransactionOutput) bool { @@ -243,7 +249,7 @@ func (output *DomainTransactionOutput) Equal(other *DomainTransactionOutput) boo return false } - if !bytes.Equal(output.ScriptPublicKey, other.ScriptPublicKey) { + if !bytes.Equal(output.ScriptPublicKey.Script, other.ScriptPublicKey.Script) { return false } @@ -252,8 +258,10 @@ func (output *DomainTransactionOutput) Equal(other *DomainTransactionOutput) boo // Clone returns a clone of DomainTransactionOutput func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput { - scriptPublicKeyClone := make([]byte, len(output.ScriptPublicKey)) - copy(scriptPublicKeyClone, output.ScriptPublicKey) + scriptPublicKeyClone := &ScriptPublicKey{ + Script: make([]byte, len(output.ScriptPublicKey.Script)), + Version: output.ScriptPublicKey.Version} + copy(scriptPublicKeyClone.Script, output.ScriptPublicKey.Script) return &DomainTransactionOutput{ Value: output.Value, diff --git a/domain/consensus/model/externalapi/transaction_equal_clone_test.go b/domain/consensus/model/externalapi/transaction_equal_clone_test.go index 48065b0fa..76f0f79a9 100644 --- a/domain/consensus/model/externalapi/transaction_equal_clone_test.go +++ b/domain/consensus/model/externalapi/transaction_equal_clone_test.go @@ -71,11 +71,11 @@ func initTestBaseTransaction() *externalapi.DomainTransaction { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -103,11 +103,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -131,11 +131,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 3}}, //Changed + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}, //Changed {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -159,11 +159,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01, 0x02}, //Changed 1, @@ -187,11 +187,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -215,10 +215,10 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -244,11 +244,12 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, + externalapi.DomainSubnetworkID{0x01}, 1, *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -272,11 +273,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -300,10 +301,10 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -327,10 +328,10 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -354,10 +355,10 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 2, //Changed externalapi.DomainSubnetworkID{0x01}, 1, @@ -381,15 +382,15 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, {externalapi.DomainOutpoint{ *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -413,11 +414,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}, {uint64(0xFFFFF), - []byte{1, 2, 3}}}, //changed Outputs + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}, {uint64(0xFFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2, 3}, Version: 0}}}, //changed Outputs 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -441,10 +442,10 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -465,10 +466,10 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed sequence - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 1, @@ -493,11 +494,11 @@ func initTestTransactionToCompare() []*transactionToCompare { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}}, []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), - []byte{1, 3}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, 1, externalapi.DomainSubnetworkID{0x01}, 2, // Changed @@ -529,10 +530,10 @@ func initTestDomainTransactionForClone() []*externalapi.DomainTransaction { *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2)}, + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2)}, }, Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), - []byte{1, 2}}}, + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}}, LockTime: 1, SubnetworkID: externalapi.DomainSubnetworkID{0x01}, Gas: 1, @@ -688,7 +689,7 @@ func initTestBaseDomainTransactionInput() *externalapi.DomainTransactionInput { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), } return basetxInput } @@ -699,7 +700,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: true, }, { @@ -707,7 +708,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, false, 2), // Changed + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, false, 2), // Changed }, expectsPanic: true, }, { @@ -723,7 +724,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), // Changed - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: false, }, { @@ -731,7 +732,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3, 4}, // Changed uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: false, }, { @@ -739,7 +740,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, expectedResult: false, }, { @@ -747,7 +748,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(2 /* Changed */, []byte{0, 1, 2, 3}, true, 2), // Changed + utxo.NewUTXOEntry(2 /* Changed */, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), // Changed }, expectedResult: false, }, { @@ -755,7 +756,7 @@ func initTestDomainTxInputToCompare() []*transactionInputToCompare { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01, 0x02}), 0xFFFF}, // Changed []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(3 /* Changed */, []byte{0, 1, 2, 3}, true, 3), // Changed + utxo.NewUTXOEntry(3 /* Changed */, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 3), // Changed }, expectedResult: false, }, { @@ -772,19 +773,19 @@ func initTestDomainTransactionInputForClone() []*externalapi.DomainTransactionIn externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFFF), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }, { externalapi.DomainOutpoint{*externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), 0xFFFF}, []byte{1, 2, 3}, uint64(0xFFFFFFF0), - utxo.NewUTXOEntry(1, []byte{0, 1, 2, 3}, true, 2), + utxo.NewUTXOEntry(1, &externalapi.ScriptPublicKey{Script: []byte{0, 1, 2, 3}, Version: 0}, true, 2), }} return txInput } @@ -792,7 +793,7 @@ func initTestDomainTransactionInputForClone() []*externalapi.DomainTransactionIn func initTestBaseDomainTransactionOutput() *externalapi.DomainTransactionOutput { basetxOutput := &externalapi.DomainTransactionOutput{ 0xFFFFFFFF, - []byte{0xFF, 0xFF}, + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF}, Version: 0}, } return basetxOutput } @@ -801,10 +802,10 @@ func initTestDomainTransactionOutputForClone() []*externalapi.DomainTransactionO txInput := []*externalapi.DomainTransactionOutput{ { 0xFFFFFFFF, - []byte{0xF0, 0xFF}, + &externalapi.ScriptPublicKey{Script: []byte{0xF0, 0xFF}, Version: 0}, }, { 0xFFFFFFF1, - []byte{0xFF, 0xFF}, + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF}, Version: 0}, }} return txInput } @@ -816,18 +817,18 @@ func initTestDomainTransactionOutputForEqual() []testDomainTransactionOutputStru transactionOutputToCompareTo: []*transactionOutputToCompare{{ tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFFF, - []byte{0xFF, 0xFF}}, + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF}, Version: 0}}, expectedResult: true, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFFF, - []byte{0xF0, 0xFF}, // Changed + &externalapi.ScriptPublicKey{Script: []byte{0xF0, 0xFF}, Version: 0}, // Changed }, expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFF0, // Changed - []byte{0xFF, 0xFF}, + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF}, Version: 0}, }, expectedResult: false, }, { @@ -835,14 +836,13 @@ func initTestDomainTransactionOutputForEqual() []testDomainTransactionOutputStru expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ - 0xFFFFFFF0, // Changed - []byte{0xFF, 0xFF, 0x01}, // Changed - }, + 0xFFFFFFF0, // Changed + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF, 0x01}, Version: 0}}, // Changed expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFF0, // Changed - []byte{}, // Changed + &externalapi.ScriptPublicKey{Script: []byte{}, Version: 0}, // Changed }, expectedResult: false, }}, @@ -855,30 +855,30 @@ func initTestDomainTransactionOutputForEqual() []testDomainTransactionOutputStru }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFFF, - []byte{0xFF, 0xFF}}, + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF}, Version: 0}}, expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFFF, - []byte{0xF0, 0xFF}, // Changed + &externalapi.ScriptPublicKey{Script: []byte{0xF0, 0xFF}, Version: 0}, // Changed }, expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFF0, // Changed - []byte{0xFF, 0xFF}, + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF}, Version: 0}, }, expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFF0, - []byte{0xFF, 0xFF, 0x01}, // Changed + &externalapi.ScriptPublicKey{Script: []byte{0xFF, 0xFF, 0x01}, Version: 0}, // Changed }, expectedResult: false, }, { tx: &externalapi.DomainTransactionOutput{ 0xFFFFFFF0, - []byte{}, // Changed + &externalapi.ScriptPublicKey{Script: []byte{}, Version: 0}, // Changed }, expectedResult: false, }}, diff --git a/domain/consensus/model/externalapi/utxoentry.go b/domain/consensus/model/externalapi/utxoentry.go index efc803809..d3a83843e 100644 --- a/domain/consensus/model/externalapi/utxoentry.go +++ b/domain/consensus/model/externalapi/utxoentry.go @@ -6,8 +6,8 @@ package externalapi // much it pays. type UTXOEntry interface { Amount() uint64 - ScriptPublicKey() []byte // The public key script for the output. - BlockBlueScore() uint64 // Blue score of the block accepting the tx. + ScriptPublicKey() *ScriptPublicKey // The public key script for the output. + BlockBlueScore() uint64 // Blue score of the block accepting the tx. IsCoinbase() bool Equal(other UTXOEntry) bool } diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 1246e9bd9..044134f67 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -120,7 +120,7 @@ func (bb *blockBuilder) buildHeader(transactions []*externalapi.DomainTransactio } return blockheader.NewImmutableBlockHeader( - constants.BlockVersion, + constants.MaxBlockVersion, parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 697672d60..6316216e4 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -83,7 +83,7 @@ func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.D bb.nonceCounter++ return blockheader.NewImmutableBlockHeader( - constants.BlockVersion, + constants.MaxBlockVersion, parentHashes, hashMerkleRoot, acceptedIDMerkleRoot, diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 6171cd327..fc1559fe2 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -121,7 +121,7 @@ func TestCheckBlockSanity(t *testing.T) { var unOrderedParentsBlock = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 0x10000000, + 0x00000000, []*externalapi.DomainHash{ externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, @@ -137,10 +137,10 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ }), }, externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xf8, 0x55, 0x7b, 0xd0, 0xda, 0xf2, 0x06, 0x8b, - 0x3b, 0xb1, 0x93, 0x5a, 0x2c, 0x52, 0x43, 0xf0, - 0x02, 0xf2, 0xb1, 0x40, 0x81, 0x2c, 0x0c, 0x15, - 0x8d, 0x04, 0x3d, 0xe2, 0x23, 0x54, 0x98, 0x88, + 0x33, 0x77, 0x88, 0xd7, 0x8a, 0xd7, 0x49, 0xbf, + 0xce, 0x97, 0x58, 0x4f, 0x05, 0x4c, 0xbb, 0x18, + 0xb4, 0xe4, 0x73, 0x6e, 0x1f, 0xcd, 0x57, 0x5d, + 0x6b, 0xe4, 0xb1, 0x01, 0xea, 0x7f, 0x01, 0xd7, }), externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, @@ -160,7 +160,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ ), Transactions: []*externalapi.DomainTransaction{ { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -178,23 +178,23 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0x12a05f200, // 5000000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x51, - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDCoinbase, - Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, + Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, - 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, - 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, - 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, + 0x2e, 0xb5, 0xe8, 0x1c, 0xe2, 0xa7, 0x67, 0x84, + 0xd1, 0x1a, 0x42, 0x66, 0xcf, 0x12, 0x7f, 0x10, + 0x9b, 0x6f, 0x84, 0x63, 0xf5, 0x65, 0x5a, 0x65, + 0xec, 0xed, 0x60, 0xc6, 0x32, 0x7a, 0x9d, 0x08, }), }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -235,7 +235,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0x2123e300, // 556000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -244,11 +244,11 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ 0xf7, 0xf5, 0x8b, 0x32, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, { Value: 0x108e20f00, // 4444000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -257,14 +257,14 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ 0x52, 0xde, 0x3d, 0x7c, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -304,7 +304,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0xf4240, // 1000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -313,11 +313,11 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ 0xad, 0xbe, 0x7e, 0x10, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, { Value: 0x11d260c0, // 299000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -326,14 +326,14 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ 0xb3, 0x40, 0x9c, 0xd9, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -374,7 +374,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0xf4240, // 1000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -383,7 +383,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ 0xf2, 0xeb, 0x9e, 0xe0, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, @@ -395,7 +395,7 @@ var unOrderedParentsBlock = externalapi.DomainBlock{ // exampleValidBlock defines a sample valid block var exampleValidBlock = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 0x10000000, + 0x00000000, []*externalapi.DomainHash{ externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, @@ -411,10 +411,10 @@ var exampleValidBlock = externalapi.DomainBlock{ }), }, externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x33, 0x70, 0xa7, 0x40, 0x9f, 0x2d, 0x87, 0xe1, - 0x26, 0xaf, 0x0f, 0x5c, 0x7e, 0xc3, 0x84, 0x5e, - 0x4f, 0x68, 0x42, 0x0a, 0xbf, 0x90, 0xcd, 0xef, - 0x94, 0x9b, 0xe1, 0x9a, 0xf7, 0xdd, 0xb0, 0xb5, + 0x8f, 0x2e, 0x67, 0x13, 0x86, 0xf9, 0x4c, 0x2a, + 0x1d, 0x1a, 0xc1, 0xf0, 0x30, 0x88, 0xfd, 0x48, + 0x20, 0xf3, 0x50, 0xd1, 0xfb, 0x6d, 0x06, 0x39, + 0x72, 0xaa, 0x6f, 0x78, 0x22, 0x64, 0x83, 0x19, }), externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3, @@ -429,7 +429,7 @@ var exampleValidBlock = externalapi.DomainBlock{ ), Transactions: []*externalapi.DomainTransaction{ { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -448,25 +448,25 @@ var exampleValidBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0x12a05f200, // 5000000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, 0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87, - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDCoinbase, - Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, + Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, - 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, - 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, - 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, + 0x2e, 0xb5, 0xe8, 0x1c, 0xe2, 0xa7, 0x67, 0x84, + 0xd1, 0x1a, 0x42, 0x66, 0xcf, 0x12, 0x7f, 0x10, + 0x9b, 0x6f, 0x84, 0x63, 0xf5, 0x65, 0x5a, 0x65, + 0xec, 0xed, 0x60, 0xc6, 0x32, 0x7a, 0x9d, 0x08, }), }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -496,7 +496,7 @@ var exampleValidBlock = externalapi.DomainBlock{ SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -537,7 +537,7 @@ var exampleValidBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0x2123e300, // 556000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -546,11 +546,11 @@ var exampleValidBlock = externalapi.DomainBlock{ 0xf7, 0xf5, 0x8b, 0x32, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, { Value: 0x108e20f00, // 4444000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -559,14 +559,14 @@ var exampleValidBlock = externalapi.DomainBlock{ 0x52, 0xde, 0x3d, 0x7c, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -606,7 +606,7 @@ var exampleValidBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0xf4240, // 1000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -615,11 +615,11 @@ var exampleValidBlock = externalapi.DomainBlock{ 0xad, 0xbe, 0x7e, 0x10, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, { Value: 0x11d260c0, // 299000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -628,14 +628,14 @@ var exampleValidBlock = externalapi.DomainBlock{ 0xb3, 0x40, 0x9c, 0xd9, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -676,7 +676,7 @@ var exampleValidBlock = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0xf4240, // 1000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -685,7 +685,7 @@ var exampleValidBlock = externalapi.DomainBlock{ 0xf2, 0xeb, 0x9e, 0xe0, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, @@ -697,7 +697,7 @@ var exampleValidBlock = externalapi.DomainBlock{ // blockWithWrongTxOrder defines invalid block 100,000 of the block DAG. var blockWithWrongTxOrder = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 1, + 0, []*externalapi.DomainHash{ externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, @@ -736,7 +736,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ ), Transactions: []*externalapi.DomainTransaction{ { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -755,25 +755,26 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0x12a05f200, // 5000000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, 0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87, - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDCoinbase, - Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0}, + Payload: []byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x31, 0x3d, 0xd5, 0x20, 0x4c, 0xc9, 0x89, 0x20, - 0x46, 0x22, 0x59, 0xe0, 0x0d, 0x33, 0x27, 0xe6, - 0x04, 0x20, 0x5f, 0x4e, 0xd5, 0xf4, 0xf9, 0x2f, - 0x1a, 0xf0, 0x13, 0x0b, 0xe3, 0x92, 0xd8, 0xff, + 0x2e, 0xb5, 0xe8, 0x1c, 0xe2, 0xa7, 0x67, 0x84, + 0xd1, 0x1a, 0x42, 0x66, 0xcf, 0x12, 0x7f, 0x10, + 0x9b, 0x6f, 0x84, 0x63, 0xf5, 0x65, 0x5a, 0x65, + 0xec, 0xed, 0x60, 0xc6, 0x32, 0x7a, 0x9d, 0x08, }), }, + { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -803,7 +804,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -844,7 +845,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0x2123e300, // 556000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -853,11 +854,11 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ 0xf7, 0xf5, 0x8b, 0x32, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, { Value: 0x108e20f00, // 4444000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -866,7 +867,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ 0x52, 0xde, 0x3d, 0x7c, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, @@ -875,7 +876,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0xFF, 0xFF}), }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -915,7 +916,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0xf4240, // 1000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -924,11 +925,11 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ 0xad, 0xbe, 0x7e, 0x10, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, { Value: 0x11d260c0, // 299000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -937,14 +938,14 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ 0xb3, 0x40, 0x9c, 0xd9, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, SubnetworkID: subnetworks.SubnetworkIDNative, }, { - Version: 1, + Version: 0, Inputs: []*externalapi.DomainTransactionInput{ { PreviousOutpoint: externalapi.DomainOutpoint{ @@ -985,7 +986,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ Outputs: []*externalapi.DomainTransactionOutput{ { Value: 0xf4240, // 1000000 - ScriptPublicKey: []byte{ + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 @@ -994,7 +995,7 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ 0xf2, 0xeb, 0x9e, 0xe0, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG - }, + }, Version: 0}, }, }, LockTime: 0, diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go index f6de3184a..cb22346b8 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation.go @@ -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/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" @@ -20,6 +21,11 @@ func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.Domain return err } + err = v.checkBlockVersion(header) + if err != nil { + return err + } + err = v.checkBlockTimestampInIsolation(header) if err != nil { return err @@ -46,6 +52,14 @@ func (v *blockValidator) checkParentsLimit(header externalapi.BlockHeader) error return nil } +func (v *blockValidator) checkBlockVersion(header externalapi.BlockHeader) error { + if header.Version() > constants.MaxBlockVersion { + return errors.Wrapf( + ruleerrors.ErrBlockVersionIsUnknown, "The block version is unknown.") + } + return nil +} + func (v *blockValidator) checkBlockTimestampInIsolation(header externalapi.BlockHeader) error { blockTimestamp := header.TimeInMilliseconds() now := mstime.Now().UnixMilliseconds() diff --git a/domain/consensus/processes/blockvalidator/header_estimated_size.go b/domain/consensus/processes/blockvalidator/header_estimated_size.go index 025197ad5..0f7b021bc 100644 --- a/domain/consensus/processes/blockvalidator/header_estimated_size.go +++ b/domain/consensus/processes/blockvalidator/header_estimated_size.go @@ -9,7 +9,7 @@ import ( // it's only used to check block size limit violation. func (v *blockValidator) headerEstimatedSerializedSize(header externalapi.BlockHeader) uint64 { size := uint64(0) - size += 4 // Version (int32) + size += 2 // Version (uint16) size += 8 // number of parents (uint64) size += uint64(externalapi.DomainHashSize * len(header.ParentHashes())) // parents diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index a9146818e..ccf4cb71c 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -51,7 +51,7 @@ func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Dom payloadHash := hashes.PayloadHash(payload) return &externalapi.DomainTransaction{ - Version: constants.TransactionVersion, + Version: constants.MaxTransactionVersion, Inputs: []*externalapi.DomainTransactionInput{}, Outputs: txOuts, LockTime: 0, @@ -85,7 +85,7 @@ func (c *coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.Doma return nil, false, nil } - // the ScriptPubKey for the coinbase is parsed from the coinbase payload + // the ScriptPublicKey for the coinbase is parsed from the coinbase payload _, coinbaseData, err := c.ExtractCoinbaseDataAndBlueScore(blockAcceptanceData.TransactionAcceptanceData[0].Transaction) if err != nil { return nil, false, err diff --git a/domain/consensus/processes/coinbasemanager/payload.go b/domain/consensus/processes/coinbasemanager/payload.go index 5041072ed..a5ad83c7d 100644 --- a/domain/consensus/processes/coinbasemanager/payload.go +++ b/domain/consensus/processes/coinbasemanager/payload.go @@ -12,24 +12,28 @@ import ( var byteOrder = binary.LittleEndian const uint64Len = 8 +const uint16Len = 2 const lengthOfscriptPubKeyLength = 1 +const lengthOfVersionScriptPubKey = uint16Len // serializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data. func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) { - scriptPubKeyLength := len(coinbaseData.ScriptPublicKey) - if uint64(scriptPubKeyLength) > c.coinbasePayloadScriptPublicKeyMaxLength { + scriptLengthOfScriptPubKey := len(coinbaseData.ScriptPublicKey.Script) + if uint64(scriptLengthOfScriptPubKey) > c.coinbasePayloadScriptPublicKeyMaxLength { return nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+ "longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength) } - payload := make([]byte, uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength+len(coinbaseData.ExtraData)) + payload := make([]byte, uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptLengthOfScriptPubKey+len(coinbaseData.ExtraData)) byteOrder.PutUint64(payload[:uint64Len], blueScore) - if len(coinbaseData.ScriptPublicKey) > math.MaxUint8 { + if len(coinbaseData.ScriptPublicKey.Script) > math.MaxUint8 { return nil, errors.Errorf("script public key is bigger than %d", math.MaxUint8) } - payload[uint64Len] = uint8(len(coinbaseData.ScriptPublicKey)) - copy(payload[uint64Len+lengthOfscriptPubKeyLength:], coinbaseData.ScriptPublicKey) - copy(payload[uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength:], coinbaseData.ExtraData) + + payload[uint64Len] = uint8(coinbaseData.ScriptPublicKey.Version) + payload[uint64Len+lengthOfVersionScriptPubKey] = uint8(len(coinbaseData.ScriptPublicKey.Script)) + copy(payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength:], coinbaseData.ScriptPublicKey.Script) + copy(payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptLengthOfScriptPubKey:], coinbaseData.ExtraData) return payload, nil } @@ -37,27 +41,28 @@ func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseDat func (c *coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData, err error) { - minLength := uint64Len + lengthOfscriptPubKeyLength + minLength := uint64Len + lengthOfVersionScriptPubKey + lengthOfscriptPubKeyLength if len(coinbaseTx.Payload) < minLength { return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase payload is less than the minimum length of %d", minLength) } blueScore = byteOrder.Uint64(coinbaseTx.Payload[:uint64Len]) - scriptPubKeyLength := coinbaseTx.Payload[uint64Len] + scriptPubKeyVersion := uint16(coinbaseTx.Payload[uint64Len]) + scriptPubKeyScriptLength := coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey] - if uint64(scriptPubKeyLength) > c.coinbasePayloadScriptPublicKeyMaxLength { + if uint64(scriptPubKeyScriptLength) > c.coinbasePayloadScriptPublicKeyMaxLength { return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+ "longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength) } - if len(coinbaseTx.Payload) < minLength+int(scriptPubKeyLength) { + if len(coinbaseTx.Payload) < minLength+int(scriptPubKeyScriptLength) { return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, - "coinbase payload doesn't have enough bytes to contain a script public key of %d bytes", scriptPubKeyLength) + "coinbase payload doesn't have enough bytes to contain a script public key of %d bytes", scriptPubKeyScriptLength) } - + scriptPubKeyScript := coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength : uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptPubKeyScriptLength] return blueScore, &externalapi.DomainCoinbaseData{ - ScriptPublicKey: coinbaseTx.Payload[uint64Len+lengthOfscriptPubKeyLength : uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength], - ExtraData: coinbaseTx.Payload[uint64Len+lengthOfscriptPubKeyLength+scriptPubKeyLength:], + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: scriptPubKeyScript, Version: scriptPubKeyVersion}, + ExtraData: coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptPubKeyScriptLength:], }, nil } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 02d749075..119b931bf 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -234,7 +234,7 @@ func TestTransactionAcceptance(t *testing.T) { t.Fatalf("Error creating redBlock: %+v", err) } - blueScriptPublicKey := []byte{1} + blueScriptPublicKey := &externalapi.ScriptPublicKey{Script: []byte{1}, Version: 0} blueHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, &externalapi.DomainCoinbaseData{ ScriptPublicKey: blueScriptPublicKey, ExtraData: nil, @@ -250,7 +250,7 @@ func TestTransactionAcceptance(t *testing.T) { t.Fatalf("Error creating tip: %+v", err) } - finalTipSelectedParentScriptPublicKey := []byte{3} + finalTipSelectedParentScriptPublicKey := &externalapi.ScriptPublicKey{Script: []byte{3}, Version: 0} finalTipSelectedParentHash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, &externalapi.DomainCoinbaseData{ ScriptPublicKey: finalTipSelectedParentScriptPublicKey, @@ -355,7 +355,7 @@ func TestTransactionAcceptance(t *testing.T) { // We expect the coinbase transaction to pay reward for the selected parent, the // blue block, and not for the red block. expectedCoinbase := &externalapi.DomainTransaction{ - Version: constants.TransactionVersion, + Version: constants.MaxTransactionVersion, Inputs: nil, Outputs: []*externalapi.DomainTransactionOutput{ { diff --git a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go index 874c44b17..56a95b2ca 100644 --- a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go +++ b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go @@ -26,7 +26,7 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) { t.Fatalf("Failed getting virtual block virtualRelations: %v", err) } - block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{}, nil) + block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{ScriptPublicKey: &externalapi.ScriptPublicKey{Script: nil, Version: 0}}, nil) if err != nil { t.Fatalf("Consensus failed building a block: %v", err) } @@ -78,7 +78,7 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) { // Clear all tips. var virtualSelectedParent *externalapi.DomainHash for { - block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{}, nil) + block, err := tc.BuildBlock(&externalapi.DomainCoinbaseData{ScriptPublicKey: &externalapi.ScriptPublicKey{Script: nil, Version: 0}, ExtraData: nil}, nil) if err != nil { t.Fatalf("Failed building a block: %v", err) } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 8dfad88e5..802757822 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -58,37 +58,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "H", "C", "D", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "H", "C", "D", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "C", "D", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "C", "D", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "C", "D", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"}, }, }, "kaspa-testnet": { @@ -130,37 +130,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "H", "D", "C", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "H", "D", "C", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "D", "C", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "D", "C", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "D", "C", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "D", "C", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "D", "C"}, }, }, "kaspa-devnet": { @@ -182,12 +182,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"C", "D"}, id: "E", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"C", "D"}, id: "F", - expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -202,37 +202,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "D", "H", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "H", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "H", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, }, }, "kaspa-simnet": { @@ -274,37 +274,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "C", "H", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "C", "H", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "C", "H", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "C", "H", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "C", "H", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, }, }, } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index f11de5c5e..eaa2c5104 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -111,7 +111,7 @@ func TestGHOSTDAG(t *testing.T) { blockID := StringToDomainHash(testBlockData.ID) dagTopology.parentsMap[*blockID] = StringToDomainHashSlice(testBlockData.Parents) blockHeadersStore.dagMap[*blockID] = blockheader.NewImmutableBlockHeader( - constants.BlockVersion, + constants.MaxBlockVersion, StringToDomainHashSlice(testBlockData.Parents), nil, nil, diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index 16c83ace2..3b3f10808 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -33,8 +33,8 @@ func TestPruning(t *testing.T) { }, "dag-for-test-pruning.json": { "kaspa-mainnet": "503", - "kaspa-simnet": "502", - "kaspa-devnet": "503", + "kaspa-simnet": "503", + "kaspa-devnet": "502", "kaspa-testnet": "503", }, } diff --git a/domain/consensus/processes/transactionvalidator/mass.go b/domain/consensus/processes/transactionvalidator/mass.go index e18454ea3..041537bf8 100644 --- a/domain/consensus/processes/transactionvalidator/mass.go +++ b/domain/consensus/processes/transactionvalidator/mass.go @@ -13,7 +13,8 @@ func (v *transactionValidator) transactionMassStandalonePart(tx *externalapi.Dom totalScriptPubKeySize := uint64(0) for _, output := range tx.Outputs { - totalScriptPubKeySize += uint64(len(output.ScriptPublicKey)) + totalScriptPubKeySize += 2 //output.ScriptPublicKey.Version (uint16) + totalScriptPubKeySize += uint64(len(output.ScriptPublicKey.Script)) } return size*v.massPerTxByte + totalScriptPubKeySize*v.massPerScriptPubKeyByte diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go index 9d0ecb65e..ccfffdda9 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation.go @@ -50,6 +50,11 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do if err != nil { return err } + + if tx.Version > constants.MaxTransactionVersion { + return errors.Wrapf(ruleerrors.ErrTransactionVersionIsUnknown, "validation failed: unknown transaction version. ") + } + return nil } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go index 54cafe183..f0fcb2afb 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -150,14 +150,14 @@ func createTxForTest(numInputs uint32, numOutputs uint32, outputValue uint64, su for i := uint32(0); i < numOutputs; i++ { txOuts = append(txOuts, &externalapi.DomainTransactionOutput{ - ScriptPublicKey: []byte{}, + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: []byte{}, Version: 0}, Value: outputValue, }) } if subnetworkData != nil { - return transactionhelper.NewSubnetworkTransaction(constants.TransactionVersion, txIns, txOuts, &subnetworkData.subnetworkID, subnetworkData.gas, subnetworkData.payload) + return transactionhelper.NewSubnetworkTransaction(constants.MaxTransactionVersion, txIns, txOuts, &subnetworkData.subnetworkID, subnetworkData.gas, subnetworkData.payload) } - return transactionhelper.NewNativeTransaction(constants.TransactionVersion, txIns, txOuts) + return transactionhelper.NewNativeTransaction(constants.MaxTransactionVersion, txIns, txOuts) } diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 8e8c50c8f..bdc88e58d 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -179,6 +179,12 @@ var ( ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint") ErrSuggestedPruningViolatesFinality = newRuleError("ErrSuggestedPruningViolatesFinality") + + //ErrBlockVersionIsUnknown indicates that the block version is unknown. + ErrBlockVersionIsUnknown = newRuleError("ErrBlockVersionIsUnknown") + + //ErrTransactionVersionIsUnknown indicates that the transaction version is unknown. + ErrTransactionVersionIsUnknown = newRuleError("ErrTransactionVersionIsUnknown") ) // RuleError identifies a rule violation. It is used to indicate that diff --git a/domain/consensus/ruleerrors/rule_error_test.go b/domain/consensus/ruleerrors/rule_error_test.go index ebeeb517b..717375f84 100644 --- a/domain/consensus/ruleerrors/rule_error_test.go +++ b/domain/consensus/ruleerrors/rule_error_test.go @@ -47,7 +47,7 @@ func TestNewErrMissingTxOut(t *testing.T) { func TestNewErrInvalidTransactionsInNewBlock(t *testing.T) { outer := NewErrInvalidTransactionsInNewBlock([]InvalidTransaction{{&externalapi.DomainTransaction{Fee: 1337}, ErrNoTxInputs}}) //TODO: Implement Stringer for `DomainTransaction` - expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(3e93deca99d6f1b285bff219220a1e56447bdbf99dfa2ab5b794df883036a54e: ErrNoTxInputs)]" + expectedOuterErr := "ErrInvalidTransactionsInNewBlock: [(bbf6e84f5a6333948063aa45ea02ff5bb0355e11e41becf20245791f61179db1: ErrNoTxInputs)]" inner := &ErrInvalidTransactionsInNewBlock{} if !errors.As(outer, inner) { t.Fatal("TestNewErrInvalidTransactionsInNewBlock: Outer should contain ErrInvalidTransactionsInNewBlock in it") diff --git a/domain/consensus/utils/blockheader/blockheader.go b/domain/consensus/utils/blockheader/blockheader.go index 0ad3776c5..dd0f10beb 100644 --- a/domain/consensus/utils/blockheader/blockheader.go +++ b/domain/consensus/utils/blockheader/blockheader.go @@ -3,7 +3,7 @@ package blockheader import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type blockHeader struct { - version int32 + version uint16 parentHashes []*externalapi.DomainHash hashMerkleRoot *externalapi.DomainHash acceptedIDMerkleRoot *externalapi.DomainHash @@ -25,7 +25,7 @@ func (bh *blockHeader) SetTimeInMilliseconds(timeInMilliseconds int64) { bh.timeInMilliseconds = timeInMilliseconds } -func (bh *blockHeader) Version() int32 { +func (bh *blockHeader) Version() uint16 { return bh.version } @@ -124,7 +124,7 @@ func (bh *blockHeader) ToMutable() externalapi.MutableBlockHeader { // NewImmutableBlockHeader returns a new immutable header func NewImmutableBlockHeader( - version int32, + version uint16, parentHashes []*externalapi.DomainHash, hashMerkleRoot *externalapi.DomainHash, acceptedIDMerkleRoot *externalapi.DomainHash, diff --git a/domain/consensus/utils/consensushashing/transaction.go b/domain/consensus/utils/consensushashing/transaction.go index a0c74660b..492943890 100644 --- a/domain/consensus/utils/consensushashing/transaction.go +++ b/domain/consensus/utils/consensushashing/transaction.go @@ -93,7 +93,7 @@ func TransactionID(tx *externalapi.DomainTransaction) *externalapi.DomainTransac } func serializeTransaction(w io.Writer, tx *externalapi.DomainTransaction, encodingFlags txEncoding) error { - err := binaryserializer.PutUint32(w, uint32(tx.Version)) + err := binaryserializer.PutUint16(w, tx.Version) if err != nil { return err } @@ -204,6 +204,9 @@ func writeTxOut(w io.Writer, to *externalapi.DomainTransactionOutput) error { if err != nil { return err } - - return writeVarBytes(w, to.ScriptPublicKey) + err = binaryserializer.PutUint16(w, to.ScriptPublicKey.Version) + if err != nil { + return err + } + return writeVarBytes(w, to.ScriptPublicKey.Script) } diff --git a/domain/consensus/utils/constants/constants.go b/domain/consensus/utils/constants/constants.go index 09e432baa..5312477ac 100644 --- a/domain/consensus/utils/constants/constants.go +++ b/domain/consensus/utils/constants/constants.go @@ -3,12 +3,15 @@ package constants import "math" const ( - // BlockVersion represents the current version of blocks mined and the maximum block version + // MaxBlockVersion represents the current version of blocks mined and the maximum block version // this node is able to validate - BlockVersion = 1 + MaxBlockVersion uint16 = 0 - // TransactionVersion is the current latest supported transaction version. - TransactionVersion = 1 + // MaxTransactionVersion is the current latest supported transaction version. + MaxTransactionVersion uint16 = 0 + + // MaxScriptPublicKeyVersion is the current latest supported public key script version. + MaxScriptPublicKeyVersion uint16 = 0 // SompiPerKaspa is the number of sompi in one kaspa (1 KAS). SompiPerKaspa = 100_000_000 diff --git a/domain/consensus/utils/estimatedsize/transaction_estimated_size.go b/domain/consensus/utils/estimatedsize/transaction_estimated_size.go index 8ebf8b695..55d8c4320 100644 --- a/domain/consensus/utils/estimatedsize/transaction_estimated_size.go +++ b/domain/consensus/utils/estimatedsize/transaction_estimated_size.go @@ -14,7 +14,7 @@ func TransactionEstimatedSerializedSize(tx *externalapi.DomainTransaction) uint6 return 0 } size := uint64(0) - + size += 2 // Txn Version size += 8 // number of inputs (uint64) for _, input := range tx.Inputs { size += transactionInputEstimatedSerializedSize(input) @@ -58,7 +58,8 @@ func outpointEstimatedSerializedSize() uint64 { func TransactionOutputEstimatedSerializedSize(output *externalapi.DomainTransactionOutput) uint64 { size := uint64(0) size += 8 // value (uint64) + size += 2 //output.ScriptPublicKey.Version (uint 16) size += 8 // length of script public key (uint64) - size += uint64(len(output.ScriptPublicKey)) + size += uint64(len(output.ScriptPublicKey.Script)) return size } diff --git a/domain/consensus/utils/serialization/common.go b/domain/consensus/utils/serialization/common.go index 9228ef9c0..91038a0f2 100644 --- a/domain/consensus/utils/serialization/common.go +++ b/domain/consensus/utils/serialization/common.go @@ -18,6 +18,12 @@ func WriteElement(w io.Writer, element interface{}) error { // Attempt to write the element based on the concrete type via fast // type assertions first. switch e := element.(type) { + case uint16: + err := binaryserializer.PutUint16(w, e) + if err != nil { + return err + } + return nil case int32: err := binaryserializer.PutUint32(w, uint32(e)) if err != nil { diff --git a/domain/consensus/utils/testutils/create_transaction.go b/domain/consensus/utils/testutils/create_transaction.go index 57d585de9..c747d20fc 100644 --- a/domain/consensus/utils/testutils/create_transaction.go +++ b/domain/consensus/utils/testutils/create_transaction.go @@ -30,7 +30,7 @@ func CreateTransaction(txToSpend *externalapi.DomainTransaction) (*externalapi.D Value: txToSpend.Outputs[0].Value - 1, } return &externalapi.DomainTransaction{ - Version: constants.TransactionVersion, + Version: constants.MaxTransactionVersion, Inputs: []*externalapi.DomainTransactionInput{input}, Outputs: []*externalapi.DomainTransactionOutput{output}, Payload: []byte{}, diff --git a/domain/consensus/utils/testutils/op_true_script.go b/domain/consensus/utils/testutils/op_true_script.go index fb111dc1d..68be93cfb 100644 --- a/domain/consensus/utils/testutils/op_true_script.go +++ b/domain/consensus/utils/testutils/op_true_script.go @@ -1,18 +1,21 @@ package testutils import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/pkg/errors" ) // OpTrueScript returns a P2SH script paying to an anyone-can-spend address, // The second return value is a redeemScript to be used with txscript.PayToScriptHashSignatureScript -func OpTrueScript() (scriptPublicKey, redeemScript []byte) { +func OpTrueScript() (*externalapi.ScriptPublicKey, []byte) { var err error - redeemScript = []byte{txscript.OpTrue} - scriptPublicKey, err = txscript.PayToScriptHashScript(redeemScript) + redeemScript := []byte{txscript.OpTrue} + scriptPublicKeyScript, err := txscript.PayToScriptHashScript(redeemScript) if err != nil { panic(errors.Wrapf(err, "Couldn't parse opTrueScript. This should never happen")) } + scriptPublicKey := &externalapi.ScriptPublicKey{Script: scriptPublicKeyScript, Version: constants.MaxScriptPublicKeyVersion} return scriptPublicKey, redeemScript } diff --git a/domain/consensus/utils/transactionhelper/new.go b/domain/consensus/utils/transactionhelper/new.go index b796baf27..629aa86b8 100644 --- a/domain/consensus/utils/transactionhelper/new.go +++ b/domain/consensus/utils/transactionhelper/new.go @@ -7,7 +7,7 @@ import ( ) // NewSubnetworkTransaction returns a new trsnactions in the specified subnetwork with specified gas and payload -func NewSubnetworkTransaction(version int32, inputs []*externalapi.DomainTransactionInput, +func NewSubnetworkTransaction(version uint16, inputs []*externalapi.DomainTransactionInput, outputs []*externalapi.DomainTransactionOutput, subnetworkID *externalapi.DomainSubnetworkID, gas uint64, payload []byte) *externalapi.DomainTransaction { @@ -27,7 +27,7 @@ func NewSubnetworkTransaction(version int32, inputs []*externalapi.DomainTransac } // NewNativeTransaction returns a new native transaction -func NewNativeTransaction(version int32, inputs []*externalapi.DomainTransactionInput, +func NewNativeTransaction(version uint16, inputs []*externalapi.DomainTransactionInput, outputs []*externalapi.DomainTransactionOutput) *externalapi.DomainTransaction { return &externalapi.DomainTransaction{ Version: version, diff --git a/domain/consensus/utils/txscript/engine.go b/domain/consensus/utils/txscript/engine.go index fde7653e8..a9d827f89 100644 --- a/domain/consensus/utils/txscript/engine.go +++ b/domain/consensus/utils/txscript/engine.go @@ -7,6 +7,7 @@ package txscript import ( "fmt" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/infrastructure/logger" ) @@ -38,6 +39,7 @@ const ( // Engine is the virtual machine that executes scripts. type Engine struct { + isKnownVersion bool scripts [][]parsedOpcode scriptIdx int scriptOff int @@ -313,6 +315,10 @@ func (vm *Engine) Step() (done bool, err error) { // Execute will execute all scripts in the script engine and return either nil // for successful validation or an error if one occurred. func (vm *Engine) Execute() (err error) { + if !vm.isKnownVersion { + log.Tracef("The version of the scriptPublicKey is higher than the known version - the Execute function returns true.") + return nil + } done := false for !done { log.Tracef("%s", logger.NewLogClosure(func() string { @@ -429,7 +435,7 @@ func (vm *Engine) SetAltStack(data [][]byte) { // NewEngine returns a new script engine for the provided public key script, // transaction, and input index. The flags modify the behavior of the script // engine according to the description provided by each flag. -func NewEngine(scriptPubKey []byte, tx *externalapi.DomainTransaction, txIdx int, flags ScriptFlags, +func NewEngine(scriptPubKey *externalapi.ScriptPublicKey, tx *externalapi.DomainTransaction, txIdx int, flags ScriptFlags, sigCache *SigCache) (*Engine, error) { // The provided transaction input index must refer to a valid input. @@ -444,13 +450,17 @@ func NewEngine(scriptPubKey []byte, tx *externalapi.DomainTransaction, txIdx int // result is necessarily an error since the stack would end up being // empty which is equivalent to a false top element. Thus, just return // the relevant error now as an optimization. - if len(scriptSig) == 0 && len(scriptPubKey) == 0 { + if len(scriptSig) == 0 && len(scriptPubKey.Script) == 0 { return nil, scriptError(ErrEvalFalse, "false stack entry at end of script execution") } - vm := Engine{flags: flags, sigCache: sigCache} + if scriptPubKey.Version > constants.MaxScriptPublicKeyVersion { + vm.isKnownVersion = false + return &vm, nil + } + vm.isKnownVersion = true parsedScriptSig, err := parseScriptAndVerifySize(scriptSig) if err != nil { return nil, err @@ -461,7 +471,7 @@ func NewEngine(scriptPubKey []byte, tx *externalapi.DomainTransaction, txIdx int "signature script is not push only") } - parsedScriptPubKey, err := parseScriptAndVerifySize(scriptPubKey) + parsedScriptPubKey, err := parseScriptAndVerifySize(scriptPubKey.Script) if err != nil { return nil, err } diff --git a/domain/consensus/utils/txscript/engine_test.go b/domain/consensus/utils/txscript/engine_test.go index d79f855d4..6a8380ed9 100644 --- a/domain/consensus/utils/txscript/engine_test.go +++ b/domain/consensus/utils/txscript/engine_test.go @@ -38,7 +38,7 @@ func TestBadPC(t *testing.T) { }), Index: 0, }, - SignatureScript: mustParseShortForm(""), + SignatureScript: mustParseShortForm("", 0), Sequence: 4294967295, }, } @@ -51,7 +51,7 @@ func TestBadPC(t *testing.T) { Inputs: inputs, Outputs: outputs, } - scriptPubKey := mustParseShortForm("NOP") + scriptPubKey := &externalapi.ScriptPublicKey{Script: mustParseShortForm("NOP", 0), Version: 0} for _, test := range tests { vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) @@ -120,7 +120,7 @@ func TestCheckErrorCondition(t *testing.T) { Outputs: outputs, } - scriptPubKey := mustParseShortForm(test.script) + scriptPubKey := &externalapi.ScriptPublicKey{Script: mustParseShortForm(test.script, 0), Version: 0} vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) if err != nil { @@ -235,7 +235,7 @@ func TestDisasmPC(t *testing.T) { }), Index: 0, }, - SignatureScript: mustParseShortForm("OP_2"), + SignatureScript: mustParseShortForm("OP_2", 0), Sequence: 4294967295, }} outputs := []*externalapi.DomainTransactionOutput{{ @@ -248,7 +248,7 @@ func TestDisasmPC(t *testing.T) { Outputs: outputs, } - scriptPubKey := mustParseShortForm("OP_DROP NOP TRUE") + scriptPubKey := &externalapi.ScriptPublicKey{Script: mustParseShortForm("OP_DROP NOP TRUE", 0), Version: 0} vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) if err != nil { @@ -299,7 +299,7 @@ func TestDisasmScript(t *testing.T) { }), Index: 0, }, - SignatureScript: mustParseShortForm("OP_2"), + SignatureScript: mustParseShortForm("OP_2", 0), Sequence: 4294967295, }} outputs := []*externalapi.DomainTransactionOutput{{ @@ -312,8 +312,7 @@ func TestDisasmScript(t *testing.T) { Outputs: outputs, } - scriptPubKey := mustParseShortForm("OP_DROP NOP TRUE") - + scriptPubKey := &externalapi.ScriptPublicKey{Script: mustParseShortForm("OP_DROP NOP TRUE", 0), Version: 0} vm, err := NewEngine(scriptPubKey, tx, 0, 0, nil) if err != nil { t.Fatalf("failed to create script: %v", err) diff --git a/domain/consensus/utils/txscript/example_test.go b/domain/consensus/utils/txscript/example_test.go index 2bcfbd44c..b6f00d212 100644 --- a/domain/consensus/utils/txscript/example_test.go +++ b/domain/consensus/utils/txscript/example_test.go @@ -7,6 +7,7 @@ package txscript_test import ( "encoding/hex" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/domain/dagconfig" @@ -34,9 +35,9 @@ func ExamplePayToAddrScript() { fmt.Println(err) return } - fmt.Printf("Script Hex: %x\n", script) + fmt.Printf("Script Hex: %x\n", script.Script) - disasm, err := txscript.DisasmString(script) + disasm, err := txscript.DisasmString(script.Version, script.Script) if err != nil { fmt.Println(err) return @@ -61,7 +62,10 @@ func ExampleExtractScriptPubKeyAddress() { // Extract and print details from the script. scriptClass, address, err := txscript.ExtractScriptPubKeyAddress( - script, &dagconfig.MainnetParams) + &externalapi.ScriptPublicKey{ + Script: script, + Version: 0, + }, &dagconfig.MainnetParams) if err != nil { fmt.Println(err) return diff --git a/domain/consensus/utils/txscript/reference_test.go b/domain/consensus/utils/txscript/reference_test.go index 188535e41..a6e674f2a 100644 --- a/domain/consensus/utils/txscript/reference_test.go +++ b/domain/consensus/utils/txscript/reference_test.go @@ -64,7 +64,12 @@ var shortFormOps map[string]byte // 0x14 is OP_DATA_20) // - Single quoted strings are pushed as data // - Anything else is an error -func parseShortForm(script string) ([]byte, error) { +func parseShortForm(script string, version uint16) ([]byte, error) { + if version > constants.MaxScriptPublicKeyVersion { + return nil, errors.Errorf("unknown version %d (max: %d)", + version, constants.MaxScriptPublicKeyVersion) + } + // Only create the short form opcode map once. if shortFormOps == nil { ops := make(map[string]byte) @@ -213,7 +218,7 @@ func parseExpectedResult(expected string) ([]ErrorCode, error) { // createSpendTx generates a basic spending transaction given the passed // signature and public key scripts. -func createSpendingTx(sigScript, scriptPubKey []byte) *externalapi.DomainTransaction { +func createSpendingTx(sigScript []byte, scriptPubKey *externalapi.ScriptPublicKey) *externalapi.DomainTransaction { outpoint := externalapi.DomainOutpoint{ TransactionID: externalapi.DomainTransactionID{}, Index: ^uint32(0), @@ -282,7 +287,7 @@ func testScripts(t *testing.T, tests [][]interface{}, useSigCache bool) { t.Errorf("%s: signature script is not a string", name) continue } - scriptSig, err := parseShortForm(scriptSigStr) + scriptSig, err := parseShortForm(scriptSigStr, 0) if err != nil { t.Errorf("%s: can't parse signature script: %v", name, err) @@ -295,12 +300,13 @@ func testScripts(t *testing.T, tests [][]interface{}, useSigCache bool) { t.Errorf("%s: public key script is not a string", name) continue } - scriptPubKey, err := parseShortForm(scriptPubKeyStr) + script, err := parseShortForm(scriptPubKeyStr, 0) if err != nil { t.Errorf("%s: can't parse public key script: %v", name, err) continue } + scriptPubKey := &externalapi.ScriptPublicKey{Script: script, Version: 0} // Extract and parse the script flags from the test fields. flagsStr, ok := test[2].(string) diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index b287ff257..683b182b3 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -7,6 +7,7 @@ package txscript import ( "bytes" "fmt" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" @@ -56,8 +57,8 @@ func isScriptHash(pops []parsedOpcode) bool { // IsPayToScriptHash returns true if the script is in the standard // pay-to-script-hash (P2SH) format, false otherwise. -func IsPayToScriptHash(script []byte) bool { - pops, err := parseScript(script) +func IsPayToScriptHash(script *externalapi.ScriptPublicKey) bool { + pops, err := parseScript(script.Script) if err != nil { return false } @@ -205,20 +206,24 @@ func unparseScript(pops []parsedOpcode) ([]byte, error) { // script up to the point the failure occurred along with the string '[error]' // appended. In addition, the reason the script failed to parse is returned // if the caller wants more information about the failure. -func DisasmString(buf []byte) (string, error) { - var disbuf bytes.Buffer - opcodes, err := parseScript(buf) - for _, pop := range opcodes { - disbuf.WriteString(pop.print(true)) - disbuf.WriteByte(' ') +func DisasmString(version uint16, buf []byte) (string, error) { + // currently, there is only one version exists so it equals to the max version. + if version == constants.MaxScriptPublicKeyVersion { + var disbuf bytes.Buffer + opcodes, err := parseScript(buf) + for _, pop := range opcodes { + disbuf.WriteString(pop.print(true)) + disbuf.WriteByte(' ') + } + if disbuf.Len() > 0 { + disbuf.Truncate(disbuf.Len() - 1) + } + if err != nil { + disbuf.WriteString("[error]") + } + return disbuf.String(), err } - if disbuf.Len() > 0 { - disbuf.Truncate(disbuf.Len() - 1) - } - if err != nil { - disbuf.WriteString("[error]") - } - return disbuf.String(), err + return "", scriptError(ErrPubKeyFormat, "the version of the scriptPublicHash is higher then the known version") } // canonicalPush returns true if the object is either not a push instruction @@ -282,8 +287,11 @@ func shallowCopyTx(tx *externalapi.DomainTransaction) externalapi.DomainTransact // CalcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. -func CalcSignatureHash(script []byte, hashType SigHashType, tx *externalapi.DomainTransaction, idx int) (*externalapi.DomainHash, error) { - parsedScript, err := parseScript(script) +func CalcSignatureHash(script *externalapi.ScriptPublicKey, hashType SigHashType, tx *externalapi.DomainTransaction, idx int) (*externalapi.DomainHash, error) { + if script.Version > constants.MaxScriptPublicKeyVersion { + return nil, errors.Errorf("Script version is unkown.") + } + parsedScript, err := parseScript(script.Script) if err != nil { return nil, errors.Errorf("cannot parse output script: %s", err) } @@ -335,7 +343,8 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *external // All but current output get zeroed out. for i := 0; i < idx; i++ { txCopy.Outputs[i].Value = 0 - txCopy.Outputs[i].ScriptPublicKey = nil + txCopy.Outputs[i].ScriptPublicKey.Script = nil + txCopy.Outputs[i].ScriptPublicKey.Version = 0 } // Sequence on all other inputs is 0, too. @@ -424,10 +433,10 @@ func GetSigOpCount(script []byte) int { // Pay-To-Script-Hash script in order to find the precise number of signature // operations in the transaction. If the script fails to parse, then the count // up to the point of failure is returned. -func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, isP2SH bool) int { +func GetPreciseSigOpCount(scriptSig []byte, scriptPubKey *externalapi.ScriptPublicKey, isP2SH bool) int { // Don't check error since parseScript returns the parsed-up-to-error // list of pops. - pops, _ := parseScript(scriptPubKey) + pops, _ := parseScript(scriptPubKey.Script) // Treat non P2SH transactions as normal. if !(isP2SH && isScriptHash(pops)) { diff --git a/domain/consensus/utils/txscript/script_test.go b/domain/consensus/utils/txscript/script_test.go index d5052e20c..16e2a708f 100644 --- a/domain/consensus/utils/txscript/script_test.go +++ b/domain/consensus/utils/txscript/script_test.go @@ -6,6 +6,7 @@ package txscript import ( "bytes" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "reflect" "testing" ) @@ -3705,7 +3706,7 @@ func TestPushedData(t *testing.T) { } for i, test := range tests { - script := mustParseShortForm(test.script) + script := mustParseShortForm(test.script, 0) data, err := PushedData(script) if test.valid && err != nil { t.Errorf("TestPushedData failed test #%d: %v\n", i, err) @@ -3789,11 +3790,11 @@ func TestGetPreciseSigOps(t *testing.T) { }{ { name: "scriptSig doesn't parse", - scriptSig: mustParseShortForm("PUSHDATA1 0x02"), + scriptSig: mustParseShortForm("PUSHDATA1 0x02", 0), }, { name: "scriptSig isn't push only", - scriptSig: mustParseShortForm("1 DUP"), + scriptSig: mustParseShortForm("1 DUP", 0), nSigOps: 0, }, { @@ -3804,20 +3805,21 @@ func TestGetPreciseSigOps(t *testing.T) { { name: "No script at the end", // No script at end but still push only. - scriptSig: mustParseShortForm("1 1"), + scriptSig: mustParseShortForm("1 1", 0), nSigOps: 0, }, { name: "pushed script doesn't parse", - scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02"), + scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02", 0), }, } // The signature in the p2sh script is nonsensical for the tests since // this script will never be executed. What matters is that it matches // the right pattern. - scriptPubKey := mustParseShortForm("HASH160 DATA_20 0x433ec2ac1ffa1b7b7d0" + - "27f564529c57197f9ae88 EQUAL") + scriptOnly := mustParseShortForm("HASH160 DATA_20 0x433ec2ac1ffa1b7b7d0"+ + "27f564529c57197f9ae88 EQUAL", 0) + scriptPubKey := &externalapi.ScriptPublicKey{scriptOnly, 0} for _, test := range tests { count := GetPreciseSigOpCount(test.scriptSig, scriptPubKey, true) if count != test.nSigOps { @@ -3834,7 +3836,7 @@ func TestIsPayToScriptHash(t *testing.T) { t.Parallel() for _, test := range scriptClassTests { - script := mustParseShortForm(test.script) + script := &externalapi.ScriptPublicKey{mustParseShortForm(test.script, 0), 0} shouldBe := (test.class == ScriptHashTy) p2sh := IsPayToScriptHash(script) if p2sh != shouldBe { @@ -3868,7 +3870,7 @@ func TestHasCanonicalPushes(t *testing.T) { } for i, test := range tests { - script := mustParseShortForm(test.script) + script := mustParseShortForm(test.script, 0) pops, err := parseScript(script) if err != nil { if test.expected { @@ -3900,20 +3902,20 @@ func TestIsPushOnlyScript(t *testing.T) { }{ { name: "does not parse", - script: mustParseShortForm("0x046708afdb0fe5548271967f1a67130" + - "b7105cd6a828e03909a67962e0ea1f61d"), + script: mustParseShortForm("0x046708afdb0fe5548271967f1a67130"+ + "b7105cd6a828e03909a67962e0ea1f61d", 0), expectedResult: false, shouldFail: true, }, { name: "non push only script", - script: mustParseShortForm("0x515293"), //OP_1 OP_2 OP_ADD + script: mustParseShortForm("0x515293", 0), //OP_1 OP_2 OP_ADD expectedResult: false, shouldFail: false, }, { name: "push only script", - script: mustParseShortForm("0x5152"), //OP_1 OP_2 + script: mustParseShortForm("0x5152", 0), //OP_1 OP_2 expectedResult: true, shouldFail: false, }, diff --git a/domain/consensus/utils/txscript/sign.go b/domain/consensus/utils/txscript/sign.go index 5b8507559..b4872d1cf 100644 --- a/domain/consensus/utils/txscript/sign.go +++ b/domain/consensus/utils/txscript/sign.go @@ -15,7 +15,7 @@ import ( // RawTxInSignature returns the serialized Schnorr signature for the input idx of // the given transaction, with hashType appended to it. -func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, script []byte, +func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, script *externalapi.ScriptPublicKey, hashType SigHashType, key *secp256k1.SchnorrKeyPair) ([]byte, error) { hash, err := CalcSignatureHash(script, hashType, tx, idx) @@ -35,11 +35,11 @@ func RawTxInSignature(tx *externalapi.DomainTransaction, idx int, script []byte, // from a previous output to the owner of privKey. tx must include all // transaction inputs and outputs, however txin scripts are allowed to be filled // or empty. The returned script is calculated to be used as the idx'th txin -// sigscript for tx. script is the ScriptPubKey of the previous output being used +// sigscript for tx. script is the ScriptPublicKey of the previous output being used // as the idx'th input. privKey is serialized in either a compressed or // uncompressed format based on compress. This format must match the same format // used to generate the payment address, or the script validation will fail. -func SignatureScript(tx *externalapi.DomainTransaction, idx int, script []byte, hashType SigHashType, privKey *secp256k1.SchnorrKeyPair) ([]byte, error) { +func SignatureScript(tx *externalapi.DomainTransaction, idx int, script *externalapi.ScriptPublicKey, hashType SigHashType, privKey *secp256k1.SchnorrKeyPair) ([]byte, error) { sig, err := RawTxInSignature(tx, idx, script, hashType, privKey) if err != nil { return nil, err @@ -58,7 +58,7 @@ func SignatureScript(tx *externalapi.DomainTransaction, idx int, script []byte, } func sign(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx int, - script []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB) ([]byte, + script *externalapi.ScriptPublicKey, hashType SigHashType, kdb KeyDB, sdb ScriptDB) ([]byte, ScriptClass, util.Address, error) { class, address, err := ExtractScriptPubKeyAddress(script, @@ -100,7 +100,7 @@ func sign(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx in // function with addresses, class and nrequired that do not match scriptPubKey is // an error and results in undefined behaviour. func mergeScripts(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx int, - class ScriptClass, sigScript, prevScript []byte) ([]byte, error) { + class ScriptClass, sigScript []byte, prevScript *externalapi.ScriptPublicKey) ([]byte, error) { switch class { case ScriptHashTy: @@ -108,9 +108,9 @@ func mergeScripts(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction // this could be a lot less inefficient. sigPops, err := parseScript(sigScript) if err != nil || len(sigPops) == 0 { - return prevScript, nil + return prevScript.Script, nil } - prevPops, err := parseScript(prevScript) + prevPops, err := parseScript(prevScript.Script) if err != nil || len(prevPops) == 0 { return sigScript, nil } @@ -118,15 +118,21 @@ func mergeScripts(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction // assume that script in sigPops is the correct one, we just // made it. script := sigPops[len(sigPops)-1].data - + scriptPubKey := &externalapi.ScriptPublicKey{ + Script: script, + Version: prevScript.Version, + } // We already know this information somewhere up the stack. class, _, _ := - ExtractScriptPubKeyAddress(script, dagParams) + ExtractScriptPubKeyAddress(scriptPubKey, dagParams) // regenerate scripts. sigScript, _ := unparseScript(sigPops) - prevScript, _ := unparseScript(prevPops) - + prevScriptByte, _ := unparseScript(prevPops) + prevScript = &externalapi.ScriptPublicKey{ + Script: prevScriptByte, + Version: prevScript.Version, + } // Merge mergedScript, err := mergeScripts(dagParams, tx, idx, class, sigScript, prevScript) if err != nil { @@ -146,10 +152,10 @@ func mergeScripts(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction // above. In the conflict case here we just assume the longest is // correct (this matches behaviour of the reference implementation). default: - if len(sigScript) > len(prevScript) { + if len(sigScript) > len(prevScript.Script) { return sigScript, nil } - return prevScript, nil + return prevScript.Script, nil } } @@ -182,25 +188,30 @@ func (sc ScriptClosure) GetScript(address util.Address) ([]byte, error) { } // SignTxOutput signs output idx of the given tx to resolve the script given in -// scriptPubKey with a signature type of hashType. Any keys required will be +// scriptPublicKey with a signature type of hashType. Any keys required will be // looked up by calling getKey() with the string of the given address. // Any pay-to-script-hash signatures will be similarly looked up by calling // getScript. If previousScript is provided then the results in previousScript // will be merged in a type-dependent manner with the newly generated. // signature script. func SignTxOutput(dagParams *dagconfig.Params, tx *externalapi.DomainTransaction, idx int, - scriptPubKey []byte, hashType SigHashType, kdb KeyDB, sdb ScriptDB, - previousScript []byte) ([]byte, error) { + scriptPublicKey *externalapi.ScriptPublicKey, hashType SigHashType, kdb KeyDB, sdb ScriptDB, + previousScript *externalapi.ScriptPublicKey) ([]byte, error) { sigScript, class, _, err := sign(dagParams, tx, - idx, scriptPubKey, hashType, kdb, sdb) + idx, scriptPublicKey, hashType, kdb, sdb) if err != nil { return nil, err } if class == ScriptHashTy { + scriptHashPreimageScriptPublicKey := &externalapi.ScriptPublicKey{ + Script: sigScript, + Version: scriptPublicKey.Version, + } + realSigScript, _, _, err := sign(dagParams, tx, idx, - sigScript, hashType, kdb, sdb) + scriptHashPreimageScriptPublicKey, hashType, kdb, sdb) if err != nil { return nil, err } diff --git a/domain/consensus/utils/txscript/sign_test.go b/domain/consensus/utils/txscript/sign_test.go index 7a36cab24..8026ba4e5 100644 --- a/domain/consensus/utils/txscript/sign_test.go +++ b/domain/consensus/utils/txscript/sign_test.go @@ -46,7 +46,7 @@ func mkGetScript(scripts map[string][]byte) ScriptDB { }) } -func checkScripts(msg string, tx *externalapi.DomainTransaction, idx int, sigScript, scriptPubKey []byte) error { +func checkScripts(msg string, tx *externalapi.DomainTransaction, idx int, sigScript []byte, scriptPubKey *externalapi.ScriptPublicKey) error { tx.Inputs[idx].SignatureScript = sigScript var flags ScriptFlags vm, err := NewEngine(scriptPubKey, tx, idx, @@ -65,12 +65,12 @@ func checkScripts(msg string, tx *externalapi.DomainTransaction, idx int, sigScr return nil } -func signAndCheck(msg string, tx *externalapi.DomainTransaction, idx int, scriptPubKey []byte, +func signAndCheck(msg string, tx *externalapi.DomainTransaction, idx int, scriptPubKey *externalapi.ScriptPublicKey, hashType SigHashType, kdb KeyDB, sdb ScriptDB, previousScript []byte) error { sigScript, err := SignTxOutput(&dagconfig.TestnetParams, tx, idx, - scriptPubKey, hashType, kdb, sdb, nil) + scriptPubKey, hashType, kdb, sdb, &externalapi.ScriptPublicKey{Script: nil, Version: 0}) if err != nil { return errors.Errorf("failed to sign output %s: %v", msg, err) } @@ -117,17 +117,20 @@ func TestSignTxOutput(t *testing.T) { } outputs := []*externalapi.DomainTransactionOutput{ { - Value: 1, + Value: 1, + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: nil, Version: 0}, }, { - Value: 2, + Value: 2, + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: nil, Version: 0}, }, { - Value: 3, + Value: 3, + ScriptPublicKey: &externalapi.ScriptPublicKey{Script: nil, Version: 0}, }, } tx := &externalapi.DomainTransaction{ - Version: 1, + Version: 0, Inputs: inputs, Outputs: outputs, } @@ -174,7 +177,7 @@ func TestSignTxOutput(t *testing.T) { tx, i, scriptPubKey, hashType, mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, - }), mkGetScript(nil), nil) + }), mkGetScript(nil), &externalapi.ScriptPublicKey{Script: nil, Version: 0}) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) @@ -187,7 +190,10 @@ func TestSignTxOutput(t *testing.T) { tx, i, scriptPubKey, hashType, mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, - }), mkGetScript(nil), sigScript) + }), mkGetScript(nil), &externalapi.ScriptPublicKey{ + Script: sigScript, + Version: scriptPubKey.Version, + }) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) @@ -242,7 +248,6 @@ func TestSignTxOutput(t *testing.T) { t.Errorf("failed to make scriptPubKey "+ "for %s: %v", msg, err) } - if err := signAndCheck(msg, tx, i, scriptPubKey, hashType, mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, @@ -297,7 +302,7 @@ func TestSignTxOutput(t *testing.T) { tx, i, scriptPubKey, hashType, mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, - }), mkGetScript(nil), nil) + }), mkGetScript(nil), &externalapi.ScriptPublicKey{Script: nil, Version: 0}) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) @@ -310,7 +315,10 @@ func TestSignTxOutput(t *testing.T) { tx, i, scriptPubKey, hashType, mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, - }), mkGetScript(nil), sigScript) + }), mkGetScript(nil), &externalapi.ScriptPublicKey{ + Script: sigScript, + Version: scriptPubKey.Version, + }) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) @@ -369,15 +377,14 @@ func TestSignTxOutput(t *testing.T) { } scriptAddr, err := util.NewAddressScriptHash( - scriptPubKey, util.Bech32PrefixKaspaTest) + scriptPubKey.Script, util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptScriptPubKey, err := PayToAddrScript( - scriptAddr) + scriptScriptPubKey, err := PayToAddrScript(scriptAddr) if err != nil { t.Errorf("failed to make script scriptPubKey for "+ "%s: %v", msg, err) @@ -388,7 +395,7 @@ func TestSignTxOutput(t *testing.T) { mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, }), mkGetScript(map[string][]byte{ - scriptAddr.EncodeAddress(): scriptPubKey, + scriptAddr.EncodeAddress(): scriptPubKey.Script, }), nil); err != nil { t.Error(err) break @@ -437,28 +444,26 @@ func TestSignTxOutput(t *testing.T) { } scriptAddr, err := util.NewAddressScriptHash( - scriptPubKey, util.Bech32PrefixKaspaTest) + scriptPubKey.Script, util.Bech32PrefixKaspaTest) if err != nil { t.Errorf("failed to make p2sh addr for %s: %v", msg, err) break } - scriptScriptPubKey, err := PayToAddrScript( - scriptAddr) + scriptScriptPubKey, err := PayToAddrScript(scriptAddr) if err != nil { t.Errorf("failed to make script scriptPubKey for "+ "%s: %v", msg, err) break } - _, err = SignTxOutput(&dagconfig.TestnetParams, tx, i, scriptScriptPubKey, hashType, mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, }), mkGetScript(map[string][]byte{ - scriptAddr.EncodeAddress(): scriptPubKey, - }), nil) + scriptAddr.EncodeAddress(): scriptPubKey.Script, + }), &externalapi.ScriptPublicKey{Script: nil, Version: 0}) if err != nil { t.Errorf("failed to sign output %s: %v", msg, err) @@ -472,8 +477,8 @@ func TestSignTxOutput(t *testing.T) { mkGetKey(map[string]*secp256k1.SchnorrKeyPair{ address.EncodeAddress(): key, }), mkGetScript(map[string][]byte{ - scriptAddr.EncodeAddress(): scriptPubKey, - }), nil) + scriptAddr.EncodeAddress(): scriptPubKey.Script, + }), &externalapi.ScriptPublicKey{Script: nil, Version: 0}) if err != nil { t.Errorf("failed to sign output %s a "+ "second time: %v", msg, err) @@ -515,18 +520,18 @@ var ( 0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65, 0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0, 0xd6, 0x0e, 0x06, 0x92} - oldUncompressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + oldUncompressedScriptPubKey = &externalapi.ScriptPublicKey{[]byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, - 0x53, 0x90, 0x0e, 0x0a, 0x86, 0xc9, 0xfa, 0x88, 0xac} - oldCompressedScriptPubKey = []byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, + 0x53, 0x90, 0x0e, 0x0a, 0x86, 0xc9, 0xfa, 0x88, 0xac}, 0} + oldCompressedScriptPubKey = &externalapi.ScriptPublicKey{[]byte{0x76, 0xa9, 0x14, 0x27, 0x4d, 0x9f, 0x7f, 0x61, 0x7e, 0x7c, 0x7a, 0x1c, 0x1f, 0xb2, 0x75, 0x79, 0x10, - 0x43, 0x65, 0x68, 0x27, 0x9d, 0x86, 0x88, 0xac} - p2pkhScriptPubKey = []byte{0x76, 0xa9, 0x14, 0x7e, 0x01, 0x76, 0xb6, + 0x43, 0x65, 0x68, 0x27, 0x9d, 0x86, 0x88, 0xac}, 0} + p2pkhScriptPubKey = &externalapi.ScriptPublicKey{[]byte{0x76, 0xa9, 0x14, 0x7e, 0x01, 0x76, 0xb6, 0x72, 0x08, 0xc0, 0x08, 0x98, 0x85, 0x97, 0x00, 0x4e, 0x1a, 0x8d, - 0x60, 0x89, 0xfe, 0x42, 0x6f, 0x88, 0xac} - shortScriptPubKey = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, + 0x60, 0x89, 0xfe, 0x42, 0x6f, 0x88, 0xac}, 0} + shortScriptPubKey = &externalapi.ScriptPublicKey{[]byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5, 0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32, - 0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac} + 0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac}, 0} ) // Pretend output amounts. @@ -738,7 +743,7 @@ var sigScriptTests = []tstSigScript{ scriptAtWrongIndex: false, }, { - name: "short ScriptPubKey", + name: "short ScriptPublicKey", inputs: []tstInput{ { txout: &externalapi.DomainTransactionOutput{ @@ -817,7 +822,7 @@ func TestSignatureScript(t *testing.T) { nexttest: for i := range sigScriptTests { outputs := []*externalapi.DomainTransactionOutput{ - {Value: 500, ScriptPublicKey: []byte{OpReturn}}, + {Value: 500, ScriptPublicKey: &externalapi.ScriptPublicKey{[]byte{OpReturn}, 0}}, } inputs := []*externalapi.DomainTransactionInput{} @@ -827,7 +832,7 @@ nexttest: }) } tx := &externalapi.DomainTransaction{ - Version: 1, + Version: 0, Inputs: inputs, Outputs: outputs, } diff --git a/domain/consensus/utils/txscript/standard.go b/domain/consensus/utils/txscript/standard.go index 12ad363b2..4afea2711 100644 --- a/domain/consensus/utils/txscript/standard.go +++ b/domain/consensus/utils/txscript/standard.go @@ -6,6 +6,8 @@ package txscript import ( "fmt" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/dagconfig" @@ -184,23 +186,30 @@ func payToScriptHashScript(scriptHash []byte) ([]byte, error) { // PayToAddrScript creates a new script to pay a transaction output to a the // specified address. -func PayToAddrScript(addr util.Address) ([]byte, error) { +func PayToAddrScript(addr util.Address) (*externalapi.ScriptPublicKey, error) { const nilAddrErrStr = "unable to generate payment script for nil address" - switch addr := addr.(type) { case *util.AddressPubKeyHash: if addr == nil { return nil, scriptError(ErrUnsupportedAddress, nilAddrErrStr) } - return payToPubKeyHashScript(addr.ScriptAddress()) + script, err := payToPubKeyHashScript(addr.ScriptAddress()) + if err != nil { + return nil, err + } + return &externalapi.ScriptPublicKey{script, constants.MaxScriptPublicKeyVersion}, err case *util.AddressScriptHash: if addr == nil { return nil, scriptError(ErrUnsupportedAddress, nilAddrErrStr) } - return payToScriptHashScript(addr.ScriptAddress()) + script, err := payToScriptHashScript(addr.ScriptAddress()) + if err != nil { + return nil, err + } + return &externalapi.ScriptPublicKey{script, constants.MaxScriptPublicKeyVersion}, err } str := fmt.Sprintf("unable to generate payment script for unsupported "+ @@ -254,9 +263,12 @@ func PushedData(script []byte) ([][]byte, error) { // ExtractScriptPubKeyAddress returns the type of script and its addresses. // Note that it only works for 'standard' transaction script types. Any data such // as public keys which are invalid will return a nil address. -func ExtractScriptPubKeyAddress(scriptPubKey []byte, dagParams *dagconfig.Params) (ScriptClass, util.Address, error) { +func ExtractScriptPubKeyAddress(scriptPubKey *externalapi.ScriptPublicKey, dagParams *dagconfig.Params) (ScriptClass, util.Address, error) { + if scriptPubKey.Version > constants.MaxScriptPublicKeyVersion { + return NonStandardTy, nil, errors.Errorf("Script version is unkown.") + } // No valid address if the script doesn't parse. - pops, err := parseScript(scriptPubKey) + pops, err := parseScript(scriptPubKey.Script) if err != nil { return NonStandardTy, nil, err } diff --git a/domain/consensus/utils/txscript/standard_test.go b/domain/consensus/utils/txscript/standard_test.go index 8e19a3e91..a8a7f56e2 100644 --- a/domain/consensus/utils/txscript/standard_test.go +++ b/domain/consensus/utils/txscript/standard_test.go @@ -6,6 +6,7 @@ package txscript import ( "bytes" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "reflect" "testing" @@ -17,8 +18,8 @@ import ( // resulting bytes. It panics if an error occurs. This is only used in the // tests as a helper since the only way it can fail is if there is an error in // the test source code. -func mustParseShortForm(script string) []byte { - s, err := parseShortForm(script) +func mustParseShortForm(script string, version uint16) []byte { + s, err := parseShortForm(script, version) if err != nil { panic("invalid short form script in test source: err " + err.Error() + ", script: " + script) @@ -61,22 +62,28 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) { tests := []struct { name string - script []byte + script *externalapi.ScriptPublicKey addr util.Address class ScriptClass }{ { name: "standard p2pkh", - script: hexToBytes("76a914ad06dd6ddee55cbca9a9e3713bd" + - "7587509a3056488ac"), + script: &externalapi.ScriptPublicKey{ + Script: hexToBytes("76a914ad06dd6ddee55cbca9a9e3713bd" + + "7587509a3056488ac"), + Version: 0, + }, addr: newAddressPubKeyHash(hexToBytes("ad06dd6ddee5" + "5cbca9a9e3713bd7587509a30564")), class: PubKeyHashTy, }, { name: "standard p2sh", - script: hexToBytes("a91463bcc565f9e68ee0189dd5cc67f1b" + - "0e5f02f45cb87"), + script: &externalapi.ScriptPublicKey{ + Script: hexToBytes("a91463bcc565f9e68ee0189dd5cc67f1b" + + "0e5f02f45cb87"), + Version: 0, + }, addr: newAddressScriptHash(hexToBytes("63bcc565f9e6" + "8ee0189dd5cc67f1b0e5f02f45cb")), class: ScriptHashTy, @@ -88,19 +95,25 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) { { name: "p2pk with uncompressed pk missing OP_CHECKSIG", - script: hexToBytes("410411db93e1dcdb8a016b49840f8c53b" + - "c1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddf" + - "b84ccf9744464f82e160bfa9b8b64f9d4c03f999b864" + - "3f656b412a3"), + script: &externalapi.ScriptPublicKey{ + Script: hexToBytes("410411db93e1dcdb8a016b49840f8c53b" + + "c1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddf" + + "b84ccf9744464f82e160bfa9b8b64f9d4c03f999b864" + + "3f656b412a3"), + Version: 0, + }, addr: nil, class: NonStandardTy, }, { name: "valid signature from a sigscript - no addresses", - script: hexToBytes("47304402204e45e16932b8af514961a1d" + - "3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41022" + - "0181522ec8eca07de4860a4acdd12909d831cc56cbba" + - "c4622082221a8768d1d0901"), + script: &externalapi.ScriptPublicKey{ + Script: hexToBytes("47304402204e45e16932b8af514961a1d" + + "3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41022" + + "0181522ec8eca07de4860a4acdd12909d831cc56cbba" + + "c4622082221a8768d1d0901"), + Version: 0, + }, addr: nil, class: NonStandardTy, }, @@ -110,27 +123,36 @@ func TestExtractScriptPubKeyAddrs(t *testing.T) { // addresses. { name: "valid sigscript to reedeem p2pk - no addresses", - script: hexToBytes("493046022100ddc69738bf2336318e4e0" + - "41a5a77f305da87428ab1606f023260017854350ddc0" + - "22100817af09d2eec36862d16009852b7e3a0f6dd765" + - "98290b7834e1453660367e07a014104cd4240c198e12" + - "523b6f9cb9f5bed06de1ba37e96a1bbd13745fcf9d11" + - "c25b1dff9a519675d198804ba9962d3eca2d5937d58e" + - "5a75a71042d40388a4d307f887d"), + script: &externalapi.ScriptPublicKey{ + Script: hexToBytes("493046022100ddc69738bf2336318e4e0" + + "41a5a77f305da87428ab1606f023260017854350ddc0" + + "22100817af09d2eec36862d16009852b7e3a0f6dd765" + + "98290b7834e1453660367e07a014104cd4240c198e12" + + "523b6f9cb9f5bed06de1ba37e96a1bbd13745fcf9d11" + + "c25b1dff9a519675d198804ba9962d3eca2d5937d58e" + + "5a75a71042d40388a4d307f887d"), + Version: 0, + }, addr: nil, class: NonStandardTy, }, { - name: "empty script", - script: []byte{}, - addr: nil, - class: NonStandardTy, + name: "empty script", + script: &externalapi.ScriptPublicKey{ + Script: []byte{}, + Version: 0, + }, + addr: nil, + class: NonStandardTy, }, { - name: "script that does not parse", - script: []byte{OpData45}, - addr: nil, - class: NonStandardTy, + name: "script that does not parse", + script: &externalapi.ScriptPublicKey{ + Script: []byte{OpData45}, + Version: 0, + }, + addr: nil, + class: NonStandardTy, }, } @@ -224,8 +246,8 @@ func TestCalcScriptInfo(t *testing.T) { } for _, test := range tests { - sigScript := mustParseShortForm(test.sigScript) - scriptPubKey := mustParseShortForm(test.scriptPubKey) + sigScript := mustParseShortForm(test.sigScript, 0) + scriptPubKey := mustParseShortForm(test.scriptPubKey, 0) si, err := CalcScriptInfo(sigScript, scriptPubKey, test.isP2SH) if e := checkScriptError(err, test.scriptInfoErr); e != nil { @@ -301,15 +323,17 @@ func TestPayToAddrScript(t *testing.T) { errUnsupportedAddress := scriptError(ErrUnsupportedAddress, "") tests := []struct { - in util.Address - expected string - err error + in util.Address + expectedScript string + expectedVersion uint16 + err error }{ // pay-to-pubkey-hash address on mainnet { p2pkhMain, "DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" + "91bb4a0e8488 CHECKSIG", + 0, nil, }, // pay-to-script-hash address on mainnet @@ -317,30 +341,44 @@ func TestPayToAddrScript(t *testing.T) { p2shMain, "HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" + "6eb5b4 EQUAL", + 0, nil, }, // Supported address types with nil pointers. - {(*util.AddressPubKeyHash)(nil), "", errUnsupportedAddress}, - {(*util.AddressScriptHash)(nil), "", errUnsupportedAddress}, + {(*util.AddressPubKeyHash)(nil), "", 0, errUnsupportedAddress}, + {(*util.AddressScriptHash)(nil), "", 0, errUnsupportedAddress}, // Unsupported address type. - {&bogusAddress{}, "", errUnsupportedAddress}, + {&bogusAddress{}, "", 0, errUnsupportedAddress}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { - scriptPubKey, err := PayToAddrScript(test.in) + scriptPublicKey, err := PayToAddrScript(test.in) if e := checkScriptError(err, test.err); e != nil { t.Errorf("PayToAddrScript #%d unexpected error - "+ "got %v, want %v", i, err, test.err) continue } - expected := mustParseShortForm(test.expected) - if !bytes.Equal(scriptPubKey, expected) { + var scriptPublicKeyScript []byte + var scriptPublicKeyVersion uint16 + if scriptPublicKey != nil { + scriptPublicKeyScript = scriptPublicKey.Script + scriptPublicKeyVersion = scriptPublicKey.Version + } + + expectedVersion := test.expectedVersion + expectedScript := mustParseShortForm(test.expectedScript, test.expectedVersion) + if !bytes.Equal(scriptPublicKeyScript, expectedScript) { t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", - i, scriptPubKey, expected) + i, scriptPublicKey, expectedScript) + continue + } + if scriptPublicKeyVersion != expectedVersion { + t.Errorf("PayToAddrScript #%d got version: %d\nwant: %d", + i, scriptPublicKeyVersion, expectedVersion) continue } } @@ -454,7 +492,7 @@ func TestScriptClass(t *testing.T) { t.Parallel() for _, test := range scriptClassTests { - script := mustParseShortForm(test.script) + script := mustParseShortForm(test.script, 0) class := GetScriptClass(script) if class != test.class { t.Errorf("%s: expected %s got %s (script %x)", test.name, diff --git a/domain/consensus/utils/utxo/diff_algebra_test.go b/domain/consensus/utils/utxo/diff_algebra_test.go index 97b7efc4d..c9bf4bad8 100644 --- a/domain/consensus/utils/utxo/diff_algebra_test.go +++ b/domain/consensus/utils/utxo/diff_algebra_test.go @@ -24,8 +24,8 @@ func TestUTXOCollection(t *testing.T) { txID1, _ := transactionid.FromString("1111111111111111111111111111111111111111111111111111111111111111") outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) outpoint1 := externalapi.NewDomainOutpoint(txID1, 0) - utxoEntry0 := NewUTXOEntry(10, []byte{}, true, 0) - utxoEntry1 := NewUTXOEntry(20, []byte{}, false, 1) + utxoEntry0 := NewUTXOEntry(10, &externalapi.ScriptPublicKey{[]byte{}, 0}, true, 0) + utxoEntry1 := NewUTXOEntry(20, &externalapi.ScriptPublicKey{[]byte{}, 0}, false, 1) // For each of the following test cases, we will: // .String() the given collection and compare it to expectedStringWithMultiset @@ -83,8 +83,8 @@ func TestUTXODiff(t *testing.T) { txID1, _ := transactionid.FromString("1111111111111111111111111111111111111111111111111111111111111111") outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) outpoint1 := externalapi.NewDomainOutpoint(txID1, 0) - utxoEntry0 := NewUTXOEntry(10, []byte{}, true, 0) - utxoEntry1 := NewUTXOEntry(20, []byte{}, false, 1) + utxoEntry0 := NewUTXOEntry(10, &externalapi.ScriptPublicKey{[]byte{}, 0}, true, 0) + utxoEntry1 := NewUTXOEntry(20, &externalapi.ScriptPublicKey{[]byte{}, 0}, false, 1) diff := newMutableUTXODiff() @@ -126,8 +126,8 @@ func TestUTXODiff(t *testing.T) { func TestUTXODiffRules(t *testing.T) { txID0, _ := transactionid.FromString("0000000000000000000000000000000000000000000000000000000000000000") outpoint0 := externalapi.NewDomainOutpoint(txID0, 0) - utxoEntry1 := NewUTXOEntry(10, []byte{}, true, 0) - utxoEntry2 := NewUTXOEntry(20, []byte{}, true, 1) + utxoEntry1 := NewUTXOEntry(10, &externalapi.ScriptPublicKey{[]byte{}, 0}, true, 0) + utxoEntry2 := NewUTXOEntry(20, &externalapi.ScriptPublicKey{[]byte{}, 0}, true, 1) // For each of the following test cases, we will: // this.diffFrom(other) and compare it to expectedDiffFromResult diff --git a/domain/consensus/utils/utxo/serialization.go b/domain/consensus/utils/utxo/serialization.go index 850e0f9d7..0fae67734 100644 --- a/domain/consensus/utils/utxo/serialization.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -86,14 +86,17 @@ func serializeUTXOEntry(w io.Writer, entry externalapi.UTXOEntry) error { if err != nil { return err } - - count := uint64(len(entry.ScriptPublicKey())) + err = serialization.WriteElement(w, entry.ScriptPublicKey().Version) + if err != nil { + return err + } + count := uint64(len(entry.ScriptPublicKey().Script)) err = serialization.WriteElement(w, count) if err != nil { return err } - _, err = w.Write(entry.ScriptPublicKey()) + _, err = w.Write(entry.ScriptPublicKey().Script) if err != nil { return errors.WithStack(err) } @@ -110,17 +113,20 @@ func deserializeUTXOEntry(r io.Reader) (externalapi.UTXOEntry, error) { return nil, err } + var version uint16 + err = serialization.ReadElement(r, version) var scriptPubKeyLen uint64 err = serialization.ReadElement(r, &scriptPubKeyLen) if err != nil { return nil, err } - scriptPubKey := make([]byte, scriptPubKeyLen) - _, err = io.ReadFull(r, scriptPubKey) + scriptPubKeyScript := make([]byte, scriptPubKeyLen) + _, err = io.ReadFull(r, scriptPubKeyScript) if err != nil { return nil, errors.WithStack(err) } + scriptPubKey := externalapi.ScriptPublicKey{scriptPubKeyScript, version} - return NewUTXOEntry(amount, scriptPubKey, isCoinbase, blockBlueScore), nil + return NewUTXOEntry(amount, &scriptPubKey, isCoinbase, blockBlueScore), nil } diff --git a/domain/consensus/utils/utxo/serialization_test.go b/domain/consensus/utils/utxo/serialization_test.go index 9ac8d9015..19eab145a 100644 --- a/domain/consensus/utils/utxo/serialization_test.go +++ b/domain/consensus/utils/utxo/serialization_test.go @@ -9,10 +9,11 @@ import ( ) func Benchmark_serializeUTXO(b *testing.B) { - scriptPublicKey, err := hex.DecodeString("76a914ad06dd6ddee55cbca9a9e3713bd7587509a3056488ac") + script, err := hex.DecodeString("76a914ad06dd6ddee55cbca9a9e3713bd7587509a3056488ac") if err != nil { b.Fatalf("Error decoding scriptPublicKey string: %s", err) } + scriptPublicKey := &externalapi.ScriptPublicKey{script, 0} entry := NewUTXOEntry(5000000000, scriptPublicKey, false, 1432432) outpoint := &externalapi.DomainOutpoint{ TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ @@ -33,10 +34,11 @@ func Benchmark_serializeUTXO(b *testing.B) { } func Test_serializeUTXO(t *testing.T) { - scriptPublicKey, err := hex.DecodeString("76a914ad06dd6ddee55cbca9a9e3713bd7587509a3056488ac") + script, err := hex.DecodeString("76a914ad06dd6ddee55cbca9a9e3713bd7587509a3056488ac") if err != nil { - t.Fatalf("Error decoding scriptPublicKey string: %s", err) + t.Fatalf("Error decoding scriptPublicKey script string: %s", err) } + scriptPublicKey := &externalapi.ScriptPublicKey{Script: script, Version: 0} entry := NewUTXOEntry(5000000000, scriptPublicKey, false, 1432432) outpoint := &externalapi.DomainOutpoint{ TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{ diff --git a/domain/consensus/utils/utxo/utxo_entry.go b/domain/consensus/utils/utxo/utxo_entry.go index b6cae4bab..037e4559f 100644 --- a/domain/consensus/utils/utxo/utxo_entry.go +++ b/domain/consensus/utils/utxo/utxo_entry.go @@ -7,18 +7,18 @@ import ( type utxoEntry struct { amount uint64 - scriptPublicKey []byte + scriptPublicKey *externalapi.ScriptPublicKey blockBlueScore uint64 isCoinbase bool } // NewUTXOEntry creates a new utxoEntry representing the given txOut -func NewUTXOEntry(amount uint64, scriptPubKey []byte, isCoinbase bool, blockBlueScore uint64) externalapi.UTXOEntry { - scriptPubKeyClone := make([]byte, len(scriptPubKey)) - copy(scriptPubKeyClone, scriptPubKey) +func NewUTXOEntry(amount uint64, scriptPubKey *externalapi.ScriptPublicKey, isCoinbase bool, blockBlueScore uint64) externalapi.UTXOEntry { + scriptPubKeyClone := externalapi.ScriptPublicKey{Script: make([]byte, len(scriptPubKey.Script)), Version: scriptPubKey.Version} + copy(scriptPubKeyClone.Script, scriptPubKey.Script) return &utxoEntry{ amount: amount, - scriptPublicKey: scriptPubKeyClone, + scriptPublicKey: &scriptPubKeyClone, blockBlueScore: blockBlueScore, isCoinbase: isCoinbase, } @@ -28,10 +28,10 @@ func (u *utxoEntry) Amount() uint64 { return u.amount } -func (u *utxoEntry) ScriptPublicKey() []byte { - clone := make([]byte, len(u.scriptPublicKey)) - copy(clone, u.scriptPublicKey) - return clone +func (u *utxoEntry) ScriptPublicKey() *externalapi.ScriptPublicKey { + clone := externalapi.ScriptPublicKey{Script: make([]byte, len(u.scriptPublicKey.Script)), Version: u.scriptPublicKey.Version} + copy(clone.Script, u.scriptPublicKey.Script) + return &clone } func (u *utxoEntry) BlockBlueScore() uint64 { @@ -60,7 +60,11 @@ func (u *utxoEntry) Equal(other externalapi.UTXOEntry) bool { return false } - if !bytes.Equal(u.ScriptPublicKey(), other.ScriptPublicKey()) { + if !bytes.Equal(u.ScriptPublicKey().Script, other.ScriptPublicKey().Script) { + return false + } + + if u.ScriptPublicKey().Version != other.ScriptPublicKey().Version { return false } diff --git a/domain/consensus/utils/utxo/utxo_entry_test.go b/domain/consensus/utils/utxo/utxo_entry_test.go index 69b90277b..ba8b0b63a 100644 --- a/domain/consensus/utils/utxo/utxo_entry_test.go +++ b/domain/consensus/utils/utxo/utxo_entry_test.go @@ -25,7 +25,7 @@ func TestUTXOEntry_Equal(t *testing.T) { { utxoEntry: &utxoEntry{ 0xFFFF, - []byte{0xA1, 0xA2, 0xA3}, + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA2, 0xA3}, Version: 0}, 0xFFFF, false, }, @@ -35,7 +35,7 @@ func TestUTXOEntry_Equal(t *testing.T) { }, { baseUTXOEntry: &utxoEntry{ 0xFFFF, - []byte{0xA1, 0xA2, 0xA3}, + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA2, 0xA3}, Version: 0}, 0xFFFF, true, }, @@ -43,7 +43,7 @@ func TestUTXOEntry_Equal(t *testing.T) { { utxoEntry: &utxoEntry{ 0xFFFF, - []byte{0xA1, 0xA2, 0xA3}, + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA2, 0xA3}, Version: 0}, 0xFFFF, true, }, @@ -56,7 +56,7 @@ func TestUTXOEntry_Equal(t *testing.T) { { utxoEntry: &utxoEntry{ 0xFFFF, - []byte{0xA1, 0xA0, 0xA3}, // Changed + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA0, 0xA3}, Version: 0}, // Changed 0xFFFF, true, }, @@ -65,7 +65,7 @@ func TestUTXOEntry_Equal(t *testing.T) { { utxoEntry: &utxoEntry{ 0xFFFF, - []byte{0xA1, 0xA2, 0xA3}, + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA2, 0xA3}, Version: 0}, 0xFFFF, false, // Changed }, @@ -74,7 +74,7 @@ func TestUTXOEntry_Equal(t *testing.T) { { utxoEntry: &utxoEntry{ 0xFFFF, - []byte{0xA1, 0xA2, 0xA3}, + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA2, 0xA3}, Version: 0}, 0xFFF0, // Changed true, }, @@ -87,7 +87,7 @@ func TestUTXOEntry_Equal(t *testing.T) { { utxoEntry: &utxoEntry{ 0xFFF0, // Changed - []byte{0xA1, 0xA2, 0xA3}, + &externalapi.ScriptPublicKey{Script: []byte{0xA1, 0xA2, 0xA3}, Version: 0}, 0xFFFF, true, }, diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 088f03e9b..62dfbf5ca 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -15,6 +15,7 @@ var genesisTxOuts = []*externalapi.DomainTransactionOutput{} var genesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score + 0x00, 0x00, //script version 0x17, // Varint 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, // OP-TRUE p2sh 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, @@ -23,39 +24,39 @@ var genesisTxPayload = []byte{ // genesisCoinbaseTx is the coinbase transaction for the genesis blocks for // the main network. -var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externalapi.DomainTransactionInput{}, genesisTxOuts, +var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externalapi.DomainTransactionInput{}, genesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, genesisTxPayload) // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x8c, 0x74, 0x62, 0xc9, 0xb6, 0xa8, 0xb2, 0x7c, - 0x8d, 0x03, 0xa3, 0x7e, 0x45, 0x73, 0x31, 0x77, - 0xc7, 0xe1, 0x00, 0xa8, 0xc7, 0x75, 0xe9, 0xaa, - 0x31, 0x02, 0xa9, 0x82, 0x9f, 0xad, 0x34, 0xc8, + 0xbf, 0x07, 0x16, 0x75, 0x1e, 0x62, 0x3b, 0xbe, + 0x18, 0xab, 0x1e, 0x79, 0x09, 0xe6, 0x48, 0x5c, + 0x1b, 0xaf, 0x03, 0x08, 0x25, 0x3c, 0xb9, 0xf5, + 0x22, 0xd2, 0x9d, 0xa6, 0x4d, 0xd1, 0x01, 0xc0, }) // genesisMerkleRoot is the hash of the first transaction in the genesis block // for the main network. var genesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x32, 0xea, 0x93, 0x9a, 0x1f, 0x00, 0x50, 0xc3, - 0x97, 0x2c, 0x3d, 0xdf, 0x28, 0xb4, 0x8f, 0x1d, - 0x75, 0x9f, 0xb1, 0x82, 0x99, 0x79, 0x7a, 0x48, - 0xc9, 0xf6, 0x05, 0xc6, 0xae, 0x30, 0x49, 0xf7, + 0x0f, 0xa7, 0x42, 0x5e, 0xa9, 0xec, 0xd7, 0x1f, + 0x40, 0x53, 0x31, 0xe4, 0x88, 0x22, 0x31, 0x9a, + 0xfb, 0xa7, 0xf4, 0x66, 0x9b, 0xa4, 0x37, 0xe0, + 0x86, 0x54, 0x21, 0xaa, 0x6d, 0x4e, 0x87, 0xe6, }) // genesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the main network. var genesisBlock = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 1, + 0, []*externalapi.DomainHash{}, genesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x1763db5c4a9, + 0x176c86a5bac, 0x207fffff, - 0x1, + 0x3, ), Transactions: []*externalapi.DomainTransaction{genesisCoinbaseTx}, } @@ -64,6 +65,7 @@ var devnetGenesisTxOuts = []*externalapi.DomainTransactionOutput{} var devnetGenesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score + 0x00, 0x00, // Script version 0x17, // Varint 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, // OP-TRUE p2sh 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, @@ -73,40 +75,40 @@ var devnetGenesisTxPayload = []byte{ // devnetGenesisCoinbaseTx is the coinbase transaction for the genesis blocks for // the development network. -var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, +var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externalapi.DomainTransactionInput{}, devnetGenesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, devnetGenesisTxPayload) // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xee, 0xce, 0x68, 0x63, 0x61, 0xb4, 0xa8, 0x09, - 0x5d, 0xa3, 0x91, 0x6c, 0x12, 0x20, 0x27, 0xdd, - 0xf8, 0x16, 0x74, 0x8e, 0xd8, 0x7a, 0xfe, 0x2c, - 0xb7, 0x98, 0xe6, 0x9d, 0x47, 0x07, 0x02, 0xc5, + 0x7a, 0x45, 0xc7, 0x1e, 0x75, 0x91, 0x82, 0x7a, + 0x0f, 0x97, 0xfb, 0x20, 0x35, 0x22, 0x7c, 0x54, + 0xc2, 0x34, 0x4c, 0xc4, 0x85, 0x45, 0xcb, 0xfb, + 0x04, 0x3b, 0x2e, 0x55, 0x63, 0xcb, 0x38, 0xde, }) // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. var devnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xdf, 0x52, 0x65, 0x3a, 0x5a, 0xd4, 0x07, 0x4e, - 0xad, 0xac, 0xb3, 0xd7, 0xd6, 0x9a, 0xf5, 0xd3, - 0x68, 0x05, 0x4d, 0xef, 0xd9, 0x41, 0x28, 0x84, - 0xa9, 0x56, 0xdd, 0x68, 0x60, 0x1b, 0x8d, 0x2c, + 0x62, 0xf4, 0xfa, 0xfc, 0xb2, 0x28, 0xfc, 0x33, + 0x1b, 0xae, 0xaf, 0x4a, 0xdc, 0xa9, 0xc8, 0xc6, + 0xfb, 0xc5, 0xfc, 0xc7, 0x2c, 0x86, 0x44, 0x33, + 0xbd, 0x75, 0xf7, 0x93, 0x2c, 0x11, 0xa8, 0x2a, }) // devnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. var devnetGenesisBlock = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 1, + 0, []*externalapi.DomainHash{}, devnetGenesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x1763db5c4a9, + 0x176c903cecd, 0x1e7fffff, - 0xb6c8, + 0x3bc1, ), Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } @@ -115,6 +117,7 @@ var simnetGenesisTxOuts = []*externalapi.DomainTransactionOutput{} var simnetGenesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score + 0x00, 0x00, // Script version 0x17, // Varint 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, // OP-TRUE p2sh 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, @@ -123,40 +126,40 @@ var simnetGenesisTxPayload = []byte{ } // simnetGenesisCoinbaseTx is the coinbase transaction for the simnet genesis block. -var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, +var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externalapi.DomainTransactionInput{}, simnetGenesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, simnetGenesisTxPayload) // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xe3, 0xa4, 0x4a, 0xe5, 0xdc, 0x3d, 0x39, 0x6a, - 0xc8, 0x5b, 0x1b, 0x95, 0x30, 0x05, 0x7d, 0xb9, - 0xd4, 0xfa, 0x30, 0x9a, 0x20, 0x7a, 0x42, 0x54, - 0xf8, 0x10, 0x73, 0xc0, 0x15, 0x31, 0xf5, 0x1a, + 0x2e, 0x37, 0x4f, 0xac, 0xa9, 0xfb, 0x88, 0xea, + 0x0e, 0xb7, 0x8f, 0xb2, 0x1e, 0xbe, 0xb6, 0xe5, + 0xbf, 0x59, 0xde, 0x29, 0x98, 0x55, 0x9e, 0x21, + 0xf2, 0x3b, 0x55, 0xcc, 0x41, 0xb8, 0xd9, 0x55, }) // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. var simnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x16, 0x07, 0x15, 0x0f, 0x1b, 0xc0, 0x26, 0x27, - 0x42, 0xc5, 0x84, 0x77, 0xdb, 0x58, 0xf7, 0x87, - 0xa8, 0xe9, 0x9f, 0x21, 0x73, 0xa0, 0x9d, 0x96, - 0x6a, 0x99, 0x55, 0x46, 0x7b, 0xb2, 0x1b, 0x99, + 0x0a, 0x84, 0xe5, 0xf0, 0xae, 0x6d, 0x26, 0xd2, + 0xf6, 0xdb, 0x94, 0x00, 0xfc, 0xcd, 0xea, 0x4b, + 0x61, 0x17, 0x1b, 0xa4, 0x32, 0xae, 0xde, 0x27, + 0xfb, 0x3e, 0x1d, 0x46, 0x17, 0xf2, 0xb8, 0xac, }) // simnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. var simnetGenesisBlock = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 1, + 0, []*externalapi.DomainHash{}, simnetGenesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x1763db5c4a9, + 0x176c86a5c26, 0x207fffff, - 0x0, + 0x1, ), Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } @@ -165,46 +168,47 @@ var testnetGenesisTxOuts = []*externalapi.DomainTransactionOutput{} var testnetGenesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score + 0x00, 0x00, // Script version 0x01, // Varint 0x00, // OP-FALSE 0x6b, 0x61, 0x73, 0x70, 0x61, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, 0x74, // kaspa-testnet } // testnetGenesisCoinbaseTx is the coinbase transaction for the testnet genesis block. -var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, +var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externalapi.DomainTransactionInput{}, testnetGenesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, testnetGenesisTxPayload) // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x17, 0xb3, 0x16, 0xd3, 0x4f, 0xb5, 0x2c, 0xc1, - 0x22, 0x53, 0x1a, 0xc9, 0xde, 0x79, 0xc3, 0x03, - 0x53, 0xa2, 0x1a, 0x0d, 0x00, 0x40, 0x7d, 0x49, - 0x66, 0x0c, 0x76, 0xf2, 0x61, 0xe4, 0x9a, 0x23, + 0x5a, 0x22, 0xf5, 0x2e, 0x87, 0x5b, 0xc2, 0xf2, + 0x9d, 0xbb, 0xa7, 0xc1, 0xf6, 0x0a, 0x81, 0xde, + 0xfa, 0x1e, 0xbc, 0x87, 0x8a, 0x37, 0x20, 0xac, + 0xc6, 0x6d, 0x1f, 0x49, 0x9b, 0x0b, 0xe7, 0xe0, }) // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for testnet. var testnetGenesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xd7, 0x16, 0x4a, 0x38, 0x3b, 0x8a, 0x67, 0xc2, - 0x3b, 0x89, 0x12, 0x1c, 0xcb, 0x97, 0x89, 0xe1, - 0x12, 0x82, 0x12, 0xc2, 0x69, 0x95, 0x7f, 0x03, - 0x29, 0xd1, 0x4f, 0xdd, 0xf1, 0x93, 0xd8, 0x47, + 0xc5, 0xef, 0xd2, 0xc7, 0xa6, 0x18, 0xe0, 0xd0, + 0xd1, 0x47, 0x3c, 0x44, 0x58, 0xaa, 0xdb, 0xfb, + 0x82, 0xfc, 0x9f, 0x88, 0x73, 0x93, 0xb1, 0x91, + 0x32, 0xec, 0xf9, 0x20, 0xd1, 0x6c, 0xce, 0xe9, }) // testnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for testnet. var testnetGenesisBlock = externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( - 1, + 0, []*externalapi.DomainHash{}, testnetGenesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x1763db5c4a9, + 0x176c86a5c26, 0x1e7fffff, - 0x493d, + 0x18cbd, ), Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index f654efa87..fb973be44 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -42,7 +42,7 @@ type policy struct { // MaxTxVersion is the transaction version that the mempool should // accept. All transactions above this version are rejected as // non-standard. - MaxTxVersion int32 + MaxTxVersion uint16 // AcceptNonStd defines whether to accept non-standard transactions. If // true, non-standard transactions will be accepted into the mempool. @@ -92,7 +92,7 @@ type mempool struct { // transactions until they are mined into a block. func New(consensus consensusexternalapi.Consensus, acceptNonStd bool) miningmanagermodel.Mempool { policy := policy{ - MaxTxVersion: constants.TransactionVersion, + MaxTxVersion: constants.MaxTransactionVersion, AcceptNonStd: acceptNonStd, MaxOrphanTxs: 5, MaxOrphanTxSize: 100000, diff --git a/domain/miningmanager/mempool/policy.go b/domain/miningmanager/mempool/policy.go index 4e679f33b..ff5538cf7 100644 --- a/domain/miningmanager/mempool/policy.go +++ b/domain/miningmanager/mempool/policy.go @@ -6,6 +6,7 @@ package mempool import ( "fmt" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/estimatedsize" @@ -89,7 +90,7 @@ func checkInputsStandard(tx *consensusexternalapi.DomainTransaction) error { // function. entry := txIn.UTXOEntry originScriptPubKey := entry.ScriptPublicKey() - switch txscript.GetScriptClass(originScriptPubKey) { + switch txscript.GetScriptClass(originScriptPubKey.Script) { case txscript.ScriptHashTy: numSigOps := txscript.GetPreciseSigOpCount( txIn.SignatureScript, originScriptPubKey, true) @@ -118,7 +119,7 @@ func checkInputsStandard(tx *consensusexternalapi.DomainTransaction) error { // minimum transaction relay fee, it is considered dust. func isDust(txOut *consensusexternalapi.DomainTransactionOutput, minRelayTxFee util.Amount) bool { // Unspendable outputs are considered dust. - if txscript.IsUnspendable(txOut.ScriptPublicKey) { + if txscript.IsUnspendable(txOut.ScriptPublicKey.Script) { return true } @@ -191,9 +192,9 @@ func isDust(txOut *consensusexternalapi.DomainTransactionOutput, minRelayTxFee u func checkTransactionStandard(tx *consensusexternalapi.DomainTransaction, policy *policy) error { // The transaction must be a currently supported version. - if tx.Version > policy.MaxTxVersion || tx.Version < 1 { + if tx.Version > policy.MaxTxVersion { str := fmt.Sprintf("transaction version %d is not in the "+ - "valid range of %d-%d", tx.Version, 1, + "valid range of %d-%d", tx.Version, 0, policy.MaxTxVersion) return txRuleError(RejectNonstandard, str) } @@ -239,7 +240,10 @@ func checkTransactionStandard(tx *consensusexternalapi.DomainTransaction, policy // None of the output public key scripts can be a non-standard script or // be "dust". for i, txOut := range tx.Outputs { - scriptClass := txscript.GetScriptClass(txOut.ScriptPublicKey) + if txOut.ScriptPublicKey.Version > constants.MaxScriptPublicKeyVersion { + return txRuleError(RejectNonstandard, "The version of the scriptPublicKey is higher than the known version.") + } + scriptClass := txscript.GetScriptClass(txOut.ScriptPublicKey.Script) if scriptClass == txscript.NonStandardTy { str := fmt.Sprintf("transaction output %d: non-standard script form", i) return txRuleError(RejectNonstandard, str) diff --git a/domain/miningmanager/mempool/policy_test.go b/domain/miningmanager/mempool/policy_test.go index 15ccc13a1..1968db7c2 100644 --- a/domain/miningmanager/mempool/policy_test.go +++ b/domain/miningmanager/mempool/policy_test.go @@ -95,11 +95,12 @@ func TestCalcMinRequiredTxRelayFee(t *testing.T) { // TestDust tests the isDust API. func TestDust(t *testing.T) { - ScriptPublicKey := []byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43, - 0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9, - 0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c, - 0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d, - 0xba, 0x5e, 0x88, 0xac} + scriptPublicKey := &consensusexternalapi.ScriptPublicKey{ + []byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43, + 0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9, + 0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c, + 0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d, + 0xba, 0x5e}, 0} tests := []struct { name string // test description @@ -110,40 +111,40 @@ func TestDust(t *testing.T) { { // Any value is allowed with a zero relay fee. "zero value with zero relay fee", - consensusexternalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: ScriptPublicKey}, + consensusexternalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPublicKey}, 0, false, }, { // Zero value is dust with any relay fee" "zero value with very small tx fee", - consensusexternalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: ScriptPublicKey}, + consensusexternalapi.DomainTransactionOutput{Value: 0, ScriptPublicKey: scriptPublicKey}, 1, true, }, { - "38 byte public key script with value 605", - consensusexternalapi.DomainTransactionOutput{Value: 605, ScriptPublicKey: ScriptPublicKey}, + "36 byte public key script with value 605", + consensusexternalapi.DomainTransactionOutput{Value: 605, ScriptPublicKey: scriptPublicKey}, 1000, true, }, { - "38 byte public key script with value 606", - consensusexternalapi.DomainTransactionOutput{Value: 606, ScriptPublicKey: ScriptPublicKey}, + "36 byte public key script with value 606", + consensusexternalapi.DomainTransactionOutput{Value: 606, ScriptPublicKey: scriptPublicKey}, 1000, false, }, { // Maximum allowed value is never dust. "max sompi amount is never dust", - consensusexternalapi.DomainTransactionOutput{Value: util.MaxSompi, ScriptPublicKey: ScriptPublicKey}, + consensusexternalapi.DomainTransactionOutput{Value: util.MaxSompi, ScriptPublicKey: scriptPublicKey}, util.MaxSompi, false, }, { // Maximum int64 value causes overflow. "maximum int64 value", - consensusexternalapi.DomainTransactionOutput{Value: 1<<63 - 1, ScriptPublicKey: ScriptPublicKey}, + consensusexternalapi.DomainTransactionOutput{Value: 1<<63 - 1, ScriptPublicKey: scriptPublicKey}, 1<<63 - 1, true, }, @@ -151,7 +152,7 @@ func TestDust(t *testing.T) { // Unspendable ScriptPublicKey due to an invalid public key // script. "unspendable ScriptPublicKey", - consensusexternalapi.DomainTransactionOutput{Value: 5000, ScriptPublicKey: []byte{0x01}}, + consensusexternalapi.DomainTransactionOutput{Value: 5000, ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{[]byte{0x01}, 0}}, 0, // no relay fee true, }, @@ -200,34 +201,23 @@ func TestCheckTransactionStandard(t *testing.T) { }{ { name: "Typical pay-to-pubkey-hash transaction", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, height: 300000, isStandard: true, }, { name: "Transaction version too high", - tx: consensusexternalapi.DomainTransaction{Version: constants.TransactionVersion + 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, + tx: consensusexternalapi.DomainTransaction{Version: constants.MaxTransactionVersion + 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, height: 300000, isStandard: false, code: RejectNonstandard, }, - // This is commented out, because transaction finaliation is a consensus check, not a policy check. - //{ - // name: "Transaction is not finalized", - // tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{{ - // PreviousOutpoint: dummyPrevOut, - // SignatureScript: dummySigScript, - // Sequence: 0, - // }}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}, LockTime: 300001}, - // height: 300000, - // isStandard: false, - // code: RejectNonstandard, - //}, + { name: "Transaction size is too large", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ Value: 0, - ScriptPublicKey: bytes.Repeat([]byte{0x00}, MaxStandardTxSize+1), + ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{bytes.Repeat([]byte{0x00}, MaxStandardTxSize+1), 0}, }}}, height: 300000, isStandard: false, @@ -235,7 +225,7 @@ func TestCheckTransactionStandard(t *testing.T) { }, { name: "Signature script size is too large", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{{ + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{{ PreviousOutpoint: dummyPrevOut, SignatureScript: bytes.Repeat([]byte{0x00}, maxStandardSigScriptSize+1), @@ -247,7 +237,7 @@ func TestCheckTransactionStandard(t *testing.T) { }, { name: "Signature script that does more than push data", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{{ + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{{ PreviousOutpoint: dummyPrevOut, SignatureScript: []byte{ txscript.OpCheckSigVerify}, @@ -259,17 +249,17 @@ func TestCheckTransactionStandard(t *testing.T) { }, { name: "Valid but non standard public key script", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ Value: 100000000, - ScriptPublicKey: []byte{txscript.OpTrue}, + ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{[]byte{txscript.OpTrue}, 0}, }}}, height: 300000, isStandard: false, code: RejectNonstandard, }, - { + { //Todo : check on ScriptPublicKey type. name: "Dust output", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ Value: 0, ScriptPublicKey: dummyScriptPublicKey, }}}, @@ -279,9 +269,9 @@ func TestCheckTransactionStandard(t *testing.T) { }, { name: "Nulldata transaction", - tx: consensusexternalapi.DomainTransaction{Version: 1, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ + tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ Value: 0, - ScriptPublicKey: []byte{txscript.OpReturn}, + ScriptPublicKey: &consensusexternalapi.ScriptPublicKey{[]byte{txscript.OpReturn}, 0}, }}}, height: 300000, isStandard: false, @@ -291,7 +281,7 @@ func TestCheckTransactionStandard(t *testing.T) { for _, test := range tests { // Ensure standardness is as expected. - err := checkTransactionStandard(&test.tx, &policy{MinRelayTxFee: DefaultMinRelayTxFee, MaxTxVersion: 1}) + err := checkTransactionStandard(&test.tx, &policy{MinRelayTxFee: DefaultMinRelayTxFee, MaxTxVersion: 0}) if err == nil && test.isStandard { // Test passes since function returned standard for a // transaction which is intended to be standard. diff --git a/domain/utxoindex/model.go b/domain/utxoindex/model.go index c8ded415f..d877f2cd6 100644 --- a/domain/utxoindex/model.go +++ b/domain/utxoindex/model.go @@ -1,6 +1,7 @@ package utxoindex import ( + "encoding/binary" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) @@ -23,11 +24,20 @@ type UTXOChanges struct { } // ConvertScriptPublicKeyToString converts the given scriptPublicKey to a string -func ConvertScriptPublicKeyToString(scriptPublicKey []byte) ScriptPublicKeyString { - return ScriptPublicKeyString(scriptPublicKey) +func ConvertScriptPublicKeyToString(scriptPublicKey *externalapi.ScriptPublicKey) ScriptPublicKeyString { + var versionBytes = make([]byte, 2) // uint16 + binary.LittleEndian.PutUint16(versionBytes, scriptPublicKey.Version) + versionString := ScriptPublicKeyString(versionBytes) + scriptString := ScriptPublicKeyString(scriptPublicKey.Script) + return versionString + scriptString + } -// ConvertStringToScriptPublicKey converts the given string to a scriptPublicKey byte slice -func ConvertStringToScriptPublicKey(string ScriptPublicKeyString) []byte { - return []byte(string) +// ConvertStringToScriptPublicKey converts the given string to a scriptPublicKey +func ConvertStringToScriptPublicKey(string ScriptPublicKeyString) *externalapi.ScriptPublicKey { + bytes := []byte(string) + version := binary.LittleEndian.Uint16(bytes[:2]) + script := bytes[2:] + return &externalapi.ScriptPublicKey{Script: script, Version: version} + } diff --git a/domain/utxoindex/store.go b/domain/utxoindex/store.go index e2e8e4b9f..9fd7b6ce9 100644 --- a/domain/utxoindex/store.go +++ b/domain/utxoindex/store.go @@ -1,6 +1,7 @@ package utxoindex import ( + "encoding/binary" "github.com/golang/protobuf/proto" "github.com/kaspanet/kaspad/domain/consensus/database/serialization" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -27,7 +28,8 @@ func newUTXOIndexStore(database database.Database) *utxoIndexStore { } } -func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error { +func (uis *utxoIndexStore) add(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry) error { + key := ConvertScriptPublicKeyToString(scriptPublicKey) log.Tracef("Adding outpoint %s:%d to scriptPublicKey %s", outpoint.TransactionID, outpoint.Index, key) @@ -61,7 +63,7 @@ func (uis *utxoIndexStore) add(scriptPublicKey []byte, outpoint *externalapi.Dom return nil } -func (uis *utxoIndexStore) remove(scriptPublicKey []byte, outpoint *externalapi.DomainOutpoint) error { +func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey, outpoint *externalapi.DomainOutpoint) error { key := ConvertScriptPublicKeyToString(scriptPublicKey) log.Tracef("Removing outpoint %s:%d from scriptPublicKey %s", outpoint.TransactionID, outpoint.Index, key) @@ -159,8 +161,11 @@ func (uis *utxoIndexStore) commit() error { return nil } -func (uis *utxoIndexStore) bucketForScriptPublicKey(scriptPublicKey []byte) *database.Bucket { - return utxoIndexBucket.Bucket(scriptPublicKey) +func (uis *utxoIndexStore) bucketForScriptPublicKey(scriptPublicKey *externalapi.ScriptPublicKey) *database.Bucket { + var scriptPublicKeyBytes = make([]byte, 2+len(scriptPublicKey.Script)) // uint16 + binary.LittleEndian.PutUint16(scriptPublicKeyBytes[:2], scriptPublicKey.Version) + copy(scriptPublicKeyBytes[2:], scriptPublicKey.Script) + return utxoIndexBucket.Bucket(scriptPublicKeyBytes) } func (uis *utxoIndexStore) convertOutpointToKey(bucket *database.Bucket, outpoint *externalapi.DomainOutpoint) (*database.Key, error) { @@ -201,7 +206,7 @@ func (uis *utxoIndexStore) deserializeUTXOEntry(serializedUTXOEntry []byte) (ext if err != nil { return nil, err } - return serialization.DBUTXOEntryToUTXOEntry(&dbUTXOEntry), nil + return serialization.DBUTXOEntryToUTXOEntry(&dbUTXOEntry) } func (uis *utxoIndexStore) stagedData() ( @@ -229,7 +234,7 @@ func (uis *utxoIndexStore) stagedData() ( return toAddClone, toRemoveClone } -func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) { +func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey *externalapi.ScriptPublicKey) (UTXOOutpointEntryPairs, error) { if uis.isAnythingStaged() { return nil, errors.Errorf("cannot get utxo outpoint entry pairs while staging isn't empty") } diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go index c538a29ac..dce226348 100644 --- a/domain/utxoindex/utxoindex.go +++ b/domain/utxoindex/utxoindex.go @@ -231,7 +231,7 @@ func (ui *UTXOIndex) removeTransaction(transaction *externalapi.DomainTransactio } // UTXOs returns all the UTXOs for the given scriptPublicKey -func (ui *UTXOIndex) UTXOs(scriptPublicKey []byte) (UTXOOutpointEntryPairs, error) { +func (ui *UTXOIndex) UTXOs(scriptPublicKey *externalapi.ScriptPublicKey) (UTXOOutpointEntryPairs, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.UTXOs") defer onEnd() diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 0c855de34..e947ab80c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -1523,7 +1523,7 @@ type TransactionMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` Inputs []*TransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` Outputs []*TransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` @@ -1565,7 +1565,7 @@ func (*TransactionMessage) Descriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{5} } -func (x *TransactionMessage) GetVersion() int32 { +func (x *TransactionMessage) GetVersion() uint32 { if x != nil { return x.Version } @@ -1786,19 +1786,74 @@ func (x *TransactionId) GetBytes() []byte { return nil } +type ScriptPublicKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Script []byte `protobuf:"bytes,1,opt,name=script,proto3" json:"script,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` +} + +func (x *ScriptPublicKey) Reset() { + *x = ScriptPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScriptPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScriptPublicKey) ProtoMessage() {} + +func (x *ScriptPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScriptPublicKey.ProtoReflect.Descriptor instead. +func (*ScriptPublicKey) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{9} +} + +func (x *ScriptPublicKey) GetScript() []byte { + if x != nil { + return x.Script + } + return nil +} + +func (x *ScriptPublicKey) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + type TransactionOutput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - ScriptPubKey []byte `protobuf:"bytes,2,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + ScriptPublicKey *ScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` } func (x *TransactionOutput) Reset() { *x = TransactionOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[9] + mi := &file_messages_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1811,7 +1866,7 @@ func (x *TransactionOutput) String() string { func (*TransactionOutput) ProtoMessage() {} func (x *TransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[9] + mi := &file_messages_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1824,7 +1879,7 @@ func (x *TransactionOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionOutput.ProtoReflect.Descriptor instead. func (*TransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{9} + return file_messages_proto_rawDescGZIP(), []int{10} } func (x *TransactionOutput) GetValue() uint64 { @@ -1834,9 +1889,9 @@ func (x *TransactionOutput) GetValue() uint64 { return 0 } -func (x *TransactionOutput) GetScriptPubKey() []byte { +func (x *TransactionOutput) GetScriptPublicKey() *ScriptPublicKey { if x != nil { - return x.ScriptPubKey + return x.ScriptPublicKey } return nil } @@ -1854,7 +1909,7 @@ type BlockMessage struct { func (x *BlockMessage) Reset() { *x = BlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[10] + mi := &file_messages_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1867,7 +1922,7 @@ func (x *BlockMessage) String() string { func (*BlockMessage) ProtoMessage() {} func (x *BlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[10] + mi := &file_messages_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1880,7 +1935,7 @@ func (x *BlockMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockMessage.ProtoReflect.Descriptor instead. func (*BlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{10} + return file_messages_proto_rawDescGZIP(), []int{11} } func (x *BlockMessage) GetHeader() *BlockHeaderMessage { @@ -1902,7 +1957,7 @@ type BlockHeaderMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` ParentHashes []*Hash `protobuf:"bytes,2,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` HashMerkleRoot *Hash `protobuf:"bytes,3,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` AcceptedIdMerkleRoot *Hash `protobuf:"bytes,4,opt,name=acceptedIdMerkleRoot,proto3" json:"acceptedIdMerkleRoot,omitempty"` @@ -1915,7 +1970,7 @@ type BlockHeaderMessage struct { func (x *BlockHeaderMessage) Reset() { *x = BlockHeaderMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[11] + mi := &file_messages_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1928,7 +1983,7 @@ func (x *BlockHeaderMessage) String() string { func (*BlockHeaderMessage) ProtoMessage() {} func (x *BlockHeaderMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[11] + mi := &file_messages_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1941,10 +1996,10 @@ func (x *BlockHeaderMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockHeaderMessage.ProtoReflect.Descriptor instead. func (*BlockHeaderMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{11} + return file_messages_proto_rawDescGZIP(), []int{12} } -func (x *BlockHeaderMessage) GetVersion() int32 { +func (x *BlockHeaderMessage) GetVersion() uint32 { if x != nil { return x.Version } @@ -2011,7 +2066,7 @@ type Hash struct { func (x *Hash) Reset() { *x = Hash{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[12] + mi := &file_messages_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2024,7 +2079,7 @@ func (x *Hash) String() string { func (*Hash) ProtoMessage() {} func (x *Hash) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[12] + mi := &file_messages_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2037,7 +2092,7 @@ func (x *Hash) ProtoReflect() protoreflect.Message { // Deprecated: Use Hash.ProtoReflect.Descriptor instead. func (*Hash) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{12} + return file_messages_proto_rawDescGZIP(), []int{13} } func (x *Hash) GetBytes() []byte { @@ -2061,7 +2116,7 @@ type RequestBlockLocatorMessage struct { func (x *RequestBlockLocatorMessage) Reset() { *x = RequestBlockLocatorMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[13] + mi := &file_messages_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2074,7 +2129,7 @@ func (x *RequestBlockLocatorMessage) String() string { func (*RequestBlockLocatorMessage) ProtoMessage() {} func (x *RequestBlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[13] + mi := &file_messages_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2087,7 +2142,7 @@ func (x *RequestBlockLocatorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestBlockLocatorMessage.ProtoReflect.Descriptor instead. func (*RequestBlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{13} + return file_messages_proto_rawDescGZIP(), []int{14} } func (x *RequestBlockLocatorMessage) GetLowHash() *Hash { @@ -2123,7 +2178,7 @@ type BlockLocatorMessage struct { func (x *BlockLocatorMessage) Reset() { *x = BlockLocatorMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[14] + mi := &file_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2136,7 +2191,7 @@ func (x *BlockLocatorMessage) String() string { func (*BlockLocatorMessage) ProtoMessage() {} func (x *BlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[14] + mi := &file_messages_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2149,7 +2204,7 @@ func (x *BlockLocatorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockLocatorMessage.ProtoReflect.Descriptor instead. func (*BlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{14} + return file_messages_proto_rawDescGZIP(), []int{15} } func (x *BlockLocatorMessage) GetHashes() []*Hash { @@ -2172,7 +2227,7 @@ type RequestHeadersMessage struct { func (x *RequestHeadersMessage) Reset() { *x = RequestHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[15] + mi := &file_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2185,7 +2240,7 @@ func (x *RequestHeadersMessage) String() string { func (*RequestHeadersMessage) ProtoMessage() {} func (x *RequestHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[15] + mi := &file_messages_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2198,7 +2253,7 @@ func (x *RequestHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestHeadersMessage.ProtoReflect.Descriptor instead. func (*RequestHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{15} + return file_messages_proto_rawDescGZIP(), []int{16} } func (x *RequestHeadersMessage) GetLowHash() *Hash { @@ -2225,7 +2280,7 @@ type RequestNextHeadersMessage struct { func (x *RequestNextHeadersMessage) Reset() { *x = RequestNextHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[16] + mi := &file_messages_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2238,7 +2293,7 @@ func (x *RequestNextHeadersMessage) String() string { func (*RequestNextHeadersMessage) ProtoMessage() {} func (x *RequestNextHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[16] + mi := &file_messages_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2251,7 +2306,7 @@ func (x *RequestNextHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestNextHeadersMessage.ProtoReflect.Descriptor instead. func (*RequestNextHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{16} + return file_messages_proto_rawDescGZIP(), []int{17} } // DoneIBDBlocksMessage start @@ -2264,7 +2319,7 @@ type DoneHeadersMessage struct { func (x *DoneHeadersMessage) Reset() { *x = DoneHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[17] + mi := &file_messages_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2277,7 +2332,7 @@ func (x *DoneHeadersMessage) String() string { func (*DoneHeadersMessage) ProtoMessage() {} func (x *DoneHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[17] + mi := &file_messages_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2290,7 +2345,7 @@ func (x *DoneHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use DoneHeadersMessage.ProtoReflect.Descriptor instead. func (*DoneHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{17} + return file_messages_proto_rawDescGZIP(), []int{18} } // RequestRelayBlocksMessage start @@ -2305,7 +2360,7 @@ type RequestRelayBlocksMessage struct { func (x *RequestRelayBlocksMessage) Reset() { *x = RequestRelayBlocksMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[18] + mi := &file_messages_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2318,7 +2373,7 @@ func (x *RequestRelayBlocksMessage) String() string { func (*RequestRelayBlocksMessage) ProtoMessage() {} func (x *RequestRelayBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[18] + mi := &file_messages_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2331,7 +2386,7 @@ func (x *RequestRelayBlocksMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestRelayBlocksMessage.ProtoReflect.Descriptor instead. func (*RequestRelayBlocksMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{18} + return file_messages_proto_rawDescGZIP(), []int{19} } func (x *RequestRelayBlocksMessage) GetHashes() []*Hash { @@ -2353,7 +2408,7 @@ type RequestTransactionsMessage struct { func (x *RequestTransactionsMessage) Reset() { *x = RequestTransactionsMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[19] + mi := &file_messages_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2366,7 +2421,7 @@ func (x *RequestTransactionsMessage) String() string { func (*RequestTransactionsMessage) ProtoMessage() {} func (x *RequestTransactionsMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[19] + mi := &file_messages_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2379,7 +2434,7 @@ func (x *RequestTransactionsMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestTransactionsMessage.ProtoReflect.Descriptor instead. func (*RequestTransactionsMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{19} + return file_messages_proto_rawDescGZIP(), []int{20} } func (x *RequestTransactionsMessage) GetIds() []*TransactionId { @@ -2401,7 +2456,7 @@ type TransactionNotFoundMessage struct { func (x *TransactionNotFoundMessage) Reset() { *x = TransactionNotFoundMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[20] + mi := &file_messages_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2414,7 +2469,7 @@ func (x *TransactionNotFoundMessage) String() string { func (*TransactionNotFoundMessage) ProtoMessage() {} func (x *TransactionNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[20] + mi := &file_messages_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2427,7 +2482,7 @@ func (x *TransactionNotFoundMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionNotFoundMessage.ProtoReflect.Descriptor instead. func (*TransactionNotFoundMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{20} + return file_messages_proto_rawDescGZIP(), []int{21} } func (x *TransactionNotFoundMessage) GetId() *TransactionId { @@ -2449,7 +2504,7 @@ type InvRelayBlockMessage struct { func (x *InvRelayBlockMessage) Reset() { *x = InvRelayBlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[21] + mi := &file_messages_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2462,7 +2517,7 @@ func (x *InvRelayBlockMessage) String() string { func (*InvRelayBlockMessage) ProtoMessage() {} func (x *InvRelayBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[21] + mi := &file_messages_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2475,7 +2530,7 @@ func (x *InvRelayBlockMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use InvRelayBlockMessage.ProtoReflect.Descriptor instead. func (*InvRelayBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{21} + return file_messages_proto_rawDescGZIP(), []int{22} } func (x *InvRelayBlockMessage) GetHash() *Hash { @@ -2497,7 +2552,7 @@ type InvTransactionsMessage struct { func (x *InvTransactionsMessage) Reset() { *x = InvTransactionsMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[22] + mi := &file_messages_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2510,7 +2565,7 @@ func (x *InvTransactionsMessage) String() string { func (*InvTransactionsMessage) ProtoMessage() {} func (x *InvTransactionsMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[22] + mi := &file_messages_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2523,7 +2578,7 @@ func (x *InvTransactionsMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use InvTransactionsMessage.ProtoReflect.Descriptor instead. func (*InvTransactionsMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{22} + return file_messages_proto_rawDescGZIP(), []int{23} } func (x *InvTransactionsMessage) GetIds() []*TransactionId { @@ -2545,7 +2600,7 @@ type PingMessage struct { func (x *PingMessage) Reset() { *x = PingMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[23] + mi := &file_messages_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2558,7 +2613,7 @@ func (x *PingMessage) String() string { func (*PingMessage) ProtoMessage() {} func (x *PingMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[23] + mi := &file_messages_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2571,7 +2626,7 @@ func (x *PingMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use PingMessage.ProtoReflect.Descriptor instead. func (*PingMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{23} + return file_messages_proto_rawDescGZIP(), []int{24} } func (x *PingMessage) GetNonce() uint64 { @@ -2593,7 +2648,7 @@ type PongMessage struct { func (x *PongMessage) Reset() { *x = PongMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[24] + mi := &file_messages_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2606,7 +2661,7 @@ func (x *PongMessage) String() string { func (*PongMessage) ProtoMessage() {} func (x *PongMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[24] + mi := &file_messages_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2619,7 +2674,7 @@ func (x *PongMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use PongMessage.ProtoReflect.Descriptor instead. func (*PongMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{24} + return file_messages_proto_rawDescGZIP(), []int{25} } func (x *PongMessage) GetNonce() uint64 { @@ -2639,7 +2694,7 @@ type VerackMessage struct { func (x *VerackMessage) Reset() { *x = VerackMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[25] + mi := &file_messages_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2652,7 +2707,7 @@ func (x *VerackMessage) String() string { func (*VerackMessage) ProtoMessage() {} func (x *VerackMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[25] + mi := &file_messages_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2665,7 +2720,7 @@ func (x *VerackMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use VerackMessage.ProtoReflect.Descriptor instead. func (*VerackMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{25} + return file_messages_proto_rawDescGZIP(), []int{26} } // VersionMessage start @@ -2688,7 +2743,7 @@ type VersionMessage struct { func (x *VersionMessage) Reset() { *x = VersionMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[26] + mi := &file_messages_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2701,7 +2756,7 @@ func (x *VersionMessage) String() string { func (*VersionMessage) ProtoMessage() {} func (x *VersionMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[26] + mi := &file_messages_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2714,7 +2769,7 @@ func (x *VersionMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionMessage.ProtoReflect.Descriptor instead. func (*VersionMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{26} + return file_messages_proto_rawDescGZIP(), []int{27} } func (x *VersionMessage) GetProtocolVersion() uint32 { @@ -2792,7 +2847,7 @@ type RejectMessage struct { func (x *RejectMessage) Reset() { *x = RejectMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[27] + mi := &file_messages_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2805,7 +2860,7 @@ func (x *RejectMessage) String() string { func (*RejectMessage) ProtoMessage() {} func (x *RejectMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[27] + mi := &file_messages_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2818,7 +2873,7 @@ func (x *RejectMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectMessage.ProtoReflect.Descriptor instead. func (*RejectMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{27} + return file_messages_proto_rawDescGZIP(), []int{28} } func (x *RejectMessage) GetReason() string { @@ -2840,7 +2895,7 @@ type RequestIBDRootUTXOSetAndBlockMessage struct { func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { *x = RequestIBDRootUTXOSetAndBlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[28] + mi := &file_messages_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2853,7 +2908,7 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) String() string { func (*RequestIBDRootUTXOSetAndBlockMessage) ProtoMessage() {} func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[28] + mi := &file_messages_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2866,7 +2921,7 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Messa // Deprecated: Use RequestIBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. func (*RequestIBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{28} + return file_messages_proto_rawDescGZIP(), []int{29} } func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { @@ -2889,7 +2944,7 @@ type IBDRootUTXOSetAndBlockMessage struct { func (x *IBDRootUTXOSetAndBlockMessage) Reset() { *x = IBDRootUTXOSetAndBlockMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[29] + mi := &file_messages_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2902,7 +2957,7 @@ func (x *IBDRootUTXOSetAndBlockMessage) String() string { func (*IBDRootUTXOSetAndBlockMessage) ProtoMessage() {} func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[29] + mi := &file_messages_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2915,7 +2970,7 @@ func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. func (*IBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{29} + return file_messages_proto_rawDescGZIP(), []int{30} } func (x *IBDRootUTXOSetAndBlockMessage) GetUtxoSet() []byte { @@ -2944,7 +2999,7 @@ type RequestIBDBlocksMessage struct { func (x *RequestIBDBlocksMessage) Reset() { *x = RequestIBDBlocksMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[30] + mi := &file_messages_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2957,7 +3012,7 @@ func (x *RequestIBDBlocksMessage) String() string { func (*RequestIBDBlocksMessage) ProtoMessage() {} func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[30] + mi := &file_messages_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2970,7 +3025,7 @@ func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{30} + return file_messages_proto_rawDescGZIP(), []int{31} } func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { @@ -2990,7 +3045,7 @@ type IBDRootNotFoundMessage struct { func (x *IBDRootNotFoundMessage) Reset() { *x = IBDRootNotFoundMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[31] + mi := &file_messages_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3003,7 +3058,7 @@ func (x *IBDRootNotFoundMessage) String() string { func (*IBDRootNotFoundMessage) ProtoMessage() {} func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[31] + mi := &file_messages_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3016,7 +3071,7 @@ func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{31} + return file_messages_proto_rawDescGZIP(), []int{32} } // RequestIBDRootHashMessage start @@ -3029,7 +3084,7 @@ type RequestIBDRootHashMessage struct { func (x *RequestIBDRootHashMessage) Reset() { *x = RequestIBDRootHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3042,7 +3097,7 @@ func (x *RequestIBDRootHashMessage) String() string { func (*RequestIBDRootHashMessage) ProtoMessage() {} func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[32] + mi := &file_messages_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3055,7 +3110,7 @@ func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestIBDRootHashMessage.ProtoReflect.Descriptor instead. func (*RequestIBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{32} + return file_messages_proto_rawDescGZIP(), []int{33} } // IBDRootHashMessage start @@ -3070,7 +3125,7 @@ type IBDRootHashMessage struct { func (x *IBDRootHashMessage) Reset() { *x = IBDRootHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3083,7 +3138,7 @@ func (x *IBDRootHashMessage) String() string { func (*IBDRootHashMessage) ProtoMessage() {} func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3096,7 +3151,7 @@ func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootHashMessage.ProtoReflect.Descriptor instead. func (*IBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{33} + return file_messages_proto_rawDescGZIP(), []int{34} } func (x *IBDRootHashMessage) GetHash() *Hash { @@ -3119,7 +3174,7 @@ type IbdBlockLocatorMessage struct { func (x *IbdBlockLocatorMessage) Reset() { *x = IbdBlockLocatorMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3132,7 +3187,7 @@ func (x *IbdBlockLocatorMessage) String() string { func (*IbdBlockLocatorMessage) ProtoMessage() {} func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3145,7 +3200,7 @@ func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IbdBlockLocatorMessage.ProtoReflect.Descriptor instead. func (*IbdBlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} + return file_messages_proto_rawDescGZIP(), []int{35} } func (x *IbdBlockLocatorMessage) GetTargetHash() *Hash { @@ -3174,7 +3229,7 @@ type IbdBlockLocatorHighestHashMessage struct { func (x *IbdBlockLocatorHighestHashMessage) Reset() { *x = IbdBlockLocatorHighestHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3187,7 +3242,7 @@ func (x *IbdBlockLocatorHighestHashMessage) String() string { func (*IbdBlockLocatorHighestHashMessage) ProtoMessage() {} func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[35] + mi := &file_messages_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3200,7 +3255,7 @@ func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message // Deprecated: Use IbdBlockLocatorHighestHashMessage.ProtoReflect.Descriptor instead. func (*IbdBlockLocatorHighestHashMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{35} + return file_messages_proto_rawDescGZIP(), []int{36} } func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { @@ -3221,7 +3276,7 @@ type BlockHeadersMessage struct { func (x *BlockHeadersMessage) Reset() { *x = BlockHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3234,7 +3289,7 @@ func (x *BlockHeadersMessage) String() string { func (*BlockHeadersMessage) ProtoMessage() {} func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] + mi := &file_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3247,7 +3302,7 @@ func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} + return file_messages_proto_rawDescGZIP(), []int{37} } func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { @@ -3268,7 +3323,7 @@ type RPCError struct { func (x *RPCError) Reset() { *x = RPCError{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3281,7 +3336,7 @@ func (x *RPCError) String() string { func (*RPCError) ProtoMessage() {} func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] + mi := &file_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3294,7 +3349,7 @@ func (x *RPCError) ProtoReflect() protoreflect.Message { // Deprecated: Use RPCError.ProtoReflect.Descriptor instead. func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} + return file_messages_proto_rawDescGZIP(), []int{38} } func (x *RPCError) GetMessage() string { @@ -3313,7 +3368,7 @@ type GetCurrentNetworkRequestMessage struct { func (x *GetCurrentNetworkRequestMessage) Reset() { *x = GetCurrentNetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3326,7 +3381,7 @@ func (x *GetCurrentNetworkRequestMessage) String() string { func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] + mi := &file_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3339,7 +3394,7 @@ func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} + return file_messages_proto_rawDescGZIP(), []int{39} } type GetCurrentNetworkResponseMessage struct { @@ -3354,7 +3409,7 @@ type GetCurrentNetworkResponseMessage struct { func (x *GetCurrentNetworkResponseMessage) Reset() { *x = GetCurrentNetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3367,7 +3422,7 @@ func (x *GetCurrentNetworkResponseMessage) String() string { func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] + mi := &file_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3380,7 +3435,7 @@ func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} + return file_messages_proto_rawDescGZIP(), []int{40} } func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { @@ -3408,7 +3463,7 @@ type SubmitBlockRequestMessage struct { func (x *SubmitBlockRequestMessage) Reset() { *x = SubmitBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3421,7 +3476,7 @@ func (x *SubmitBlockRequestMessage) String() string { func (*SubmitBlockRequestMessage) ProtoMessage() {} func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] + mi := &file_messages_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3434,7 +3489,7 @@ func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} + return file_messages_proto_rawDescGZIP(), []int{41} } func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { @@ -3455,7 +3510,7 @@ type SubmitBlockResponseMessage struct { func (x *SubmitBlockResponseMessage) Reset() { *x = SubmitBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3468,7 +3523,7 @@ func (x *SubmitBlockResponseMessage) String() string { func (*SubmitBlockResponseMessage) ProtoMessage() {} func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] + mi := &file_messages_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3481,7 +3536,7 @@ func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} + return file_messages_proto_rawDescGZIP(), []int{42} } func (x *SubmitBlockResponseMessage) GetError() *RPCError { @@ -3502,7 +3557,7 @@ type GetBlockTemplateRequestMessage struct { func (x *GetBlockTemplateRequestMessage) Reset() { *x = GetBlockTemplateRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3515,7 +3570,7 @@ func (x *GetBlockTemplateRequestMessage) String() string { func (*GetBlockTemplateRequestMessage) ProtoMessage() {} func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] + mi := &file_messages_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3528,7 +3583,7 @@ func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} + return file_messages_proto_rawDescGZIP(), []int{43} } func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { @@ -3551,7 +3606,7 @@ type GetBlockTemplateResponseMessage struct { func (x *GetBlockTemplateResponseMessage) Reset() { *x = GetBlockTemplateResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3564,7 +3619,7 @@ func (x *GetBlockTemplateResponseMessage) String() string { func (*GetBlockTemplateResponseMessage) ProtoMessage() {} func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] + mi := &file_messages_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3577,7 +3632,7 @@ func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} + return file_messages_proto_rawDescGZIP(), []int{44} } func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { @@ -3610,7 +3665,7 @@ type NotifyBlockAddedRequestMessage struct { func (x *NotifyBlockAddedRequestMessage) Reset() { *x = NotifyBlockAddedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3623,7 +3678,7 @@ func (x *NotifyBlockAddedRequestMessage) String() string { func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] + mi := &file_messages_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3636,7 +3691,7 @@ func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} + return file_messages_proto_rawDescGZIP(), []int{45} } type NotifyBlockAddedResponseMessage struct { @@ -3650,7 +3705,7 @@ type NotifyBlockAddedResponseMessage struct { func (x *NotifyBlockAddedResponseMessage) Reset() { *x = NotifyBlockAddedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3663,7 +3718,7 @@ func (x *NotifyBlockAddedResponseMessage) String() string { func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] + mi := &file_messages_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3676,7 +3731,7 @@ func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} + return file_messages_proto_rawDescGZIP(), []int{46} } func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { @@ -3697,7 +3752,7 @@ type BlockAddedNotificationMessage struct { func (x *BlockAddedNotificationMessage) Reset() { *x = BlockAddedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3710,7 +3765,7 @@ func (x *BlockAddedNotificationMessage) String() string { func (*BlockAddedNotificationMessage) ProtoMessage() {} func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] + mi := &file_messages_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3723,7 +3778,7 @@ func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} + return file_messages_proto_rawDescGZIP(), []int{47} } func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { @@ -3742,7 +3797,7 @@ type GetPeerAddressesRequestMessage struct { func (x *GetPeerAddressesRequestMessage) Reset() { *x = GetPeerAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3755,7 +3810,7 @@ func (x *GetPeerAddressesRequestMessage) String() string { func (*GetPeerAddressesRequestMessage) ProtoMessage() {} func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] + mi := &file_messages_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3768,7 +3823,7 @@ func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} + return file_messages_proto_rawDescGZIP(), []int{48} } type GetPeerAddressesResponseMessage struct { @@ -3784,7 +3839,7 @@ type GetPeerAddressesResponseMessage struct { func (x *GetPeerAddressesResponseMessage) Reset() { *x = GetPeerAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3797,7 +3852,7 @@ func (x *GetPeerAddressesResponseMessage) String() string { func (*GetPeerAddressesResponseMessage) ProtoMessage() {} func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] + mi := &file_messages_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3810,7 +3865,7 @@ func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} + return file_messages_proto_rawDescGZIP(), []int{49} } func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { @@ -3845,7 +3900,7 @@ type GetPeerAddressesKnownAddressMessage struct { func (x *GetPeerAddressesKnownAddressMessage) Reset() { *x = GetPeerAddressesKnownAddressMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3858,7 +3913,7 @@ func (x *GetPeerAddressesKnownAddressMessage) String() string { func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] + mi := &file_messages_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3871,7 +3926,7 @@ func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} + return file_messages_proto_rawDescGZIP(), []int{50} } func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { @@ -3890,7 +3945,7 @@ type GetSelectedTipHashRequestMessage struct { func (x *GetSelectedTipHashRequestMessage) Reset() { *x = GetSelectedTipHashRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3903,7 +3958,7 @@ func (x *GetSelectedTipHashRequestMessage) String() string { func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] + mi := &file_messages_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3916,7 +3971,7 @@ func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} + return file_messages_proto_rawDescGZIP(), []int{51} } type GetSelectedTipHashResponseMessage struct { @@ -3931,7 +3986,7 @@ type GetSelectedTipHashResponseMessage struct { func (x *GetSelectedTipHashResponseMessage) Reset() { *x = GetSelectedTipHashResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3944,7 +3999,7 @@ func (x *GetSelectedTipHashResponseMessage) String() string { func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] + mi := &file_messages_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3957,7 +4012,7 @@ func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} + return file_messages_proto_rawDescGZIP(), []int{52} } func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { @@ -3987,7 +4042,7 @@ type MempoolEntry struct { func (x *MempoolEntry) Reset() { *x = MempoolEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4000,7 +4055,7 @@ func (x *MempoolEntry) String() string { func (*MempoolEntry) ProtoMessage() {} func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] + mi := &file_messages_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4013,7 +4068,7 @@ func (x *MempoolEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} + return file_messages_proto_rawDescGZIP(), []int{53} } func (x *MempoolEntry) GetFee() uint64 { @@ -4041,7 +4096,7 @@ type GetMempoolEntryRequestMessage struct { func (x *GetMempoolEntryRequestMessage) Reset() { *x = GetMempoolEntryRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4054,7 +4109,7 @@ func (x *GetMempoolEntryRequestMessage) String() string { func (*GetMempoolEntryRequestMessage) ProtoMessage() {} func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] + mi := &file_messages_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4067,7 +4122,7 @@ func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} + return file_messages_proto_rawDescGZIP(), []int{54} } func (x *GetMempoolEntryRequestMessage) GetTxId() string { @@ -4089,7 +4144,7 @@ type GetMempoolEntryResponseMessage struct { func (x *GetMempoolEntryResponseMessage) Reset() { *x = GetMempoolEntryResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4102,7 +4157,7 @@ func (x *GetMempoolEntryResponseMessage) String() string { func (*GetMempoolEntryResponseMessage) ProtoMessage() {} func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] + mi := &file_messages_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4115,7 +4170,7 @@ func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} + return file_messages_proto_rawDescGZIP(), []int{55} } func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { @@ -4141,7 +4196,7 @@ type GetMempoolEntriesRequestMessage struct { func (x *GetMempoolEntriesRequestMessage) Reset() { *x = GetMempoolEntriesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4154,7 +4209,7 @@ func (x *GetMempoolEntriesRequestMessage) String() string { func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] + mi := &file_messages_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4167,7 +4222,7 @@ func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} + return file_messages_proto_rawDescGZIP(), []int{56} } type GetMempoolEntriesResponseMessage struct { @@ -4182,7 +4237,7 @@ type GetMempoolEntriesResponseMessage struct { func (x *GetMempoolEntriesResponseMessage) Reset() { *x = GetMempoolEntriesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4195,7 +4250,7 @@ func (x *GetMempoolEntriesResponseMessage) String() string { func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] + mi := &file_messages_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4208,7 +4263,7 @@ func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} + return file_messages_proto_rawDescGZIP(), []int{57} } func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { @@ -4234,7 +4289,7 @@ type GetConnectedPeerInfoRequestMessage struct { func (x *GetConnectedPeerInfoRequestMessage) Reset() { *x = GetConnectedPeerInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4247,7 +4302,7 @@ func (x *GetConnectedPeerInfoRequestMessage) String() string { func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] + mi := &file_messages_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4260,7 +4315,7 @@ func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} + return file_messages_proto_rawDescGZIP(), []int{58} } type GetConnectedPeerInfoResponseMessage struct { @@ -4275,7 +4330,7 @@ type GetConnectedPeerInfoResponseMessage struct { func (x *GetConnectedPeerInfoResponseMessage) Reset() { *x = GetConnectedPeerInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4288,7 +4343,7 @@ func (x *GetConnectedPeerInfoResponseMessage) String() string { func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] + mi := &file_messages_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4301,7 +4356,7 @@ func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} + return file_messages_proto_rawDescGZIP(), []int{59} } func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { @@ -4336,7 +4391,7 @@ type GetConnectedPeerInfoMessage struct { func (x *GetConnectedPeerInfoMessage) Reset() { *x = GetConnectedPeerInfoMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4349,7 +4404,7 @@ func (x *GetConnectedPeerInfoMessage) String() string { func (*GetConnectedPeerInfoMessage) ProtoMessage() {} func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] + mi := &file_messages_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4362,7 +4417,7 @@ func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} + return file_messages_proto_rawDescGZIP(), []int{60} } func (x *GetConnectedPeerInfoMessage) GetId() string { @@ -4433,7 +4488,7 @@ type AddPeerRequestMessage struct { func (x *AddPeerRequestMessage) Reset() { *x = AddPeerRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4446,7 +4501,7 @@ func (x *AddPeerRequestMessage) String() string { func (*AddPeerRequestMessage) ProtoMessage() {} func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] + mi := &file_messages_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4459,7 +4514,7 @@ func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} + return file_messages_proto_rawDescGZIP(), []int{61} } func (x *AddPeerRequestMessage) GetAddress() string { @@ -4487,7 +4542,7 @@ type AddPeerResponseMessage struct { func (x *AddPeerResponseMessage) Reset() { *x = AddPeerResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4500,7 +4555,7 @@ func (x *AddPeerResponseMessage) String() string { func (*AddPeerResponseMessage) ProtoMessage() {} func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] + mi := &file_messages_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4513,7 +4568,7 @@ func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} + return file_messages_proto_rawDescGZIP(), []int{62} } func (x *AddPeerResponseMessage) GetError() *RPCError { @@ -4534,7 +4589,7 @@ type SubmitTransactionRequestMessage struct { func (x *SubmitTransactionRequestMessage) Reset() { *x = SubmitTransactionRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4547,7 +4602,7 @@ func (x *SubmitTransactionRequestMessage) String() string { func (*SubmitTransactionRequestMessage) ProtoMessage() {} func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] + mi := &file_messages_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4560,7 +4615,7 @@ func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} + return file_messages_proto_rawDescGZIP(), []int{63} } func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { @@ -4582,7 +4637,7 @@ type SubmitTransactionResponseMessage struct { func (x *SubmitTransactionResponseMessage) Reset() { *x = SubmitTransactionResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4595,7 +4650,7 @@ func (x *SubmitTransactionResponseMessage) String() string { func (*SubmitTransactionResponseMessage) ProtoMessage() {} func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] + mi := &file_messages_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4608,7 +4663,7 @@ func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} + return file_messages_proto_rawDescGZIP(), []int{64} } func (x *SubmitTransactionResponseMessage) GetTransactionId() string { @@ -4634,7 +4689,7 @@ type NotifyVirtualSelectedParentChainChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4647,7 +4702,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] + mi := &file_messages_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4660,7 +4715,7 @@ func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() p // Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} + return file_messages_proto_rawDescGZIP(), []int{65} } type NotifyVirtualSelectedParentChainChangedResponseMessage struct { @@ -4674,7 +4729,7 @@ type NotifyVirtualSelectedParentChainChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4687,7 +4742,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] + mi := &file_messages_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4700,7 +4755,7 @@ func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() // Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} + return file_messages_proto_rawDescGZIP(), []int{66} } func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { @@ -4722,7 +4777,7 @@ type VirtualSelectedParentChainChangedNotificationMessage struct { func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { *x = VirtualSelectedParentChainChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4735,7 +4790,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] + mi := &file_messages_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4748,7 +4803,7 @@ func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() pr // Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} + return file_messages_proto_rawDescGZIP(), []int{67} } func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { @@ -4777,7 +4832,7 @@ type ChainBlock struct { func (x *ChainBlock) Reset() { *x = ChainBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4790,7 +4845,7 @@ func (x *ChainBlock) String() string { func (*ChainBlock) ProtoMessage() {} func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] + mi := &file_messages_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4803,7 +4858,7 @@ func (x *ChainBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} + return file_messages_proto_rawDescGZIP(), []int{68} } func (x *ChainBlock) GetHash() string { @@ -4832,7 +4887,7 @@ type AcceptedBlock struct { func (x *AcceptedBlock) Reset() { *x = AcceptedBlock{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4845,7 +4900,7 @@ func (x *AcceptedBlock) String() string { func (*AcceptedBlock) ProtoMessage() {} func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] + mi := &file_messages_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4858,7 +4913,7 @@ func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} + return file_messages_proto_rawDescGZIP(), []int{69} } func (x *AcceptedBlock) GetHash() string { @@ -4888,7 +4943,7 @@ type GetBlockRequestMessage struct { func (x *GetBlockRequestMessage) Reset() { *x = GetBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4901,7 +4956,7 @@ func (x *GetBlockRequestMessage) String() string { func (*GetBlockRequestMessage) ProtoMessage() {} func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] + mi := &file_messages_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4914,7 +4969,7 @@ func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} + return file_messages_proto_rawDescGZIP(), []int{70} } func (x *GetBlockRequestMessage) GetHash() string { @@ -4951,7 +5006,7 @@ type GetBlockResponseMessage struct { func (x *GetBlockResponseMessage) Reset() { *x = GetBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4964,7 +5019,7 @@ func (x *GetBlockResponseMessage) String() string { func (*GetBlockResponseMessage) ProtoMessage() {} func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] + mi := &file_messages_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4977,7 +5032,7 @@ func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} + return file_messages_proto_rawDescGZIP(), []int{71} } func (x *GetBlockResponseMessage) GetBlockHash() string { @@ -5007,7 +5062,7 @@ type BlockVerboseData struct { unknownFields protoimpl.UnknownFields Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - Version int32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` VersionHex string `protobuf:"bytes,3,opt,name=versionHex,proto3" json:"versionHex,omitempty"` HashMerkleRoot string `protobuf:"bytes,4,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` AcceptedIDMerkleRoot string `protobuf:"bytes,5,opt,name=acceptedIDMerkleRoot,proto3" json:"acceptedIDMerkleRoot,omitempty"` @@ -5027,7 +5082,7 @@ type BlockVerboseData struct { func (x *BlockVerboseData) Reset() { *x = BlockVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5040,7 +5095,7 @@ func (x *BlockVerboseData) String() string { func (*BlockVerboseData) ProtoMessage() {} func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] + mi := &file_messages_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5053,7 +5108,7 @@ func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} + return file_messages_proto_rawDescGZIP(), []int{72} } func (x *BlockVerboseData) GetHash() string { @@ -5063,7 +5118,7 @@ func (x *BlockVerboseData) GetHash() string { return "" } -func (x *BlockVerboseData) GetVersion() int32 { +func (x *BlockVerboseData) GetVersion() uint32 { if x != nil { return x.Version } @@ -5176,7 +5231,7 @@ type TransactionVerboseData struct { TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` - Version int32 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` LockTime uint64 `protobuf:"varint,5,opt,name=lockTime,proto3" json:"lockTime,omitempty"` SubnetworkId string `protobuf:"bytes,6,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` Gas uint64 `protobuf:"varint,7,opt,name=gas,proto3" json:"gas,omitempty"` @@ -5192,7 +5247,7 @@ type TransactionVerboseData struct { func (x *TransactionVerboseData) Reset() { *x = TransactionVerboseData{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5205,7 +5260,7 @@ func (x *TransactionVerboseData) String() string { func (*TransactionVerboseData) ProtoMessage() {} func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] + mi := &file_messages_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5218,7 +5273,7 @@ func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} + return file_messages_proto_rawDescGZIP(), []int{73} } func (x *TransactionVerboseData) GetTxId() string { @@ -5242,7 +5297,7 @@ func (x *TransactionVerboseData) GetSize() uint64 { return 0 } -func (x *TransactionVerboseData) GetVersion() int32 { +func (x *TransactionVerboseData) GetVersion() uint32 { if x != nil { return x.Version } @@ -5333,7 +5388,7 @@ type TransactionVerboseInput struct { func (x *TransactionVerboseInput) Reset() { *x = TransactionVerboseInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5346,7 +5401,7 @@ func (x *TransactionVerboseInput) String() string { func (*TransactionVerboseInput) ProtoMessage() {} func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] + mi := &file_messages_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5359,7 +5414,7 @@ func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} + return file_messages_proto_rawDescGZIP(), []int{74} } func (x *TransactionVerboseInput) GetTxId() string { @@ -5402,7 +5457,7 @@ type ScriptSig struct { func (x *ScriptSig) Reset() { *x = ScriptSig{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5415,7 +5470,7 @@ func (x *ScriptSig) String() string { func (*ScriptSig) ProtoMessage() {} func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] + mi := &file_messages_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5428,7 +5483,7 @@ func (x *ScriptSig) ProtoReflect() protoreflect.Message { // Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} + return file_messages_proto_rawDescGZIP(), []int{75} } func (x *ScriptSig) GetAsm() string { @@ -5450,15 +5505,15 @@ type TransactionVerboseOutput struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` - ScriptPubKey *ScriptPubKeyResult `protobuf:"bytes,3,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + ScriptPublicKey *ScriptPublicKeyResult `protobuf:"bytes,3,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` } func (x *TransactionVerboseOutput) Reset() { *x = TransactionVerboseOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5471,7 +5526,7 @@ func (x *TransactionVerboseOutput) String() string { func (*TransactionVerboseOutput) ProtoMessage() {} func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] + mi := &file_messages_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5484,7 +5539,7 @@ func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} + return file_messages_proto_rawDescGZIP(), []int{76} } func (x *TransactionVerboseOutput) GetValue() uint64 { @@ -5501,14 +5556,14 @@ func (x *TransactionVerboseOutput) GetIndex() uint32 { return 0 } -func (x *TransactionVerboseOutput) GetScriptPubKey() *ScriptPubKeyResult { +func (x *TransactionVerboseOutput) GetScriptPublicKey() *ScriptPublicKeyResult { if x != nil { - return x.ScriptPubKey + return x.ScriptPublicKey } return nil } -type ScriptPubKeyResult struct { +type ScriptPublicKeyResult struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -5519,23 +5574,23 @@ type ScriptPubKeyResult struct { Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` } -func (x *ScriptPubKeyResult) Reset() { - *x = ScriptPubKeyResult{} +func (x *ScriptPublicKeyResult) Reset() { + *x = ScriptPublicKeyResult{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] + mi := &file_messages_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *ScriptPubKeyResult) String() string { +func (x *ScriptPublicKeyResult) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ScriptPubKeyResult) ProtoMessage() {} +func (*ScriptPublicKeyResult) ProtoMessage() {} -func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] +func (x *ScriptPublicKeyResult) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5546,33 +5601,33 @@ func (x *ScriptPubKeyResult) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ScriptPubKeyResult.ProtoReflect.Descriptor instead. -func (*ScriptPubKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} +// Deprecated: Use ScriptPublicKeyResult.ProtoReflect.Descriptor instead. +func (*ScriptPublicKeyResult) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{77} } -func (x *ScriptPubKeyResult) GetAsm() string { +func (x *ScriptPublicKeyResult) GetAsm() string { if x != nil { return x.Asm } return "" } -func (x *ScriptPubKeyResult) GetHex() string { +func (x *ScriptPublicKeyResult) GetHex() string { if x != nil { return x.Hex } return "" } -func (x *ScriptPubKeyResult) GetType() string { +func (x *ScriptPublicKeyResult) GetType() string { if x != nil { return x.Type } return "" } -func (x *ScriptPubKeyResult) GetAddress() string { +func (x *ScriptPublicKeyResult) GetAddress() string { if x != nil { return x.Address } @@ -5590,7 +5645,7 @@ type GetSubnetworkRequestMessage struct { func (x *GetSubnetworkRequestMessage) Reset() { *x = GetSubnetworkRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5603,7 +5658,7 @@ func (x *GetSubnetworkRequestMessage) String() string { func (*GetSubnetworkRequestMessage) ProtoMessage() {} func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] + mi := &file_messages_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5616,7 +5671,7 @@ func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} + return file_messages_proto_rawDescGZIP(), []int{78} } func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { @@ -5638,7 +5693,7 @@ type GetSubnetworkResponseMessage struct { func (x *GetSubnetworkResponseMessage) Reset() { *x = GetSubnetworkResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5651,7 +5706,7 @@ func (x *GetSubnetworkResponseMessage) String() string { func (*GetSubnetworkResponseMessage) ProtoMessage() {} func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] + mi := &file_messages_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5664,7 +5719,7 @@ func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} + return file_messages_proto_rawDescGZIP(), []int{79} } func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { @@ -5692,7 +5747,7 @@ type GetVirtualSelectedParentChainFromBlockRequestMessage struct { func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5705,7 +5760,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] + mi := &file_messages_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5718,7 +5773,7 @@ func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() pr // Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} + return file_messages_proto_rawDescGZIP(), []int{80} } func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { @@ -5741,7 +5796,7 @@ type GetVirtualSelectedParentChainFromBlockResponseMessage struct { func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5754,7 +5809,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] + mi := &file_messages_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5767,7 +5822,7 @@ func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() p // Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} + return file_messages_proto_rawDescGZIP(), []int{81} } func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { @@ -5805,7 +5860,7 @@ type GetBlocksRequestMessage struct { func (x *GetBlocksRequestMessage) Reset() { *x = GetBlocksRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5818,7 +5873,7 @@ func (x *GetBlocksRequestMessage) String() string { func (*GetBlocksRequestMessage) ProtoMessage() {} func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] + mi := &file_messages_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5831,7 +5886,7 @@ func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} + return file_messages_proto_rawDescGZIP(), []int{82} } func (x *GetBlocksRequestMessage) GetLowHash() string { @@ -5876,7 +5931,7 @@ type GetBlocksResponseMessage struct { func (x *GetBlocksResponseMessage) Reset() { *x = GetBlocksResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5889,7 +5944,7 @@ func (x *GetBlocksResponseMessage) String() string { func (*GetBlocksResponseMessage) ProtoMessage() {} func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] + mi := &file_messages_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5902,7 +5957,7 @@ func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} + return file_messages_proto_rawDescGZIP(), []int{83} } func (x *GetBlocksResponseMessage) GetBlockHashes() []string { @@ -5942,7 +5997,7 @@ type GetBlockCountRequestMessage struct { func (x *GetBlockCountRequestMessage) Reset() { *x = GetBlockCountRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5955,7 +6010,7 @@ func (x *GetBlockCountRequestMessage) String() string { func (*GetBlockCountRequestMessage) ProtoMessage() {} func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] + mi := &file_messages_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5968,7 +6023,7 @@ func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} + return file_messages_proto_rawDescGZIP(), []int{84} } type GetBlockCountResponseMessage struct { @@ -5984,7 +6039,7 @@ type GetBlockCountResponseMessage struct { func (x *GetBlockCountResponseMessage) Reset() { *x = GetBlockCountResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5997,7 +6052,7 @@ func (x *GetBlockCountResponseMessage) String() string { func (*GetBlockCountResponseMessage) ProtoMessage() {} func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] + mi := &file_messages_proto_msgTypes[85] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6010,7 +6065,7 @@ func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} + return file_messages_proto_rawDescGZIP(), []int{85} } func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { @@ -6043,7 +6098,7 @@ type GetBlockDagInfoRequestMessage struct { func (x *GetBlockDagInfoRequestMessage) Reset() { *x = GetBlockDagInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6056,7 +6111,7 @@ func (x *GetBlockDagInfoRequestMessage) String() string { func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] + mi := &file_messages_proto_msgTypes[86] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6069,7 +6124,7 @@ func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} + return file_messages_proto_rawDescGZIP(), []int{86} } type GetBlockDagInfoResponseMessage struct { @@ -6090,7 +6145,7 @@ type GetBlockDagInfoResponseMessage struct { func (x *GetBlockDagInfoResponseMessage) Reset() { *x = GetBlockDagInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6103,7 +6158,7 @@ func (x *GetBlockDagInfoResponseMessage) String() string { func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] + mi := &file_messages_proto_msgTypes[87] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6116,7 +6171,7 @@ func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} + return file_messages_proto_rawDescGZIP(), []int{87} } func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { @@ -6186,7 +6241,7 @@ type ResolveFinalityConflictRequestMessage struct { func (x *ResolveFinalityConflictRequestMessage) Reset() { *x = ResolveFinalityConflictRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6199,7 +6254,7 @@ func (x *ResolveFinalityConflictRequestMessage) String() string { func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] + mi := &file_messages_proto_msgTypes[88] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6212,7 +6267,7 @@ func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} + return file_messages_proto_rawDescGZIP(), []int{88} } func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { @@ -6233,7 +6288,7 @@ type ResolveFinalityConflictResponseMessage struct { func (x *ResolveFinalityConflictResponseMessage) Reset() { *x = ResolveFinalityConflictResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6246,7 +6301,7 @@ func (x *ResolveFinalityConflictResponseMessage) String() string { func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] + mi := &file_messages_proto_msgTypes[89] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6259,7 +6314,7 @@ func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} + return file_messages_proto_rawDescGZIP(), []int{89} } func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { @@ -6278,7 +6333,7 @@ type NotifyFinalityConflictsRequestMessage struct { func (x *NotifyFinalityConflictsRequestMessage) Reset() { *x = NotifyFinalityConflictsRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6291,7 +6346,7 @@ func (x *NotifyFinalityConflictsRequestMessage) String() string { func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] + mi := &file_messages_proto_msgTypes[90] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6304,7 +6359,7 @@ func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Mess // Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} + return file_messages_proto_rawDescGZIP(), []int{90} } type NotifyFinalityConflictsResponseMessage struct { @@ -6318,7 +6373,7 @@ type NotifyFinalityConflictsResponseMessage struct { func (x *NotifyFinalityConflictsResponseMessage) Reset() { *x = NotifyFinalityConflictsResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6331,7 +6386,7 @@ func (x *NotifyFinalityConflictsResponseMessage) String() string { func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[90] + mi := &file_messages_proto_msgTypes[91] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6344,7 +6399,7 @@ func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Mes // Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{90} + return file_messages_proto_rawDescGZIP(), []int{91} } func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { @@ -6365,7 +6420,7 @@ type FinalityConflictNotificationMessage struct { func (x *FinalityConflictNotificationMessage) Reset() { *x = FinalityConflictNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6378,7 +6433,7 @@ func (x *FinalityConflictNotificationMessage) String() string { func (*FinalityConflictNotificationMessage) ProtoMessage() {} func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[91] + mi := &file_messages_proto_msgTypes[92] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6391,7 +6446,7 @@ func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Messag // Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{91} + return file_messages_proto_rawDescGZIP(), []int{92} } func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { @@ -6412,7 +6467,7 @@ type FinalityConflictResolvedNotificationMessage struct { func (x *FinalityConflictResolvedNotificationMessage) Reset() { *x = FinalityConflictResolvedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6425,7 +6480,7 @@ func (x *FinalityConflictResolvedNotificationMessage) String() string { func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[92] + mi := &file_messages_proto_msgTypes[93] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6438,7 +6493,7 @@ func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflec // Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{92} + return file_messages_proto_rawDescGZIP(), []int{93} } func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { @@ -6457,7 +6512,7 @@ type ShutDownRequestMessage struct { func (x *ShutDownRequestMessage) Reset() { *x = ShutDownRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6470,7 +6525,7 @@ func (x *ShutDownRequestMessage) String() string { func (*ShutDownRequestMessage) ProtoMessage() {} func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[93] + mi := &file_messages_proto_msgTypes[94] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6483,7 +6538,7 @@ func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{93} + return file_messages_proto_rawDescGZIP(), []int{94} } type ShutDownResponseMessage struct { @@ -6497,7 +6552,7 @@ type ShutDownResponseMessage struct { func (x *ShutDownResponseMessage) Reset() { *x = ShutDownResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6510,7 +6565,7 @@ func (x *ShutDownResponseMessage) String() string { func (*ShutDownResponseMessage) ProtoMessage() {} func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[94] + mi := &file_messages_proto_msgTypes[95] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6523,7 +6578,7 @@ func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{94} + return file_messages_proto_rawDescGZIP(), []int{95} } func (x *ShutDownResponseMessage) GetError() *RPCError { @@ -6546,7 +6601,7 @@ type GetHeadersRequestMessage struct { func (x *GetHeadersRequestMessage) Reset() { *x = GetHeadersRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6559,7 +6614,7 @@ func (x *GetHeadersRequestMessage) String() string { func (*GetHeadersRequestMessage) ProtoMessage() {} func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[95] + mi := &file_messages_proto_msgTypes[96] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6572,7 +6627,7 @@ func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{95} + return file_messages_proto_rawDescGZIP(), []int{96} } func (x *GetHeadersRequestMessage) GetStartHash() string { @@ -6608,7 +6663,7 @@ type GetHeadersResponseMessage struct { func (x *GetHeadersResponseMessage) Reset() { *x = GetHeadersResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6621,7 +6676,7 @@ func (x *GetHeadersResponseMessage) String() string { func (*GetHeadersResponseMessage) ProtoMessage() {} func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[96] + mi := &file_messages_proto_msgTypes[97] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6634,7 +6689,7 @@ func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{96} + return file_messages_proto_rawDescGZIP(), []int{97} } func (x *GetHeadersResponseMessage) GetHeaders() []string { @@ -6662,7 +6717,7 @@ type NotifyUtxosChangedRequestMessage struct { func (x *NotifyUtxosChangedRequestMessage) Reset() { *x = NotifyUtxosChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6675,7 +6730,7 @@ func (x *NotifyUtxosChangedRequestMessage) String() string { func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[97] + mi := &file_messages_proto_msgTypes[98] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6688,7 +6743,7 @@ func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{97} + return file_messages_proto_rawDescGZIP(), []int{98} } func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { @@ -6709,7 +6764,7 @@ type NotifyUtxosChangedResponseMessage struct { func (x *NotifyUtxosChangedResponseMessage) Reset() { *x = NotifyUtxosChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6722,7 +6777,7 @@ func (x *NotifyUtxosChangedResponseMessage) String() string { func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[98] + mi := &file_messages_proto_msgTypes[99] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6735,7 +6790,7 @@ func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{98} + return file_messages_proto_rawDescGZIP(), []int{99} } func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { @@ -6757,7 +6812,7 @@ type UtxosChangedNotificationMessage struct { func (x *UtxosChangedNotificationMessage) Reset() { *x = UtxosChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6770,7 +6825,7 @@ func (x *UtxosChangedNotificationMessage) String() string { func (*UtxosChangedNotificationMessage) ProtoMessage() {} func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[99] + mi := &file_messages_proto_msgTypes[100] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6783,7 +6838,7 @@ func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{99} + return file_messages_proto_rawDescGZIP(), []int{100} } func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { @@ -6813,7 +6868,7 @@ type UtxosByAddressesEntry struct { func (x *UtxosByAddressesEntry) Reset() { *x = UtxosByAddressesEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6826,7 +6881,7 @@ func (x *UtxosByAddressesEntry) String() string { func (*UtxosByAddressesEntry) ProtoMessage() {} func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[100] + mi := &file_messages_proto_msgTypes[101] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6839,7 +6894,7 @@ func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{100} + return file_messages_proto_rawDescGZIP(), []int{101} } func (x *UtxosByAddressesEntry) GetAddress() string { @@ -6868,7 +6923,7 @@ type RpcTransaction struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` Inputs []*RpcTransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` Outputs []*RpcTransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` @@ -6881,7 +6936,7 @@ type RpcTransaction struct { func (x *RpcTransaction) Reset() { *x = RpcTransaction{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6894,7 +6949,7 @@ func (x *RpcTransaction) String() string { func (*RpcTransaction) ProtoMessage() {} func (x *RpcTransaction) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[101] + mi := &file_messages_proto_msgTypes[102] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6907,10 +6962,10 @@ func (x *RpcTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. func (*RpcTransaction) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{101} + return file_messages_proto_rawDescGZIP(), []int{102} } -func (x *RpcTransaction) GetVersion() int32 { +func (x *RpcTransaction) GetVersion() uint32 { if x != nil { return x.Version } @@ -6979,7 +7034,7 @@ type RpcTransactionInput struct { func (x *RpcTransactionInput) Reset() { *x = RpcTransactionInput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6992,7 +7047,7 @@ func (x *RpcTransactionInput) String() string { func (*RpcTransactionInput) ProtoMessage() {} func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[102] + mi := &file_messages_proto_msgTypes[103] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7005,7 +7060,7 @@ func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. func (*RpcTransactionInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{102} + return file_messages_proto_rawDescGZIP(), []int{103} } func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { @@ -7029,19 +7084,74 @@ func (x *RpcTransactionInput) GetSequence() uint64 { return 0 } +type RpcScriptPublicKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + ScriptPublicKey string `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` +} + +func (x *RpcScriptPublicKey) Reset() { + *x = RpcScriptPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcScriptPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcScriptPublicKey) ProtoMessage() {} + +func (x *RpcScriptPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[104] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcScriptPublicKey.ProtoReflect.Descriptor instead. +func (*RpcScriptPublicKey) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{104} +} + +func (x *RpcScriptPublicKey) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *RpcScriptPublicKey) GetScriptPublicKey() string { + if x != nil { + return x.ScriptPublicKey + } + return "" +} + type RpcTransactionOutput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` - ScriptPubKey string `protobuf:"bytes,2,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *RpcScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` } func (x *RpcTransactionOutput) Reset() { *x = RpcTransactionOutput{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7054,7 +7164,7 @@ func (x *RpcTransactionOutput) String() string { func (*RpcTransactionOutput) ProtoMessage() {} func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[103] + mi := &file_messages_proto_msgTypes[105] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7067,7 +7177,7 @@ func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{103} + return file_messages_proto_rawDescGZIP(), []int{105} } func (x *RpcTransactionOutput) GetAmount() uint64 { @@ -7077,11 +7187,11 @@ func (x *RpcTransactionOutput) GetAmount() uint64 { return 0 } -func (x *RpcTransactionOutput) GetScriptPubKey() string { +func (x *RpcTransactionOutput) GetScriptPublicKey() *RpcScriptPublicKey { if x != nil { - return x.ScriptPubKey + return x.ScriptPublicKey } - return "" + return nil } type RpcOutpoint struct { @@ -7096,7 +7206,7 @@ type RpcOutpoint struct { func (x *RpcOutpoint) Reset() { *x = RpcOutpoint{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7109,7 +7219,7 @@ func (x *RpcOutpoint) String() string { func (*RpcOutpoint) ProtoMessage() {} func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[104] + mi := &file_messages_proto_msgTypes[106] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7122,7 +7232,7 @@ func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. func (*RpcOutpoint) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{104} + return file_messages_proto_rawDescGZIP(), []int{106} } func (x *RpcOutpoint) GetTransactionId() string { @@ -7144,16 +7254,16 @@ type RpcUtxoEntry struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` - ScriptPubKey string `protobuf:"bytes,2,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` - BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` - IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *RpcScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` + BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` + IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` } func (x *RpcUtxoEntry) Reset() { *x = RpcUtxoEntry{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7166,7 +7276,7 @@ func (x *RpcUtxoEntry) String() string { func (*RpcUtxoEntry) ProtoMessage() {} func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[105] + mi := &file_messages_proto_msgTypes[107] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7179,7 +7289,7 @@ func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{105} + return file_messages_proto_rawDescGZIP(), []int{107} } func (x *RpcUtxoEntry) GetAmount() uint64 { @@ -7189,11 +7299,11 @@ func (x *RpcUtxoEntry) GetAmount() uint64 { return 0 } -func (x *RpcUtxoEntry) GetScriptPubKey() string { +func (x *RpcUtxoEntry) GetScriptPublicKey() *RpcScriptPublicKey { if x != nil { - return x.ScriptPubKey + return x.ScriptPublicKey } - return "" + return nil } func (x *RpcUtxoEntry) GetBlockBlueScore() uint64 { @@ -7221,7 +7331,7 @@ type GetUtxosByAddressesRequestMessage struct { func (x *GetUtxosByAddressesRequestMessage) Reset() { *x = GetUtxosByAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7234,7 +7344,7 @@ func (x *GetUtxosByAddressesRequestMessage) String() string { func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[106] + mi := &file_messages_proto_msgTypes[108] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7247,7 +7357,7 @@ func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{106} + return file_messages_proto_rawDescGZIP(), []int{108} } func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { @@ -7269,7 +7379,7 @@ type GetUtxosByAddressesResponseMessage struct { func (x *GetUtxosByAddressesResponseMessage) Reset() { *x = GetUtxosByAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7282,7 +7392,7 @@ func (x *GetUtxosByAddressesResponseMessage) String() string { func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[107] + mi := &file_messages_proto_msgTypes[109] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7295,7 +7405,7 @@ func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{107} + return file_messages_proto_rawDescGZIP(), []int{109} } func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { @@ -7321,7 +7431,7 @@ type GetVirtualSelectedParentBlueScoreRequestMessage struct { func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[108] + mi := &file_messages_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7334,7 +7444,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[108] + mi := &file_messages_proto_msgTypes[110] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7347,7 +7457,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protore // Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{108} + return file_messages_proto_rawDescGZIP(), []int{110} } type GetVirtualSelectedParentBlueScoreResponseMessage struct { @@ -7362,7 +7472,7 @@ type GetVirtualSelectedParentBlueScoreResponseMessage struct { func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[109] + mi := &file_messages_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7375,7 +7485,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[109] + mi := &file_messages_proto_msgTypes[111] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7388,7 +7498,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protor // Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{109} + return file_messages_proto_rawDescGZIP(), []int{111} } func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { @@ -7414,7 +7524,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[110] + mi := &file_messages_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7427,7 +7537,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() str func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[110] + mi := &file_messages_proto_msgTypes[112] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7440,7 +7550,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{110} + return file_messages_proto_rawDescGZIP(), []int{112} } type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { @@ -7454,7 +7564,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[111] + mi := &file_messages_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7467,7 +7577,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() st func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[111] + mi := &file_messages_proto_msgTypes[113] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7480,7 +7590,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflec // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{111} + return file_messages_proto_rawDescGZIP(), []int{113} } func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { @@ -7501,7 +7611,7 @@ type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[112] + mi := &file_messages_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7514,7 +7624,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() stri func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[112] + mi := &file_messages_proto_msgTypes[114] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7527,7 +7637,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect( // Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{112} + return file_messages_proto_rawDescGZIP(), []int{114} } func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { @@ -8124,7 +8234,7 @@ var file_messages_proto_rawDesc = []byte{ 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, @@ -8161,753 +8271,770 @@ var file_messages_proto_rawDesc = []byte{ 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x4d, 0x0a, - 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, - 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, - 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, - 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, - 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, - 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, - 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, - 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, - 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x43, 0x0a, + 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x22, 0x6f, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 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, 0x44, 0x0a, + 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, + 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, + 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, + 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, + 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, + 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, + 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, + 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, + 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, + 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, - 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, + 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, + 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, + 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, + 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, + 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, + 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, + 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, - 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, - 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, - 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, - 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, - 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, - 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, - 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, - 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, - 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, - 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, - 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, - 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, - 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, + 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, + 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, + 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, + 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, + 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, + 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, + 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, + 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, + 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, + 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, + 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, + 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, + 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, + 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, - 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, - 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, - 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, - 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, - 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, - 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, - 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, - 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, - 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, - 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, - 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, - 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 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, 0x39, - 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, - 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, - 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 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, 0x24, - 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, - 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, - 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, - 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, - 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, - 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, - 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, - 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, + 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, + 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x58, + 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, + 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, - 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, + 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 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, - 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 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, 0xb3, - 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 0xdb, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, - 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, - 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 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, 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, + 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, + 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x4e, 0x0a, 0x1d, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, + 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, + 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, + 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 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, + 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, + 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, + 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, + 0x72, 0x79, 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, 0x21, + 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, + 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, 0xb5, 0x02, + 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, + 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, + 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, + 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, + 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x22, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, + 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, + 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, + 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, 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, 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, 0xdb, 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, 0x0d, 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, + 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 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, 0x0d, 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, 0x92, 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 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, + 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, - 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, - 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, - 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x49, - 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, - 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x52, 0x70, - 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, - 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, - 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, - 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, + 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, - 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, + 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, + 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, + 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, + 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, + 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, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, + 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, + 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, + 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, + 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, + 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, + 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, + 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, + 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 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, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 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, + 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, + 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 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, 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 ( @@ -8922,7 +9049,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 113) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 115) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage @@ -8933,296 +9060,301 @@ var file_messages_proto_goTypes = []interface{}{ (*TransactionInput)(nil), // 6: protowire.TransactionInput (*Outpoint)(nil), // 7: protowire.Outpoint (*TransactionId)(nil), // 8: protowire.TransactionId - (*TransactionOutput)(nil), // 9: protowire.TransactionOutput - (*BlockMessage)(nil), // 10: protowire.BlockMessage - (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage - (*Hash)(nil), // 12: protowire.Hash - (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage - (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage - (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage - (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage - (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage - (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage - (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage - (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage - (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage - (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage - (*PingMessage)(nil), // 23: protowire.PingMessage - (*PongMessage)(nil), // 24: protowire.PongMessage - (*VerackMessage)(nil), // 25: protowire.VerackMessage - (*VersionMessage)(nil), // 26: protowire.VersionMessage - (*RejectMessage)(nil), // 27: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage - (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage - (*RequestIBDRootHashMessage)(nil), // 32: protowire.RequestIBDRootHashMessage - (*IBDRootHashMessage)(nil), // 33: protowire.IBDRootHashMessage - (*IbdBlockLocatorMessage)(nil), // 34: protowire.IbdBlockLocatorMessage - (*IbdBlockLocatorHighestHashMessage)(nil), // 35: protowire.IbdBlockLocatorHighestHashMessage - (*BlockHeadersMessage)(nil), // 36: protowire.BlockHeadersMessage - (*RPCError)(nil), // 37: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 38: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 39: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 40: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 41: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 42: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 43: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 44: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 45: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 46: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 47: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 48: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 49: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 50: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 51: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 52: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 53: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 54: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 55: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 56: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 57: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 58: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 59: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 60: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 61: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 62: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 63: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 64: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 65: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 66: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*ChainBlock)(nil), // 67: protowire.ChainBlock - (*AcceptedBlock)(nil), // 68: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 69: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 70: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 71: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 72: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 73: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 74: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 75: protowire.TransactionVerboseOutput - (*ScriptPubKeyResult)(nil), // 76: protowire.ScriptPubKeyResult - (*GetSubnetworkRequestMessage)(nil), // 77: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 78: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 79: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 80: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 81: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 82: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 83: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 84: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 85: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 86: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 87: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 88: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 89: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 90: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 91: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 92: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 93: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 94: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 95: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 96: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 97: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 98: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 99: protowire.UtxosChangedNotificationMessage - (*UtxosByAddressesEntry)(nil), // 100: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 101: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 102: protowire.RpcTransactionInput - (*RpcTransactionOutput)(nil), // 103: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 104: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 105: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 106: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 107: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 108: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 109: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 110: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 111: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 112: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*ScriptPublicKey)(nil), // 9: protowire.ScriptPublicKey + (*TransactionOutput)(nil), // 10: protowire.TransactionOutput + (*BlockMessage)(nil), // 11: protowire.BlockMessage + (*BlockHeaderMessage)(nil), // 12: protowire.BlockHeaderMessage + (*Hash)(nil), // 13: protowire.Hash + (*RequestBlockLocatorMessage)(nil), // 14: protowire.RequestBlockLocatorMessage + (*BlockLocatorMessage)(nil), // 15: protowire.BlockLocatorMessage + (*RequestHeadersMessage)(nil), // 16: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 17: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 18: protowire.DoneHeadersMessage + (*RequestRelayBlocksMessage)(nil), // 19: protowire.RequestRelayBlocksMessage + (*RequestTransactionsMessage)(nil), // 20: protowire.RequestTransactionsMessage + (*TransactionNotFoundMessage)(nil), // 21: protowire.TransactionNotFoundMessage + (*InvRelayBlockMessage)(nil), // 22: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 23: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 24: protowire.PingMessage + (*PongMessage)(nil), // 25: protowire.PongMessage + (*VerackMessage)(nil), // 26: protowire.VerackMessage + (*VersionMessage)(nil), // 27: protowire.VersionMessage + (*RejectMessage)(nil), // 28: protowire.RejectMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IBDRootUTXOSetAndBlockMessage)(nil), // 30: protowire.IBDRootUTXOSetAndBlockMessage + (*RequestIBDBlocksMessage)(nil), // 31: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 32: protowire.IBDRootNotFoundMessage + (*RequestIBDRootHashMessage)(nil), // 33: protowire.RequestIBDRootHashMessage + (*IBDRootHashMessage)(nil), // 34: protowire.IBDRootHashMessage + (*IbdBlockLocatorMessage)(nil), // 35: protowire.IbdBlockLocatorMessage + (*IbdBlockLocatorHighestHashMessage)(nil), // 36: protowire.IbdBlockLocatorHighestHashMessage + (*BlockHeadersMessage)(nil), // 37: protowire.BlockHeadersMessage + (*RPCError)(nil), // 38: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 39: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 40: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 41: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 42: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 43: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 44: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 45: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 46: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 47: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 48: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 49: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 50: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 51: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 52: protowire.GetSelectedTipHashResponseMessage + (*MempoolEntry)(nil), // 53: protowire.MempoolEntry + (*GetMempoolEntryRequestMessage)(nil), // 54: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 55: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 56: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 57: protowire.GetMempoolEntriesResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 58: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 59: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 60: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 61: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 62: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 63: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 64: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 65: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 66: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 67: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*ChainBlock)(nil), // 68: protowire.ChainBlock + (*AcceptedBlock)(nil), // 69: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 70: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 71: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 72: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 73: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 74: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 75: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 76: protowire.TransactionVerboseOutput + (*ScriptPublicKeyResult)(nil), // 77: protowire.ScriptPublicKeyResult + (*GetSubnetworkRequestMessage)(nil), // 78: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 79: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 80: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 81: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 82: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 83: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 84: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 85: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 86: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 87: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 88: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 89: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 90: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 91: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 92: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 93: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 94: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 95: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 96: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 97: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 98: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 99: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 100: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 101: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 102: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 103: protowire.RpcTransactionInput + (*RpcScriptPublicKey)(nil), // 104: protowire.RpcScriptPublicKey + (*RpcTransactionOutput)(nil), // 105: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 106: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 107: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 108: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 109: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 110: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 111: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 112: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 113: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 114: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage - 10, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage + 11, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage 5, // 2: protowire.KaspadMessage.transaction:type_name -> protowire.TransactionMessage - 13, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage - 14, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage + 14, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage + 15, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage 1, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage - 15, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage - 16, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage - 17, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage - 18, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage - 19, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage - 10, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage - 21, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage - 22, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage - 23, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage - 24, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage - 25, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage - 26, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage - 20, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage - 27, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 28, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage - 29, // 21: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage - 30, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 31, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 32, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage - 33, // 25: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage - 34, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage - 35, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage - 36, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage - 38, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 39, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 40, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 41, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 42, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 43, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 44, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 45, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 46, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 47, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 48, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 50, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 51, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 53, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 54, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 57, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 58, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 60, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 61, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 62, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 63, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 64, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 65, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 66, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 69, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 70, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 77, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 78, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 79, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 80, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 81, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 82, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 83, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 84, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 85, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 86, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 87, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 88, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 89, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 90, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 91, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 92, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 55, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 56, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 93, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 94, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 95, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 96, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 97, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 98, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 99, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 106, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 107, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 108, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 109, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 110, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 111, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 112, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 16, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage + 17, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage + 18, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage + 19, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage + 20, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage + 11, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage + 22, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage + 23, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage + 24, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage + 25, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage + 26, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage + 27, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage + 21, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage + 28, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage + 29, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage + 30, // 21: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage + 31, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage + 32, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage + 33, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage + 34, // 25: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage + 35, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage + 36, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage + 37, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage + 39, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 40, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 41, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 42, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 43, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 44, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 45, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 46, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 47, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 48, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 49, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 51, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 52, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 54, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 55, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 58, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 59, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 61, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 62, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 63, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 64, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 65, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 66, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 67, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 70, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 71, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 78, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 79, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 80, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 81, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 82, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 83, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 84, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 85, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 86, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 87, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 88, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 89, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 90, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 91, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 92, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 93, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 56, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 57, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 94, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 95, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 96, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 97, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 98, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 99, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 100, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 108, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 109, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 110, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 111, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 112, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 113, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 114, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage 4, // 87: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId 3, // 88: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress 6, // 89: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 9, // 90: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 10, // 90: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput 4, // 91: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 92: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 13, // 92: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash 7, // 93: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint 8, // 94: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId - 11, // 95: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 96: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 12, // 97: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 12, // 98: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 12, // 99: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash - 12, // 100: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 12, // 101: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 12, // 102: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 12, // 103: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 12, // 104: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 12, // 105: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 12, // 106: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 107: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId - 8, // 108: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId - 12, // 109: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 110: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId - 3, // 111: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 4, // 112: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 113: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 114: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 115: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 12, // 116: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash - 12, // 117: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash - 12, // 118: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash - 12, // 119: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash - 11, // 120: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage - 37, // 121: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 10, // 122: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 37, // 123: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 10, // 124: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 37, // 125: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 37, // 126: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 10, // 127: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 49, // 128: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 49, // 129: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 37, // 130: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 37, // 131: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 72, // 132: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 52, // 133: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 37, // 134: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 52, // 135: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 37, // 136: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 59, // 137: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 37, // 138: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 37, // 139: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 101, // 140: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 37, // 141: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 37, // 142: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 67, // 143: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 68, // 144: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 71, // 145: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 37, // 146: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 72, // 147: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 73, // 148: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 75, // 149: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 74, // 150: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 76, // 151: protowire.TransactionVerboseOutput.scriptPubKey:type_name -> protowire.ScriptPubKeyResult - 37, // 152: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 67, // 153: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 37, // 154: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 71, // 155: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 37, // 156: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 37, // 157: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 37, // 158: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 37, // 159: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 37, // 160: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 37, // 161: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 37, // 162: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 37, // 163: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 100, // 164: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 100, // 165: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 104, // 166: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 105, // 167: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 102, // 168: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 103, // 169: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 104, // 170: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 100, // 171: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 37, // 172: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 37, // 173: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 37, // 174: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 0, // 175: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 176: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 177: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 178: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 177, // [177:179] is the sub-list for method output_type - 175, // [175:177] is the sub-list for method input_type - 175, // [175:175] is the sub-list for extension type_name - 175, // [175:175] is the sub-list for extension extendee - 0, // [0:175] is the sub-list for field type_name + 9, // 95: protowire.TransactionOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKey + 12, // 96: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 5, // 97: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 13, // 98: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 13, // 99: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 13, // 100: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash + 13, // 101: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 13, // 102: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 13, // 103: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 13, // 104: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 13, // 105: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 13, // 106: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 13, // 107: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 8, // 108: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 8, // 109: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId + 13, // 110: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 8, // 111: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId + 3, // 112: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 4, // 113: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 13, // 114: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 11, // 115: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 13, // 116: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 13, // 117: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash + 13, // 118: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash + 13, // 119: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash + 13, // 120: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash + 12, // 121: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage + 38, // 122: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 11, // 123: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 38, // 124: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 11, // 125: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 38, // 126: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 38, // 127: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 11, // 128: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 50, // 129: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 50, // 130: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 38, // 131: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 38, // 132: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 73, // 133: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 53, // 134: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 38, // 135: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 53, // 136: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 38, // 137: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 60, // 138: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 38, // 139: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 38, // 140: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 102, // 141: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 38, // 142: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 38, // 143: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 68, // 144: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 69, // 145: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 72, // 146: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 38, // 147: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 73, // 148: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 74, // 149: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 76, // 150: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 75, // 151: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 77, // 152: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult + 38, // 153: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 68, // 154: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 38, // 155: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 72, // 156: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 38, // 157: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 38, // 158: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 38, // 159: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 38, // 160: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 38, // 161: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 38, // 162: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 38, // 163: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 38, // 164: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 101, // 165: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 101, // 166: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 106, // 167: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 107, // 168: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 103, // 169: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 105, // 170: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 106, // 171: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 104, // 172: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 104, // 173: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 101, // 174: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 38, // 175: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 38, // 176: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 38, // 177: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 0, // 178: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 179: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 180: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 181: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 180, // [180:182] is the sub-list for method output_type + 178, // [178:180] is the sub-list for method input_type + 178, // [178:178] is the sub-list for extension type_name + 178, // [178:178] is the sub-list for extension extendee + 0, // [0:178] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -9340,7 +9472,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionOutput); i { + switch v := v.(*ScriptPublicKey); i { case 0: return &v.state case 1: @@ -9352,7 +9484,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockMessage); i { + switch v := v.(*TransactionOutput); i { case 0: return &v.state case 1: @@ -9364,7 +9496,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockHeaderMessage); i { + switch v := v.(*BlockMessage); i { case 0: return &v.state case 1: @@ -9376,7 +9508,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hash); i { + switch v := v.(*BlockHeaderMessage); i { case 0: return &v.state case 1: @@ -9388,7 +9520,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestBlockLocatorMessage); i { + switch v := v.(*Hash); i { case 0: return &v.state case 1: @@ -9400,7 +9532,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockLocatorMessage); i { + switch v := v.(*RequestBlockLocatorMessage); i { case 0: return &v.state case 1: @@ -9412,7 +9544,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestHeadersMessage); i { + switch v := v.(*BlockLocatorMessage); i { case 0: return &v.state case 1: @@ -9424,7 +9556,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestNextHeadersMessage); i { + switch v := v.(*RequestHeadersMessage); i { case 0: return &v.state case 1: @@ -9436,7 +9568,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DoneHeadersMessage); i { + switch v := v.(*RequestNextHeadersMessage); i { case 0: return &v.state case 1: @@ -9448,7 +9580,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestRelayBlocksMessage); i { + switch v := v.(*DoneHeadersMessage); i { case 0: return &v.state case 1: @@ -9460,7 +9592,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestTransactionsMessage); i { + switch v := v.(*RequestRelayBlocksMessage); i { case 0: return &v.state case 1: @@ -9472,7 +9604,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionNotFoundMessage); i { + switch v := v.(*RequestTransactionsMessage); i { case 0: return &v.state case 1: @@ -9484,7 +9616,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InvRelayBlockMessage); i { + switch v := v.(*TransactionNotFoundMessage); i { case 0: return &v.state case 1: @@ -9496,7 +9628,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InvTransactionsMessage); i { + switch v := v.(*InvRelayBlockMessage); i { case 0: return &v.state case 1: @@ -9508,7 +9640,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingMessage); i { + switch v := v.(*InvTransactionsMessage); i { case 0: return &v.state case 1: @@ -9520,7 +9652,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PongMessage); i { + switch v := v.(*PingMessage); i { case 0: return &v.state case 1: @@ -9532,7 +9664,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerackMessage); i { + switch v := v.(*PongMessage); i { case 0: return &v.state case 1: @@ -9544,7 +9676,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionMessage); i { + switch v := v.(*VerackMessage); i { case 0: return &v.state case 1: @@ -9556,7 +9688,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RejectMessage); i { + switch v := v.(*VersionMessage); i { case 0: return &v.state case 1: @@ -9568,7 +9700,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { + switch v := v.(*RejectMessage); i { case 0: return &v.state case 1: @@ -9580,7 +9712,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { + switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { case 0: return &v.state case 1: @@ -9592,7 +9724,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDBlocksMessage); i { + switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { case 0: return &v.state case 1: @@ -9604,7 +9736,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootNotFoundMessage); i { + switch v := v.(*RequestIBDBlocksMessage); i { case 0: return &v.state case 1: @@ -9616,7 +9748,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootHashMessage); i { + switch v := v.(*IBDRootNotFoundMessage); i { case 0: return &v.state case 1: @@ -9628,7 +9760,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootHashMessage); i { + switch v := v.(*RequestIBDRootHashMessage); i { case 0: return &v.state case 1: @@ -9640,7 +9772,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorMessage); i { + switch v := v.(*IBDRootHashMessage); i { case 0: return &v.state case 1: @@ -9652,7 +9784,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorHighestHashMessage); i { + switch v := v.(*IbdBlockLocatorMessage); i { case 0: return &v.state case 1: @@ -9664,7 +9796,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockHeadersMessage); i { + switch v := v.(*IbdBlockLocatorHighestHashMessage); i { case 0: return &v.state case 1: @@ -9676,7 +9808,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCError); i { + switch v := v.(*BlockHeadersMessage); i { case 0: return &v.state case 1: @@ -9688,7 +9820,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkRequestMessage); i { + switch v := v.(*RPCError); i { case 0: return &v.state case 1: @@ -9700,7 +9832,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkResponseMessage); i { + switch v := v.(*GetCurrentNetworkRequestMessage); i { case 0: return &v.state case 1: @@ -9712,7 +9844,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockRequestMessage); i { + switch v := v.(*GetCurrentNetworkResponseMessage); i { case 0: return &v.state case 1: @@ -9724,7 +9856,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockResponseMessage); i { + switch v := v.(*SubmitBlockRequestMessage); i { case 0: return &v.state case 1: @@ -9736,7 +9868,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateRequestMessage); i { + switch v := v.(*SubmitBlockResponseMessage); i { case 0: return &v.state case 1: @@ -9748,7 +9880,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateResponseMessage); i { + switch v := v.(*GetBlockTemplateRequestMessage); i { case 0: return &v.state case 1: @@ -9760,7 +9892,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedRequestMessage); i { + switch v := v.(*GetBlockTemplateResponseMessage); i { case 0: return &v.state case 1: @@ -9772,7 +9904,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedResponseMessage); i { + switch v := v.(*NotifyBlockAddedRequestMessage); i { case 0: return &v.state case 1: @@ -9784,7 +9916,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockAddedNotificationMessage); i { + switch v := v.(*NotifyBlockAddedResponseMessage); i { case 0: return &v.state case 1: @@ -9796,7 +9928,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesRequestMessage); i { + switch v := v.(*BlockAddedNotificationMessage); i { case 0: return &v.state case 1: @@ -9808,7 +9940,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesResponseMessage); i { + switch v := v.(*GetPeerAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -9820,7 +9952,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesKnownAddressMessage); i { + switch v := v.(*GetPeerAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -9832,7 +9964,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashRequestMessage); i { + switch v := v.(*GetPeerAddressesKnownAddressMessage); i { case 0: return &v.state case 1: @@ -9844,7 +9976,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashResponseMessage); i { + switch v := v.(*GetSelectedTipHashRequestMessage); i { case 0: return &v.state case 1: @@ -9856,7 +9988,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MempoolEntry); i { + switch v := v.(*GetSelectedTipHashResponseMessage); i { case 0: return &v.state case 1: @@ -9868,7 +10000,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryRequestMessage); i { + switch v := v.(*MempoolEntry); i { case 0: return &v.state case 1: @@ -9880,7 +10012,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryResponseMessage); i { + switch v := v.(*GetMempoolEntryRequestMessage); i { case 0: return &v.state case 1: @@ -9892,7 +10024,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesRequestMessage); i { + switch v := v.(*GetMempoolEntryResponseMessage); i { case 0: return &v.state case 1: @@ -9904,7 +10036,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesResponseMessage); i { + switch v := v.(*GetMempoolEntriesRequestMessage); i { case 0: return &v.state case 1: @@ -9916,7 +10048,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoRequestMessage); i { + switch v := v.(*GetMempoolEntriesResponseMessage); i { case 0: return &v.state case 1: @@ -9928,7 +10060,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoResponseMessage); i { + switch v := v.(*GetConnectedPeerInfoRequestMessage); i { case 0: return &v.state case 1: @@ -9940,7 +10072,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoMessage); i { + switch v := v.(*GetConnectedPeerInfoResponseMessage); i { case 0: return &v.state case 1: @@ -9952,7 +10084,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerRequestMessage); i { + switch v := v.(*GetConnectedPeerInfoMessage); i { case 0: return &v.state case 1: @@ -9964,7 +10096,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerResponseMessage); i { + switch v := v.(*AddPeerRequestMessage); i { case 0: return &v.state case 1: @@ -9976,7 +10108,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionRequestMessage); i { + switch v := v.(*AddPeerResponseMessage); i { case 0: return &v.state case 1: @@ -9988,7 +10120,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionResponseMessage); i { + switch v := v.(*SubmitTransactionRequestMessage); i { case 0: return &v.state case 1: @@ -10000,7 +10132,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { + switch v := v.(*SubmitTransactionResponseMessage); i { case 0: return &v.state case 1: @@ -10012,7 +10144,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { case 0: return &v.state case 1: @@ -10024,7 +10156,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { + switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { case 0: return &v.state case 1: @@ -10036,7 +10168,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainBlock); i { + switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -10048,7 +10180,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptedBlock); i { + switch v := v.(*ChainBlock); i { case 0: return &v.state case 1: @@ -10060,7 +10192,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockRequestMessage); i { + switch v := v.(*AcceptedBlock); i { case 0: return &v.state case 1: @@ -10072,7 +10204,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockResponseMessage); i { + switch v := v.(*GetBlockRequestMessage); i { case 0: return &v.state case 1: @@ -10084,7 +10216,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockVerboseData); i { + switch v := v.(*GetBlockResponseMessage); i { case 0: return &v.state case 1: @@ -10096,7 +10228,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseData); i { + switch v := v.(*BlockVerboseData); i { case 0: return &v.state case 1: @@ -10108,7 +10240,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseInput); i { + switch v := v.(*TransactionVerboseData); i { case 0: return &v.state case 1: @@ -10120,7 +10252,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptSig); i { + switch v := v.(*TransactionVerboseInput); i { case 0: return &v.state case 1: @@ -10132,7 +10264,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseOutput); i { + switch v := v.(*ScriptSig); i { case 0: return &v.state case 1: @@ -10144,7 +10276,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPubKeyResult); i { + switch v := v.(*TransactionVerboseOutput); i { case 0: return &v.state case 1: @@ -10156,7 +10288,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkRequestMessage); i { + switch v := v.(*ScriptPublicKeyResult); i { case 0: return &v.state case 1: @@ -10168,7 +10300,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkResponseMessage); i { + switch v := v.(*GetSubnetworkRequestMessage); i { case 0: return &v.state case 1: @@ -10180,7 +10312,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { + switch v := v.(*GetSubnetworkResponseMessage); i { case 0: return &v.state case 1: @@ -10192,7 +10324,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { case 0: return &v.state case 1: @@ -10204,7 +10336,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { case 0: return &v.state case 1: @@ -10216,7 +10348,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksResponseMessage); i { + switch v := v.(*GetBlocksRequestMessage); i { case 0: return &v.state case 1: @@ -10228,7 +10360,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountRequestMessage); i { + switch v := v.(*GetBlocksResponseMessage); i { case 0: return &v.state case 1: @@ -10240,7 +10372,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountResponseMessage); i { + switch v := v.(*GetBlockCountRequestMessage); i { case 0: return &v.state case 1: @@ -10252,7 +10384,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoRequestMessage); i { + switch v := v.(*GetBlockCountResponseMessage); i { case 0: return &v.state case 1: @@ -10264,7 +10396,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoResponseMessage); i { + switch v := v.(*GetBlockDagInfoRequestMessage); i { case 0: return &v.state case 1: @@ -10276,7 +10408,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictRequestMessage); i { + switch v := v.(*GetBlockDagInfoResponseMessage); i { case 0: return &v.state case 1: @@ -10288,7 +10420,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictResponseMessage); i { + switch v := v.(*ResolveFinalityConflictRequestMessage); i { case 0: return &v.state case 1: @@ -10300,7 +10432,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsRequestMessage); i { + switch v := v.(*ResolveFinalityConflictResponseMessage); i { case 0: return &v.state case 1: @@ -10312,7 +10444,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsResponseMessage); i { + switch v := v.(*NotifyFinalityConflictsRequestMessage); i { case 0: return &v.state case 1: @@ -10324,7 +10456,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictNotificationMessage); i { + switch v := v.(*NotifyFinalityConflictsResponseMessage); i { case 0: return &v.state case 1: @@ -10336,7 +10468,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + switch v := v.(*FinalityConflictNotificationMessage); i { case 0: return &v.state case 1: @@ -10348,7 +10480,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownRequestMessage); i { + switch v := v.(*FinalityConflictResolvedNotificationMessage); i { case 0: return &v.state case 1: @@ -10360,7 +10492,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownResponseMessage); i { + switch v := v.(*ShutDownRequestMessage); i { case 0: return &v.state case 1: @@ -10372,7 +10504,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersRequestMessage); i { + switch v := v.(*ShutDownResponseMessage); i { case 0: return &v.state case 1: @@ -10384,7 +10516,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersResponseMessage); i { + switch v := v.(*GetHeadersRequestMessage); i { case 0: return &v.state case 1: @@ -10396,7 +10528,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedRequestMessage); i { + switch v := v.(*GetHeadersResponseMessage); i { case 0: return &v.state case 1: @@ -10408,7 +10540,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedResponseMessage); i { + switch v := v.(*NotifyUtxosChangedRequestMessage); i { case 0: return &v.state case 1: @@ -10420,7 +10552,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosChangedNotificationMessage); i { + switch v := v.(*NotifyUtxosChangedResponseMessage); i { case 0: return &v.state case 1: @@ -10432,7 +10564,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosByAddressesEntry); i { + switch v := v.(*UtxosChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -10444,7 +10576,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransaction); i { + switch v := v.(*UtxosByAddressesEntry); i { case 0: return &v.state case 1: @@ -10456,7 +10588,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionInput); i { + switch v := v.(*RpcTransaction); i { case 0: return &v.state case 1: @@ -10468,7 +10600,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionOutput); i { + switch v := v.(*RpcTransactionInput); i { case 0: return &v.state case 1: @@ -10480,7 +10612,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcOutpoint); i { + switch v := v.(*RpcScriptPublicKey); i { case 0: return &v.state case 1: @@ -10492,7 +10624,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcUtxoEntry); i { + switch v := v.(*RpcTransactionOutput); i { case 0: return &v.state case 1: @@ -10504,7 +10636,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesRequestMessage); i { + switch v := v.(*RpcOutpoint); i { case 0: return &v.state case 1: @@ -10516,7 +10648,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesResponseMessage); i { + switch v := v.(*RpcUtxoEntry); i { case 0: return &v.state case 1: @@ -10528,7 +10660,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -10540,7 +10672,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -10552,7 +10684,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { case 0: return &v.state case 1: @@ -10564,7 +10696,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { case 0: return &v.state case 1: @@ -10576,6 +10708,30 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[112].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[113].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[114].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { case 0: return &v.state @@ -10683,7 +10839,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 113, + NumMessages: 115, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 283ab4448..236c89af1 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -126,7 +126,7 @@ message SubnetworkId{ // TransactionMessage start message TransactionMessage{ - int32 version = 1; + uint32 version = 1; repeated TransactionInput inputs = 2; repeated TransactionOutput outputs = 3; uint64 lockTime = 4; @@ -150,10 +150,14 @@ message Outpoint{ message TransactionId{ bytes bytes = 1; } +message ScriptPublicKey { + bytes script = 1; + uint32 version = 2; +} message TransactionOutput{ uint64 value = 1; - bytes scriptPubKey = 2; + ScriptPublicKey scriptPublicKey = 2; } // TransactionMessage end @@ -164,7 +168,7 @@ message BlockMessage{ } message BlockHeaderMessage{ - int32 version = 1; + uint32 version = 1; repeated Hash parentHashes = 2; Hash hashMerkleRoot = 3; Hash acceptedIdMerkleRoot = 4; @@ -500,7 +504,7 @@ message GetBlockResponseMessage{ message BlockVerboseData{ string hash = 1; - int32 version = 2; + uint32 version = 2; string versionHex = 3; string hashMerkleRoot = 4; string acceptedIDMerkleRoot = 5; @@ -521,7 +525,7 @@ message TransactionVerboseData{ string txId = 1; string hash = 2; uint64 size = 3; - int32 version = 4; + uint32 version = 4; uint64 lockTime = 5; string subnetworkId = 6; uint64 gas = 7; @@ -549,10 +553,10 @@ message ScriptSig{ message TransactionVerboseOutput{ uint64 value = 1; uint32 index = 2; - ScriptPubKeyResult scriptPubKey = 3; + ScriptPublicKeyResult scriptPublicKey = 3; } -message ScriptPubKeyResult{ +message ScriptPublicKeyResult{ string asm = 1; string hex = 2; string type = 3; @@ -677,7 +681,7 @@ message UtxosByAddressesEntry { } message RpcTransaction { - int32 version = 1; + uint32 version = 1; repeated RpcTransactionInput inputs = 2; repeated RpcTransactionOutput outputs = 3; uint64 lockTime = 4; @@ -693,9 +697,14 @@ message RpcTransactionInput { uint64 sequence = 3; } +message RpcScriptPublicKey { + uint32 version = 1; + string scriptPublicKey = 2; +} + message RpcTransactionOutput { uint64 amount = 1; - string scriptPubKey = 2; + RpcScriptPublicKey scriptPublicKey = 2; } message RpcOutpoint { @@ -705,7 +714,7 @@ message RpcOutpoint { message RpcUtxoEntry { uint64 amount = 1; - string scriptPubKey = 2; + RpcScriptPublicKey scriptPublicKey = 2; uint64 blockBlueScore = 3; bool isCoinbase = 4; } @@ -742,4 +751,4 @@ message VirtualSelectedParentBlueScoreChangedNotificationMessage { service RPC { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} -} +} \ No newline at end of file diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go index 17487ad28..b9072ddc0 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go @@ -31,9 +31,11 @@ func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) if err != nil { return nil, err } - + if x.Version > 0xffff { + return nil, errors.Errorf("Invalid block header version - bigger then uint16") + } return &appmessage.MsgBlockHeader{ - Version: x.Version, + Version: uint16(x.Version), ParentHashes: parentHashes, HashMerkleRoot: hashMerkleRoot, AcceptedIDMerkleRoot: acceptedIDMerkleRoot, @@ -51,7 +53,7 @@ func (x *BlockHeaderMessage) fromAppMessage(msgBlockHeader *appmessage.MsgBlockH } *x = BlockHeaderMessage{ - Version: msgBlockHeader.Version, + Version: uint32(msgBlockHeader.Version), ParentHashes: domainHashesToProto(msgBlockHeader.ParentHashes), HashMerkleRoot: domainHashToProto(msgBlockHeader.HashMerkleRoot), AcceptedIdMerkleRoot: domainHashToProto(msgBlockHeader.AcceptedIDMerkleRoot), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go index f50f8515c..cf92ffe26 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go @@ -30,9 +30,12 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { outputs := make([]*appmessage.TxOut, len(x.Outputs)) for i, protoOutput := range x.Outputs { + if protoOutput.ScriptPublicKey.Version > 0xFFFF { + return nil, errors.Errorf("The version on ScriptPublicKey is bigger then uint16.") + } outputs[i] = &appmessage.TxOut{ Value: protoOutput.Value, - ScriptPubKey: protoOutput.ScriptPubKey, + ScriptPubKey: &externalapi.ScriptPublicKey{protoOutput.ScriptPublicKey.Script, uint16(protoOutput.ScriptPublicKey.Version)}, } } @@ -52,9 +55,11 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { return nil, err } } - + if x.Version > 0xffff { + return nil, errors.Errorf("Invalid transaction version - bigger then uint16") + } return &appmessage.MsgTx{ - Version: x.Version, + Version: uint16(x.Version), TxIn: inputs, TxOut: outputs, LockTime: x.LockTime, @@ -81,13 +86,16 @@ func (x *TransactionMessage) fromAppMessage(msgTx *appmessage.MsgTx) { protoOutputs := make([]*TransactionOutput, len(msgTx.TxOut)) for i, output := range msgTx.TxOut { protoOutputs[i] = &TransactionOutput{ - Value: output.Value, - ScriptPubKey: output.ScriptPubKey, + Value: output.Value, + ScriptPublicKey: &ScriptPublicKey{ + Script: output.ScriptPubKey.Script, + Version: uint32(output.ScriptPubKey.Version), + }, } } *x = TransactionMessage{ - Version: msgTx.Version, + Version: uint32(msgTx.Version), Inputs: protoInputs, Outputs: protoOutputs, LockTime: msgTx.LockTime, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go index 9ec0133c1..27e899a67 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go @@ -2,6 +2,7 @@ package protowire import ( "github.com/kaspanet/kaspad/app/appmessage" + "github.com/pkg/errors" ) func (x *KaspadMessage_GetBlockRequest) toAppMessage() (appmessage.Message, error) { @@ -70,9 +71,14 @@ func (x *BlockVerboseData) toAppMessage() (*appmessage.BlockVerboseData, error) } transactionVerboseData[i] = appTransactionVerboseDatum } + + if x.Version > 0xffff { + return nil, errors.Errorf("Invalid block header version - bigger then uint16") + } + return &appmessage.BlockVerboseData{ Hash: x.Hash, - Version: x.Version, + Version: uint16(x.Version), VersionHex: x.VersionHex, HashMerkleRoot: x.HashMerkleRoot, AcceptedIDMerkleRoot: x.AcceptedIDMerkleRoot, @@ -102,7 +108,7 @@ func (x *BlockVerboseData) fromAppMessage(message *appmessage.BlockVerboseData) } *x = BlockVerboseData{ Hash: message.Hash, - Version: message.Version, + Version: uint32(message.Version), VersionHex: message.VersionHex, HashMerkleRoot: message.HashMerkleRoot, AcceptedIDMerkleRoot: message.AcceptedIDMerkleRoot, @@ -138,10 +144,9 @@ func (x *TransactionVerboseData) toAppMessage() (*appmessage.TransactionVerboseD outputs := make([]*appmessage.TransactionVerboseOutput, len(x.TransactionVerboseOutputs)) for j, item := range x.TransactionVerboseOutputs { scriptPubKey := &appmessage.ScriptPubKeyResult{ - Asm: item.ScriptPubKey.Asm, - Hex: item.ScriptPubKey.Hex, - Type: item.ScriptPubKey.Type, - Address: item.ScriptPubKey.Address, + Hex: item.ScriptPublicKey.Hex, + Type: item.ScriptPublicKey.Type, + Address: item.ScriptPublicKey.Address, } outputs[j] = &appmessage.TransactionVerboseOutput{ Value: item.Value, @@ -149,11 +154,14 @@ func (x *TransactionVerboseData) toAppMessage() (*appmessage.TransactionVerboseD ScriptPubKey: scriptPubKey, } } + if x.Version > 0xffff { + return nil, errors.Errorf("Invalid transaction version - bigger then uint16") + } return &appmessage.TransactionVerboseData{ TxID: x.TxId, Hash: x.Hash, Size: x.Size, - Version: x.Version, + Version: uint16(x.Version), LockTime: x.LockTime, SubnetworkID: x.SubnetworkId, Gas: x.Gas, @@ -183,23 +191,22 @@ func (x *TransactionVerboseData) fromAppMessage(message *appmessage.TransactionV } outputs := make([]*TransactionVerboseOutput, len(message.TransactionVerboseOutputs)) for j, item := range message.TransactionVerboseOutputs { - scriptPubKey := &ScriptPubKeyResult{ - Asm: item.ScriptPubKey.Asm, + scriptPubKey := &ScriptPublicKeyResult{ Hex: item.ScriptPubKey.Hex, Type: item.ScriptPubKey.Type, Address: item.ScriptPubKey.Address, } outputs[j] = &TransactionVerboseOutput{ - Value: item.Value, - Index: item.Index, - ScriptPubKey: scriptPubKey, + Value: item.Value, + Index: item.Index, + ScriptPublicKey: scriptPubKey, } } *x = TransactionVerboseData{ TxId: message.TxID, Hash: message.Hash, Size: message.Size, - Version: message.Version, + Version: uint32(message.Version), LockTime: message.LockTime, SubnetworkId: message.SubnetworkID, Gas: message.Gas, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go index ce712cdcc..c467dc284 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_utxos_by_addresses.go @@ -22,7 +22,11 @@ func (x *KaspadMessage_GetUtxosByAddressesResponse) toAppMessage() (appmessage.M } entries := make([]*appmessage.UTXOsByAddressesEntry, len(x.GetUtxosByAddressesResponse.Entries)) for i, entry := range x.GetUtxosByAddressesResponse.Entries { - entries[i] = entry.toAppMessage() + entryAsAppMessage, err := entry.toAppMessage() + if err != nil { + return nil, err + } + entries[i] = entryAsAppMessage } return &appmessage.GetUTXOsByAddressesResponseMessage{ Entries: entries, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go index 23b3210b3..36c9839d3 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_utxos_changed.go @@ -41,12 +41,20 @@ func (x *KaspadMessage_NotifyUtxosChangedResponse) fromAppMessage(message *appme func (x *KaspadMessage_UtxosChangedNotification) toAppMessage() (appmessage.Message, error) { added := make([]*appmessage.UTXOsByAddressesEntry, len(x.UtxosChangedNotification.Added)) for i, entry := range x.UtxosChangedNotification.Added { - added[i] = entry.toAppMessage() + entryAsAppMessage, err := entry.toAppMessage() + if err != nil { + return nil, err + } + added[i] = entryAsAppMessage } removed := make([]*appmessage.UTXOsByAddressesEntry, len(x.UtxosChangedNotification.Removed)) for i, entry := range x.UtxosChangedNotification.Removed { - removed[i] = entry.toAppMessage() + entryAsAppMessage, err := entry.toAppMessage() + if err != nil { + return nil, err + } + removed[i] = entryAsAppMessage } return &appmessage.UTXOsChangedNotificationMessage{ @@ -75,25 +83,29 @@ func (x *KaspadMessage_UtxosChangedNotification) fromAppMessage(message *appmess return nil } -func (x *UtxosByAddressesEntry) toAppMessage() *appmessage.UTXOsByAddressesEntry { +func (x *UtxosByAddressesEntry) toAppMessage() (*appmessage.UTXOsByAddressesEntry, error) { outpoint := &appmessage.RPCOutpoint{ TransactionID: x.Outpoint.TransactionId, Index: x.Outpoint.Index, } var utxoEntry *appmessage.RPCUTXOEntry if x.UtxoEntry != nil { + scriptPubKey, err := ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey(x.UtxoEntry.ScriptPublicKey) + if err != nil { + return nil, err + } utxoEntry = &appmessage.RPCUTXOEntry{ - Amount: x.UtxoEntry.Amount, - ScriptPubKey: x.UtxoEntry.ScriptPubKey, - BlockBlueScore: x.UtxoEntry.BlockBlueScore, - IsCoinbase: x.UtxoEntry.IsCoinbase, + Amount: x.UtxoEntry.Amount, + ScriptPublicKey: scriptPubKey, + BlockBlueScore: x.UtxoEntry.BlockBlueScore, + IsCoinbase: x.UtxoEntry.IsCoinbase, } } return &appmessage.UTXOsByAddressesEntry{ Address: x.Address, Outpoint: outpoint, UTXOEntry: utxoEntry, - } + }, nil } func (x *UtxosByAddressesEntry) fromAppMessage(entry *appmessage.UTXOsByAddressesEntry) { @@ -104,10 +116,10 @@ func (x *UtxosByAddressesEntry) fromAppMessage(entry *appmessage.UTXOsByAddresse var utxoEntry *RpcUtxoEntry if entry.UTXOEntry != nil { utxoEntry = &RpcUtxoEntry{ - Amount: entry.UTXOEntry.Amount, - ScriptPubKey: entry.UTXOEntry.ScriptPubKey, - BlockBlueScore: entry.UTXOEntry.BlockBlueScore, - IsCoinbase: entry.UTXOEntry.IsCoinbase, + Amount: entry.UTXOEntry.Amount, + ScriptPublicKey: ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey(entry.UTXOEntry.ScriptPublicKey), + BlockBlueScore: entry.UTXOEntry.BlockBlueScore, + IsCoinbase: entry.UTXOEntry.IsCoinbase, } } *x = UtxosByAddressesEntry{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go index f60525930..f52ef0877 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go @@ -2,10 +2,14 @@ package protowire import ( "github.com/kaspanet/kaspad/app/appmessage" + "github.com/pkg/errors" ) func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) { - rpcTransaction := x.SubmitTransactionRequest.Transaction.toAppMessage() + rpcTransaction, err := x.SubmitTransactionRequest.Transaction.toAppMessage() + if err != nil { + return nil, err + } return &appmessage.SubmitTransactionRequestMessage{ Transaction: rpcTransaction, }, nil @@ -42,7 +46,7 @@ func (x *KaspadMessage_SubmitTransactionResponse) fromAppMessage(message *appmes return nil } -func (x *RpcTransaction) toAppMessage() *appmessage.RPCTransaction { +func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) { inputs := make([]*appmessage.RPCTransactionInput, len(x.Inputs)) for i, input := range x.Inputs { previousOutpoint := &appmessage.RPCOutpoint{ @@ -57,13 +61,22 @@ func (x *RpcTransaction) toAppMessage() *appmessage.RPCTransaction { } outputs := make([]*appmessage.RPCTransactionOutput, len(x.Outputs)) for i, output := range x.Outputs { + scriptPubKey, err := ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey(output.ScriptPublicKey) + if err != nil { + return nil, err + } outputs[i] = &appmessage.RPCTransactionOutput{ - Amount: output.Amount, - ScriptPubKey: output.ScriptPubKey, + Amount: output.Amount, + ScriptPublicKey: scriptPubKey, } } + + if x.Version > 0xffff { + return nil, errors.Errorf("Invalid RPC txn version - bigger then uint16") + } + return &appmessage.RPCTransaction{ - Version: x.Version, + Version: uint16(x.Version), Inputs: inputs, Outputs: outputs, LockTime: x.LockTime, @@ -71,7 +84,23 @@ func (x *RpcTransaction) toAppMessage() *appmessage.RPCTransaction { Gas: x.Gas, PayloadHash: x.PayloadHash, Payload: x.Payload, + }, nil +} + +// ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey converts from RpcScriptPubKey to RPCScriptPublicKey. +func ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey(toConvert *RpcScriptPublicKey) (*appmessage.RPCScriptPublicKey, error) { + if toConvert.Version > 0xffff { + return nil, errors.Errorf("Invalid header version - bigger then uint16") } + version := uint16(toConvert.Version) + script := toConvert.ScriptPublicKey + return &appmessage.RPCScriptPublicKey{Version: version, + Script: script}, nil +} + +// ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey converts from RPCScriptPublicKey to RpcScriptPubKey. +func ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey(toConvert *appmessage.RPCScriptPublicKey) *RpcScriptPublicKey { + return &RpcScriptPublicKey{Version: uint32(toConvert.Version), ScriptPublicKey: toConvert.Script} } func (x *RpcTransaction) fromAppMessage(transaction *appmessage.RPCTransaction) { @@ -90,12 +119,12 @@ func (x *RpcTransaction) fromAppMessage(transaction *appmessage.RPCTransaction) outputs := make([]*RpcTransactionOutput, len(transaction.Outputs)) for i, output := range transaction.Outputs { outputs[i] = &RpcTransactionOutput{ - Amount: output.Amount, - ScriptPubKey: output.ScriptPubKey, + Amount: output.Amount, + ScriptPublicKey: ConvertFromRPCScriptPubKeyToAppMsgRPCScriptPubKey(output.ScriptPublicKey), } } *x = RpcTransaction{ - Version: transaction.Version, + Version: uint32(transaction.Version), Inputs: inputs, Outputs: outputs, LockTime: transaction.LockTime, diff --git a/testing/integration/tx_relay_test.go b/testing/integration/tx_relay_test.go index 3e6b85fe3..0347c6d6f 100644 --- a/testing/integration/tx_relay_test.go +++ b/testing/integration/tx_relay_test.go @@ -103,7 +103,7 @@ func generateTx(t *testing.T, firstBlockCoinbase *externalapi.DomainTransaction, fromScript := firstBlockCoinbase.Outputs[0].ScriptPublicKey - tx := appmessage.NewNativeMsgTx(constants.TransactionVersion, txIns, txOuts) + tx := appmessage.NewNativeMsgTx(constants.MaxTransactionVersion, txIns, txOuts) privateKeyBytes, err := hex.DecodeString(payer.miningAddressPrivateKey) if err != nil { diff --git a/testing/integration/utxo_index_test.go b/testing/integration/utxo_index_test.go index 221085141..a40c87f49 100644 --- a/testing/integration/utxo_index_test.go +++ b/testing/integration/utxo_index_test.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" @@ -132,7 +133,22 @@ func TestUTXOIndex(t *testing.T) { t.Fatalf("Missing entry in UTXOs response: %s:%d", notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index) } - if *notificationEntry.UTXOEntry != *foundResponseEntry.UTXOEntry { + if notificationEntry.UTXOEntry.Amount != foundResponseEntry.UTXOEntry.Amount { + t.Fatalf("Unexpected UTXOEntry for outpoint %s:%d. Want: %+v, got: %+v", + notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index, + notificationEntry.UTXOEntry, foundResponseEntry.UTXOEntry) + } + if notificationEntry.UTXOEntry.BlockBlueScore != foundResponseEntry.UTXOEntry.BlockBlueScore { + t.Fatalf("Unexpected UTXOEntry for outpoint %s:%d. Want: %+v, got: %+v", + notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index, + notificationEntry.UTXOEntry, foundResponseEntry.UTXOEntry) + } + if notificationEntry.UTXOEntry.IsCoinbase != foundResponseEntry.UTXOEntry.IsCoinbase { + t.Fatalf("Unexpected UTXOEntry for outpoint %s:%d. Want: %+v, got: %+v", + notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index, + notificationEntry.UTXOEntry, foundResponseEntry.UTXOEntry) + } + if *notificationEntry.UTXOEntry.ScriptPublicKey != *foundResponseEntry.UTXOEntry.ScriptPublicKey { t.Fatalf("Unexpected UTXOEntry for outpoint %s:%d. Want: %+v, got: %+v", notificationEntry.Outpoint.TransactionID, notificationEntry.Outpoint.Index, notificationEntry.UTXOEntry, foundResponseEntry.UTXOEntry) @@ -164,12 +180,12 @@ func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAdd txOuts := []*appmessage.TxOut{appmessage.NewTxOut(entry.UTXOEntry.Amount-1000, toScript)} - fromScript, err := hex.DecodeString(entry.UTXOEntry.ScriptPubKey) + fromScript, err := hex.DecodeString(entry.UTXOEntry.ScriptPublicKey.Script) if err != nil { t.Fatalf("Error decoding script public key: %s", err) } - msgTx := appmessage.NewNativeMsgTx(constants.TransactionVersion, txIns, txOuts) + msgTx := appmessage.NewNativeMsgTx(constants.MaxTransactionVersion, txIns, txOuts) privateKeyBytes, err := hex.DecodeString(miningAddress1PrivateKey) if err != nil { @@ -181,7 +197,10 @@ func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAdd } signatureScript, err := txscript.SignatureScript(appmessage.MsgTxToDomainTransaction(msgTx), 0, - fromScript, txscript.SigHashAll, privateKey) + &externalapi.ScriptPublicKey{ + Script: fromScript, + Version: 0, + }, txscript.SigHashAll, privateKey) if err != nil { t.Fatalf("Error signing transaction: %+v", err) } From e24bc527f3351efcdca3a27a86b4dbfadb868c3e Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 5 Jan 2021 18:36:08 +0200 Subject: [PATCH 210/351] Update the max block size and mass constants to reasonable values (#1344) Co-authored-by: Elichai Turkel --- domain/dagconfig/consensus_defaults.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/dagconfig/consensus_defaults.go b/domain/dagconfig/consensus_defaults.go index 68781e1b7..4688ed1be 100644 --- a/domain/dagconfig/consensus_defaults.go +++ b/domain/dagconfig/consensus_defaults.go @@ -25,7 +25,7 @@ const ( defaultMaxCoinbasePayloadLength = 150 // defaultMaxBlockSize is a bound on the size of a block in bytes, larger values increase the bound d // on the round trip time of a block, which affects the other parameters as described below - defaultMaxBlockSize = 1_000_000 + defaultMaxBlockSize = 50_000 // defaultMaxBlockParents is the number of blocks any block can point to. // Should be about d/defaultTargetTimePerBlock where d is a bound on the round trip time of a block. defaultMaxBlockParents = 10 @@ -38,7 +38,7 @@ const ( // (Higher values make pruning attacks easier by a constant, lower values make merging after a split or a spike // in block take longer) defaultMergeSetSizeLimit = 1000 - defaultMaxMassAcceptedByBlock = 10000000 + defaultMaxMassAcceptedByBlock = 500_000 defaultBaseSubsidy = 50 * constants.SompiPerKaspa defaultCoinbasePayloadScriptPublicKeyMaxLength = 150 // defaultGHOSTDAGK is a bound on the number of blue blocks in the anticone of a blue block. Approximates the maximal From 6279db2bf1f9606c8593ee6615ff07ee75f83846 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 5 Jan 2021 19:10:59 +0200 Subject: [PATCH 211/351] Reverse ghostdag tie break direction (#1359) * Remove hash reversal in ghostdag * Update tests after chaning ghostdag hash direction Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- domain/consensus/model/externalapi/hash.go | 16 +---- .../dagtraversalmanager/window_test.go | 64 +++++++++---------- .../processes/ghostdag2/ghostdagimpl.go | 2 +- .../ghostdagmanager/ghostdag_test.go | 2 +- .../processes/pruningmanager/pruning_test.go | 17 ++--- domain/consensus/testdata/dags/dag1.json | 28 ++++---- domain/consensus/testdata/dags/dag2.json | 4 +- 7 files changed, 61 insertions(+), 72 deletions(-) diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index b6baa24e7..21ab2fca6 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -1,6 +1,7 @@ package externalapi import ( + "bytes" "encoding/hex" "github.com/pkg/errors" @@ -106,20 +107,7 @@ func HashesEqual(a, b []*DomainHash) bool { return true } -func cmp(a, b *DomainHash) int { - // We compare the hashes backwards because Hash is stored as a little endian byte array. - for i := DomainHashSize - 1; i >= 0; i-- { - switch { - case a.hashArray[i] < b.hashArray[i]: - return -1 - case a.hashArray[i] > b.hashArray[i]: - return 1 - } - } - return 0 -} - // Less returns true iff hash a is less than hash b func Less(a, b *DomainHash) bool { - return cmp(a, b) < 0 + return bytes.Compare(a.hashArray[:], b.hashArray[:]) < 0 } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 802757822..d1faec258 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -36,12 +36,12 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"D", "C"}, + parents: []string{"C", "D"}, id: "E", expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"D", "C"}, + parents: []string{"C", "D"}, id: "F", expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, @@ -58,37 +58,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "H", "C", "D", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "D", "H", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "H", "C", "D", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "D", "H", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "C", "D", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "D", "H", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "C", "D", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "D", "H", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "C", "D", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "D", "H", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"}, }, }, "kaspa-testnet": { @@ -108,14 +108,14 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"B", "A", "A", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"D", "C"}, + parents: []string{"C", "D"}, id: "E", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { - parents: []string{"D", "C"}, + parents: []string{"C", "D"}, id: "F", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -130,37 +130,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "H", "D", "C", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "G", "B", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "H", "D", "C", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "G", "B", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "D", "C", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "G", "B", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "D", "C", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "G", "B", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "D", "C", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "G", "B"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "D", "C", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "G"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "D", "C"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, }, }, "kaspa-devnet": { @@ -202,32 +202,32 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, }, { parents: []string{"N"}, @@ -274,32 +274,32 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, }, { parents: []string{"N"}, diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index 0b6fee8eb..2afec5464 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -124,7 +124,7 @@ func ismoreHash(parent *externalapi.DomainHash, selectedParent *externalapi.Doma parentByteArray := parent.ByteArray() selectedParentByteArray := selectedParent.ByteArray() //Check if parentHash is more then selectedParentHash - for i := len(parentByteArray) - 1; i >= 0; i-- { + for i := 0; i < len(parentByteArray); i++ { switch { case parentByteArray[i] < selectedParentByteArray[i]: return false diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index eaa2c5104..71f87120b 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -181,7 +181,7 @@ func TestGHOSTDAG(t *testing.T) { func hashesToStrings(arr []*externalapi.DomainHash) []string { var strArr = make([]string, len(arr)) for i, hash := range arr { - strArr[i] = hash.String() + strArr[i] = string(hash.ByteSlice()) } return strArr } diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index 3b3f10808..fd25d69c0 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -2,14 +2,15 @@ package pruningmanager_test import ( "encoding/json" - "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" "os" "path/filepath" "testing" "time" + + "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" ) type jsonBlock struct { @@ -32,10 +33,10 @@ func TestPruning(t *testing.T) { "kaspa-testnet": "1582", }, "dag-for-test-pruning.json": { - "kaspa-mainnet": "503", - "kaspa-simnet": "503", - "kaspa-devnet": "502", - "kaspa-testnet": "503", + "kaspa-mainnet": "502", + "kaspa-simnet": "502", + "kaspa-devnet": "503", + "kaspa-testnet": "502", }, } diff --git a/domain/consensus/testdata/dags/dag1.json b/domain/consensus/testdata/dags/dag1.json index d751b3c00..58db801fb 100644 --- a/domain/consensus/testdata/dags/dag1.json +++ b/domain/consensus/testdata/dags/dag1.json @@ -3,7 +3,7 @@ "GenesisID": "0", "Blocks": [ { - "ID": "1111", + "ID": "a1", "ExpectedScore": 1, "ExpectedSelectedParent": "0", "ExpectedReds": [], @@ -41,13 +41,13 @@ { "ID": "4", "ExpectedScore": 2, - "ExpectedSelectedParent": "1111", + "ExpectedSelectedParent": "a1", "ExpectedReds": [], "ExpectedBlues": [ - "1111" + "a1" ], "Parents": [ - "1111" + "a1" ] }, { @@ -91,14 +91,14 @@ { "ID": "8", "ExpectedScore": 3, - "ExpectedSelectedParent": "1111", + "ExpectedSelectedParent": "a1", "ExpectedReds": [], "ExpectedBlues": [ - "1111", + "a1", "2" ], "Parents": [ - "1111", + "a1", "2" ] }, @@ -117,7 +117,7 @@ ] }, { - "ID": "10", + "ID": "a10", "ExpectedScore": 5, "ExpectedSelectedParent": "8", "ExpectedReds": [], @@ -147,18 +147,18 @@ { "ID": "12", "ExpectedScore": 8, - "ExpectedSelectedParent": "10", + "ExpectedSelectedParent": "a10", "ExpectedReds": [ "3", "6" ], "ExpectedBlues": [ - "10", + "a10", "5", "9" ], "Parents": [ - "10", + "a10", "9" ] }, @@ -186,11 +186,11 @@ ], "ExpectedBlues": [ "13", - "10" + "a10" ], "Parents": [ "13", - "10" + "a10" ] }, { @@ -198,7 +198,7 @@ "ExpectedScore": 9, "ExpectedSelectedParent": "11", "ExpectedReds": [ - "1111", + "a1", "8" ], "ExpectedBlues": [ diff --git a/domain/consensus/testdata/dags/dag2.json b/domain/consensus/testdata/dags/dag2.json index 1be478e7f..f1c5c6242 100644 --- a/domain/consensus/testdata/dags/dag2.json +++ b/domain/consensus/testdata/dags/dag2.json @@ -84,8 +84,8 @@ "ExpectedReds": [], "ExpectedBlues": [ "f154", - "d1c", - "21d" + "21d", + "d1c" ], "Parents": [ "d1c", From 741e0962bef3133d83b49e294cb1deae4749708b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 6 Jan 2021 10:31:42 +0200 Subject: [PATCH 212/351] Remove diffs from restoreUTXO logs (#1354) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- .../processes/consensusstatemanager/calculate_past_utxo.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index eccd1cc80..6c6ba244a 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -77,8 +77,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH } if !exists { log.Debugf("Block %s does not have a UTXO diff child, "+ - "meaning we reached the virtual. Returning the collected "+ - "UTXO diffs: %s", nextBlockHash, utxoDiffs) + "meaning we reached the virtual", nextBlockHash) break } @@ -88,8 +87,7 @@ func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainH } if nextBlockHash == nil { log.Debugf("Block %s does not have a UTXO diff child, "+ - "meaning we reached the virtual. Returning the collected "+ - "UTXO diffs: %s", nextBlockHash, utxoDiffs) + "meaning we reached the virtual", nextBlockHash) break } } From 3ec1cbe236117390b315530b769fe1ef6da653f7 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 6 Jan 2021 10:37:10 +0200 Subject: [PATCH 213/351] Add TestBlockStatus (#1361) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- .../consensus/model/testapi/test_consensus.go | 3 + .../validateandinsertblock_test.go | 106 ++++++++++++++++++ .../block_body_in_isolation_test.go | 2 +- domain/consensus/test_consensus.go | 22 ++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 domain/consensus/processes/blockprocessor/validateandinsertblock_test.go diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 8b3f9d1fd..c36a69a36 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -23,6 +23,9 @@ type TestConsensus interface { AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) + AddHeader(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) + DiscardAllStores() AcceptanceDataStore() model.AcceptanceDataStore diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go new file mode 100644 index 000000000..8f59baffe --- /dev/null +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go @@ -0,0 +1,106 @@ +package blockprocessor_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" + "testing" +) + +func TestBlockStatus(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, "TestBlockStatus") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + checkStatus := func(hash *externalapi.DomainHash, expectedStatus externalapi.BlockStatus) { + blockStatus, err := tc.BlockStatusStore().Get(tc.DatabaseContext(), hash) + if err != nil { + t.Fatalf("BlockStatusStore().Get: %+v", err) + } + + if blockStatus != expectedStatus { + t.Fatalf("Expected to have status %s but got %s", expectedStatus, blockStatus) + } + } + + tipHash := params.GenesisHash + for i := 0; i < 2; i++ { + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + checkStatus(tipHash, externalapi.StatusUTXOValid) + } + + headerHash, _, err := tc.AddHeader([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + checkStatus(headerHash, externalapi.StatusHeaderOnly) + + nonChainBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + checkStatus(nonChainBlockHash, externalapi.StatusUTXOPendingVerification) + + disqualifiedBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + disqualifiedBlock.Header = blockheader.NewImmutableBlockHeader( + disqualifiedBlock.Header.Version(), + disqualifiedBlock.Header.ParentHashes(), + disqualifiedBlock.Header.HashMerkleRoot(), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}), // This should disqualify the block + disqualifiedBlock.Header.UTXOCommitment(), + disqualifiedBlock.Header.TimeInMilliseconds(), + disqualifiedBlock.Header.Bits(), + disqualifiedBlock.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(disqualifiedBlock) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + checkStatus(consensushashing.BlockHash(disqualifiedBlock), externalapi.StatusDisqualifiedFromChain) + + invalidBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + invalidBlock.Header = blockheader.NewImmutableBlockHeader( + disqualifiedBlock.Header.Version(), + disqualifiedBlock.Header.ParentHashes(), + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}), // This should invalidate the block + disqualifiedBlock.Header.AcceptedIDMerkleRoot(), + disqualifiedBlock.Header.UTXOCommitment(), + disqualifiedBlock.Header.TimeInMilliseconds(), + disqualifiedBlock.Header.Bits(), + disqualifiedBlock.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(invalidBlock) + if err == nil { + t.Fatalf("block is expected to be invalid") + } + if !errors.As(err, &ruleerrors.RuleError{}) { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + checkStatus(consensushashing.BlockHash(invalidBlock), externalapi.StatusInvalid) + }) +} diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index fc1559fe2..53f47191f 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -21,7 +21,7 @@ func TestChainedTransactions(t *testing.T) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + tc, teardown, err := factory.NewTestConsensus(params, "TestChainedTransactions") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index c5b4856ec..31481a7d7 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -60,6 +60,28 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba return consensushashing.BlockHash(block), blockInsertionResult, nil } +func (tc *testConsensus) AddHeader(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, + transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) { + + // Require write lock because BuildBlockWithParents stages temporary data + tc.lock.Lock() + defer tc.lock.Unlock() + + block, _, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) + if err != nil { + return nil, nil, err + } + + block.Transactions = nil + + blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(block) + if err != nil { + return nil, nil, err + } + + return consensushashing.BlockHash(block), blockInsertionResult, nil +} + func (tc *testConsensus) DiscardAllStores() { tc.AcceptanceDataStore().Discard() tc.BlockHeaderStore().Discard() From 2059d6ba56767f28cc65b10fbf1dc32961eeb142 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 6 Jan 2021 10:43:44 +0200 Subject: [PATCH 214/351] Delete sync rate mechanism (#1356) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/protocol/flowcontext/blocks.go | 1 - app/protocol/flowcontext/flow_context.go | 3 - app/protocol/flowcontext/orphans.go | 1 - app/protocol/flowcontext/should_mine.go | 43 ++++++++ app/protocol/flowcontext/sync_rate.go | 98 ------------------- .../flows/blockrelay/handle_relay_invs.go | 1 - app/protocol/flows/blockrelay/ibd.go | 2 - 7 files changed, 43 insertions(+), 106 deletions(-) create mode 100644 app/protocol/flowcontext/should_mine.go delete mode 100644 app/protocol/flowcontext/sync_rate.go diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 96965d24f..657221669 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -24,7 +24,6 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, log.Debugf("OnNewBlock start for block %s", hash) defer log.Debugf("OnNewBlock end for block %s", hash) - f.UpdateRecentBlockAddedTimesWithLastBlock() unorphaningResults, err := f.UnorphanBlocks(block) if err != nil { return err diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index 1846148fd..2af8e5f86 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -36,9 +36,6 @@ type FlowContext struct { addressManager *addressmanager.AddressManager connectionManager *connmanager.ConnectionManager - recentBlockAddedTimes []int64 - recentBlockAddedTimesMutex sync.Mutex - timeStarted int64 onBlockAddedToDAGHandler OnBlockAddedToDAGHandler diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index d7a17ab58..4ef23eb28 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -156,7 +156,6 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa } return nil, false, err } - f.UpdateRecentBlockAddedTimesWithLastBlock() log.Infof("Unorphaned block %s", orphanHash) return blockInsertionResult, true, nil diff --git a/app/protocol/flowcontext/should_mine.go b/app/protocol/flowcontext/should_mine.go new file mode 100644 index 000000000..7f0b4b628 --- /dev/null +++ b/app/protocol/flowcontext/should_mine.go @@ -0,0 +1,43 @@ +package flowcontext + +import "github.com/kaspanet/kaspad/util/mstime" + +const ( + maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 300_000 +) + +// ShouldMine returns whether it's ok to use block template from this node +// for mining purposes. +func (f *FlowContext) ShouldMine() (bool, error) { + peers := f.Peers() + if len(peers) == 0 { + log.Debugf("The node is not connected, so ShouldMine returns false") + return false, nil + } + + if f.IsIBDRunning() { + log.Debugf("IBD is running, so ShouldMine returns false") + return false, nil + } + + virtualSelectedParent, err := f.domain.Consensus().GetVirtualSelectedParent() + if err != nil { + return false, err + } + + virtualSelectedParentHeader, err := f.domain.Consensus().GetBlockHeader(virtualSelectedParent) + if err != nil { + return false, err + } + + now := mstime.Now().UnixMilliseconds() + if now-virtualSelectedParentHeader.TimeInMilliseconds() < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { + log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true", + virtualSelectedParentHeader.TimeInMilliseconds()) + return true, nil + } + + log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false", + virtualSelectedParentHeader.TimeInMilliseconds()) + return false, nil +} diff --git a/app/protocol/flowcontext/sync_rate.go b/app/protocol/flowcontext/sync_rate.go deleted file mode 100644 index 79d488c35..000000000 --- a/app/protocol/flowcontext/sync_rate.go +++ /dev/null @@ -1,98 +0,0 @@ -package flowcontext - -import "github.com/kaspanet/kaspad/util/mstime" - -const ( - syncRateWindowInMilliSeconds = 15 * 60 * 1000 - syncRateMaxDeviation = 0.05 - maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 300_000 -) - -// UpdateRecentBlockAddedTimesWithLastBlock adds current time to list of times when block was added. -// We use this list to determine the current sync rate -func (f *FlowContext) UpdateRecentBlockAddedTimesWithLastBlock() { - f.recentBlockAddedTimesMutex.Lock() - defer f.recentBlockAddedTimesMutex.Unlock() - - f.removeOldBlockTimes() - f.recentBlockAddedTimes = append(f.recentBlockAddedTimes, mstime.Now().UnixMilliseconds()) -} - -// removeOldBlockTimes removes from recentBlockAddedTimes block times -// older than syncRateWindowInMilliSeconds. -// This function is not safe for concurrent use. -func (f *FlowContext) removeOldBlockTimes() { - now := mstime.Now().UnixMilliseconds() - mostRecentBlockToKeep := 0 - for i, blockAddedTime := range f.recentBlockAddedTimes { - if now-syncRateWindowInMilliSeconds < blockAddedTime { - mostRecentBlockToKeep = i - break - } - } - f.recentBlockAddedTimes = f.recentBlockAddedTimes[mostRecentBlockToKeep:] -} - -func (f *FlowContext) isSyncRateBelowMinimum() bool { - f.recentBlockAddedTimesMutex.Lock() - defer f.recentBlockAddedTimesMutex.Unlock() - - f.removeOldBlockTimes() - - now := mstime.Now().UnixMilliseconds() - timeSinceStart := now - f.timeStarted - if timeSinceStart <= syncRateWindowInMilliSeconds { - return false - } - - expectedBlocks := float64(syncRateWindowInMilliSeconds) / float64(f.cfg.NetParams().TargetTimePerBlock.Milliseconds()) - isSyncRateTooLow := 1-float64(len(f.recentBlockAddedTimes))/expectedBlocks > syncRateMaxDeviation - - if isSyncRateTooLow { - log.Debugf("In the last %d seconds, got %d blocks, while at least %f were expected.", - syncRateWindowInMilliSeconds/1000, len(f.recentBlockAddedTimes), expectedBlocks*(1-syncRateMaxDeviation)) - } - - return isSyncRateTooLow -} - -// ShouldMine returns whether it's ok to use block template from this node -// for mining purposes. -func (f *FlowContext) ShouldMine() (bool, error) { - peers := f.Peers() - if len(peers) == 0 { - log.Debugf("The node is not connected, so ShouldMine returns false") - return false, nil - } - - if f.isSyncRateBelowMinimum() { - log.Debugf("The sync rate is below the minimum, so ShouldMine returns true") - return true, nil - } - - if f.IsIBDRunning() { - log.Debugf("IBD is running, so ShouldMine returns false") - return false, nil - } - - virtualSelectedParent, err := f.domain.Consensus().GetVirtualSelectedParent() - if err != nil { - return false, err - } - - virtualSelectedParentHeader, err := f.domain.Consensus().GetBlockHeader(virtualSelectedParent) - if err != nil { - return false, err - } - - now := mstime.Now().UnixMilliseconds() - if now-virtualSelectedParentHeader.TimeInMilliseconds() < maxSelectedParentTimeDiffToAllowMiningInMilliSeconds { - log.Debugf("The selected tip timestamp is recent (%d), so ShouldMine returns true", - virtualSelectedParentHeader.TimeInMilliseconds()) - return true, nil - } - - log.Debugf("The selected tip timestamp is old (%d), so ShouldMine returns false", - virtualSelectedParentHeader.TimeInMilliseconds()) - return false, nil -} diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index f4a81a52f..8b91c5788 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -33,7 +33,6 @@ type RelayInvsContext interface { IsIBDRunning() bool TrySetIBDRunning() bool UnsetIBDRunning() - UpdateRecentBlockAddedTimesWithLastBlock() } type handleRelayInvsFlow struct { diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index eea862ace..8ff8a9c36 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -279,8 +279,6 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) } - flow.UpdateRecentBlockAddedTimesWithLastBlock() - return nil } From d8293ef63570c16456044b25d1547fcdc3af8d28 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 6 Jan 2021 11:41:52 +0200 Subject: [PATCH 215/351] Revert "Add recoverability for UTXO index (#1342)" (#1353) This reverts commit 778375c4 --- app/component_manager.go | 5 +- domain/consensus/consensus.go | 26 ---- .../consensus/model/externalapi/consensus.go | 2 - domain/consensus/model/externalapi/utxo.go | 7 -- domain/utxoindex/store.go | 113 ++---------------- domain/utxoindex/utxoindex.go | 78 +----------- 6 files changed, 14 insertions(+), 217 deletions(-) delete mode 100644 domain/consensus/model/externalapi/utxo.go diff --git a/app/component_manager.go b/app/component_manager.go index b2889740d..f3efe34e9 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -96,10 +96,7 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, var utxoIndex *utxoindex.UTXOIndex if cfg.UTXOIndex { - utxoIndex, err = utxoindex.New(domain.Consensus(), db, cfg.ActiveNetParams.GenesisHash) - if err != nil { - return nil, err - } + utxoIndex = utxoindex.New(domain.Consensus(), db) log.Infof("UTXO index started") } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index d45addf63..614d19b97 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -2,7 +2,6 @@ package consensus import ( "github.com/kaspanet/kaspad/infrastructure/db/database" - "github.com/kaspanet/kaspad/infrastructure/logger" "sync" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -373,28 +372,3 @@ func (s *consensus) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { return s.headersSelectedTipStore.HeadersSelectedTip(s.databaseContext) } - -func (s *consensus) GetVirtualUTXOSet() ([]*externalapi.OutpointUTXOPair, error) { - onEnd := logger.LogAndMeasureExecutionTime(log, "consensus.GetVirtualUTXOSet") - defer onEnd() - - s.lock.Lock() - defer s.lock.Unlock() - - iterator, err := s.consensusStateStore.VirtualUTXOSetIterator(s.databaseContext) - if err != nil { - return nil, err - } - - pairs := make([]*externalapi.OutpointUTXOPair, 0) - for iterator.Next() { - outpoint, entry, err := iterator.Get() - if err != nil { - return nil, err - } - - pairs = append(pairs, &externalapi.OutpointUTXOPair{Outpoint: outpoint, Entry: entry}) - } - - return pairs, nil -} diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 72b51ab4f..8921d9a28 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -26,6 +26,4 @@ type Consensus interface { GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) IsInSelectedParentChainOf(blockHashA *DomainHash, blockHashB *DomainHash) (bool, error) GetHeadersSelectedTip() (*DomainHash, error) - - GetVirtualUTXOSet() ([]*OutpointUTXOPair, error) } diff --git a/domain/consensus/model/externalapi/utxo.go b/domain/consensus/model/externalapi/utxo.go deleted file mode 100644 index 4af652fc0..000000000 --- a/domain/consensus/model/externalapi/utxo.go +++ /dev/null @@ -1,7 +0,0 @@ -package externalapi - -// OutpointUTXOPair is a pair of outpoint and UTXO entry -type OutpointUTXOPair struct { - Outpoint *DomainOutpoint - Entry UTXOEntry -} diff --git a/domain/utxoindex/store.go b/domain/utxoindex/store.go index 9fd7b6ce9..dba9d7fd5 100644 --- a/domain/utxoindex/store.go +++ b/domain/utxoindex/store.go @@ -11,13 +11,11 @@ import ( ) var utxoIndexBucket = database.MakeBucket([]byte("utxo-index")) -var utxoIndexLastVirtualSelectedParentKey = database.MakeBucket().Key([]byte("utxo-index-last-virtual-selected-parent")) type utxoIndexStore struct { - database database.Database - toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs - toRemove map[ScriptPublicKeyString]UTXOOutpoints - virtualSelectedParent *externalapi.DomainHash + database database.Database + toAdd map[ScriptPublicKeyString]UTXOOutpointEntryPairs + toRemove map[ScriptPublicKeyString]UTXOOutpoints } func newUTXOIndexStore(database database.Database) *utxoIndexStore { @@ -100,7 +98,6 @@ func (uis *utxoIndexStore) remove(scriptPublicKey *externalapi.ScriptPublicKey, func (uis *utxoIndexStore) discard() { uis.toAdd = make(map[ScriptPublicKeyString]UTXOOutpointEntryPairs) uis.toRemove = make(map[ScriptPublicKeyString]UTXOOutpoints) - uis.virtualSelectedParent = nil } func (uis *utxoIndexStore) commit() error { @@ -147,11 +144,6 @@ func (uis *utxoIndexStore) commit() error { } } - err = dbTransaction.Put(utxoIndexLastVirtualSelectedParentKey, uis.virtualSelectedParent.ByteSlice()) - if err != nil { - return err - } - err = dbTransaction.Commit() if err != nil { return err @@ -234,6 +226,10 @@ func (uis *utxoIndexStore) stagedData() ( return toAddClone, toRemoveClone } +func (uis *utxoIndexStore) isAnythingStaged() bool { + return len(uis.toAdd) > 0 || len(uis.toRemove) > 0 +} + func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey *externalapi.ScriptPublicKey) (UTXOOutpointEntryPairs, error) { if uis.isAnythingStaged() { return nil, errors.Errorf("cannot get utxo outpoint entry pairs while staging isn't empty") @@ -266,98 +262,3 @@ func (uis *utxoIndexStore) getUTXOOutpointEntryPairs(scriptPublicKey *externalap } return utxoOutpointEntryPairs, nil } - -func (uis *utxoIndexStore) getLastVirtualSelectedParent() (*externalapi.DomainHash, bool, error) { - if uis.isAnythingStaged() { - return nil, false, errors.Errorf("cannot get last virtual selected parent while staging isn't empty") - } - - hasLastVirtualSelectedParent, err := uis.database.Has(utxoIndexLastVirtualSelectedParentKey) - if err != nil { - return nil, false, err - } - - if !hasLastVirtualSelectedParent { - return nil, false, nil - } - - lastVirtualSelectedParentBytes, err := uis.database.Get(utxoIndexLastVirtualSelectedParentKey) - if err != nil { - return nil, false, err - } - - lastVirtualSelectedParent, err := externalapi.NewDomainHashFromByteSlice(lastVirtualSelectedParentBytes) - if err != nil { - return nil, false, err - } - - return lastVirtualSelectedParent, true, nil -} - -func (uis *utxoIndexStore) isAnythingStaged() bool { - return len(uis.toAdd) > 0 || len(uis.toRemove) > 0 || uis.virtualSelectedParent != nil -} - -func (uis *utxoIndexStore) replaceUTXOSet(utxoSet []*externalapi.OutpointUTXOPair, - virtualSelectedParent *externalapi.DomainHash) error { - - onEnd := logger.LogAndMeasureExecutionTime(log, "utxoIndexStore.replaceUTXOSet") - defer onEnd() - - if uis.isAnythingStaged() { - return errors.Errorf("cannot replace utxo set while something is staged") - } - - err := uis.resetStore() - if err != nil { - return err - } - - uis.virtualSelectedParent = virtualSelectedParent - for i, pair := range utxoSet { - err := uis.add(pair.Entry.ScriptPublicKey(), pair.Outpoint, pair.Entry) - if err != nil { - return err - } - const logInterval = 10_000 - if i%logInterval == 0 { - log.Debugf("Recovered %d UTXO entries out of %d", i+1, len(utxoSet)) - } - } - - return uis.commit() -} - -func (uis *utxoIndexStore) resetStore() error { - onEnd := logger.LogAndMeasureExecutionTime(log, "utxoIndexStore.resetStore") - defer onEnd() - - cursor, err := uis.database.Cursor(utxoIndexBucket) - if err != nil { - return err - } - - keysToDelete := make([]*database.Key, 0) - for cursor.Next() { - key, err := cursor.Key() - if err != nil { - return err - } - - keysToDelete = append(keysToDelete, key) - } - - for _, key := range keysToDelete { - err = uis.database.Delete(key) - if err != nil { - return err - } - } - - err = uis.database.Delete(utxoIndexLastVirtualSelectedParentKey) - if err != nil { - return err - } - - return nil -} diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go index dce226348..1d881f882 100644 --- a/domain/utxoindex/utxoindex.go +++ b/domain/utxoindex/utxoindex.go @@ -7,80 +7,25 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/kaspanet/kaspad/infrastructure/logger" - "github.com/pkg/errors" "sync" ) // UTXOIndex maintains an index between transaction scriptPublicKeys // and UTXOs type UTXOIndex struct { - consensus externalapi.Consensus - store *utxoIndexStore - genesisHash *externalapi.DomainHash + consensus externalapi.Consensus + store *utxoIndexStore mutex sync.Mutex } // New creates a new UTXO index -func New(consensus externalapi.Consensus, database database.Database, genesisHash *externalapi.DomainHash) (*UTXOIndex, error) { +func New(consensus externalapi.Consensus, database database.Database) *UTXOIndex { store := newUTXOIndexStore(database) - utxoIndex := &UTXOIndex{ - consensus: consensus, - store: store, - genesisHash: genesisHash, + return &UTXOIndex{ + consensus: consensus, + store: store, } - - isSynced, err := utxoIndex.isSynced() - if err != nil { - return nil, err - } - - if !isSynced { - err := utxoIndex.recover() - if err != nil { - return nil, err - } - } - - return utxoIndex, nil -} - -func (ui *UTXOIndex) recover() error { - onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.recover") - defer onEnd() - - // Since the RPC and P2P should be down while initializing the - // UTXO index, we can assume that the virtual selected parent - // won't be changed while fetching the virtual selected parent. - virtualSelectedParent, err := ui.consensus.GetVirtualSelectedParent() - if err != nil { - return err - } - - virtualUTXOSet, err := ui.consensus.GetVirtualUTXOSet() - if err != nil { - return err - } - - return ui.store.replaceUTXOSet(virtualUTXOSet, virtualSelectedParent) -} - -func (ui *UTXOIndex) isSynced() (bool, error) { - virtualSelectedParent, err := ui.consensus.GetVirtualSelectedParent() - if err != nil { - return false, err - } - - lastVirtualSelectedParent, hasLastVirtualSelectedParent, err := ui.store.getLastVirtualSelectedParent() - if err != nil { - return false, err - } - - if !hasLastVirtualSelectedParent { - return virtualSelectedParent.Equal(ui.genesisHash), nil - } - - return virtualSelectedParent.Equal(lastVirtualSelectedParent), nil } // Update updates the UTXO index with the given DAG selected parent chain changes @@ -92,17 +37,6 @@ func (ui *UTXOIndex) Update(chainChanges *externalapi.SelectedParentChainChanges defer ui.mutex.Unlock() log.Tracef("Updating UTXO index with chainChanges: %+v", chainChanges) - if len(chainChanges.Added) == 0 { - if len(chainChanges.Removed) != 0 { - return nil, errors.Errorf("len(chainChanges.Added) is 0 while len(chainChanges.Removed) is %d", len(chainChanges.Removed)) - } - - return nil, nil - } - - virtualSelectedParent := chainChanges.Added[len(chainChanges.Added)-1] - ui.store.virtualSelectedParent = virtualSelectedParent - for _, removedBlockHash := range chainChanges.Removed { err := ui.removeBlock(removedBlockHash) if err != nil { From 4577023e44e2e13c584b6a7a3bf7cc33d282cc28 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 6 Jan 2021 11:51:12 +0200 Subject: [PATCH 216/351] Add script pubkey version to signature hash (#1360) * Replace 0xffff with math.MaxUint16 on version checks * Add script version to the signature hash Co-authored-by: Ori Newman --- .../consensus/database/serialization/blockheader.go | 3 ++- .../consensus/database/serialization/transaction.go | 3 ++- domain/consensus/database/serialization/utxo_entry.go | 3 ++- domain/consensus/utils/txscript/engine.go | 10 ++++------ domain/consensus/utils/txscript/opcode.go | 4 ++-- domain/consensus/utils/txscript/script.go | 11 +++++++---- .../server/grpcserver/protowire/p2p_header.go | 3 ++- .../server/grpcserver/protowire/p2p_transaction.go | 5 +++-- .../server/grpcserver/protowire/rpc_get_block.go | 5 +++-- .../grpcserver/protowire/rpc_submit_transaction.go | 5 +++-- 10 files changed, 30 insertions(+), 22 deletions(-) diff --git a/domain/consensus/database/serialization/blockheader.go b/domain/consensus/database/serialization/blockheader.go index 30275c2e2..a98b7732c 100644 --- a/domain/consensus/database/serialization/blockheader.go +++ b/domain/consensus/database/serialization/blockheader.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/pkg/errors" + "math" ) // DomainBlockHeaderToDbBlockHeader converts BlockHeader to DbBlockHeader @@ -38,7 +39,7 @@ func DbBlockHeaderToDomainBlockHeader(dbBlockHeader *DbBlockHeader) (externalapi if err != nil { return nil, err } - if dbBlockHeader.Version > 0xffff { + if dbBlockHeader.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid header version - bigger then uint16") } diff --git a/domain/consensus/database/serialization/transaction.go b/domain/consensus/database/serialization/transaction.go index af8bf77fd..3ac0d16b7 100644 --- a/domain/consensus/database/serialization/transaction.go +++ b/domain/consensus/database/serialization/transaction.go @@ -3,6 +3,7 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" + "math" ) // DomainTransactionToDbTransaction converts DomainTransaction to DbTransaction @@ -73,7 +74,7 @@ func DbTransactionToDomainTransaction(dbTransaction *DbTransaction) (*externalap } } - if dbTransaction.Version > 0xFFFF { + if dbTransaction.Version > math.MaxUint16 { return nil, errors.Errorf("The transaction version is bigger then uint16.") } return &externalapi.DomainTransaction{ diff --git a/domain/consensus/database/serialization/utxo_entry.go b/domain/consensus/database/serialization/utxo_entry.go index d8db65f8b..8dcf68071 100644 --- a/domain/consensus/database/serialization/utxo_entry.go +++ b/domain/consensus/database/serialization/utxo_entry.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/pkg/errors" + "math" ) // ScriptPublicKeyToDBScriptPublicKey converts ScriptPublicKey to DBScriptPublicKey @@ -13,7 +14,7 @@ func ScriptPublicKeyToDBScriptPublicKey(scriptPublicKey *externalapi.ScriptPubli // DBScriptPublicKeyToScriptPublicKey convert DbScriptPublicKey ro ScriptPublicKey func DBScriptPublicKeyToScriptPublicKey(dbScriptPublicKey *DbScriptPublicKey) (*externalapi.ScriptPublicKey, error) { - if dbScriptPublicKey.Version > 0xFFFF { + if dbScriptPublicKey.Version > math.MaxUint16 { return nil, errors.Errorf("The version on ScriptPublicKey is bigger then uint16.") } return &externalapi.ScriptPublicKey{Script: dbScriptPublicKey.Script, Version: uint16(dbScriptPublicKey.Version)}, nil diff --git a/domain/consensus/utils/txscript/engine.go b/domain/consensus/utils/txscript/engine.go index a9d827f89..a6a3bf571 100644 --- a/domain/consensus/utils/txscript/engine.go +++ b/domain/consensus/utils/txscript/engine.go @@ -39,7 +39,7 @@ const ( // Engine is the virtual machine that executes scripts. type Engine struct { - isKnownVersion bool + scriptVersion uint16 scripts [][]parsedOpcode scriptIdx int scriptOff int @@ -315,7 +315,7 @@ func (vm *Engine) Step() (done bool, err error) { // Execute will execute all scripts in the script engine and return either nil // for successful validation or an error if one occurred. func (vm *Engine) Execute() (err error) { - if !vm.isKnownVersion { + if vm.scriptVersion > constants.MaxScriptPublicKeyVersion { log.Tracef("The version of the scriptPublicKey is higher than the known version - the Execute function returns true.") return nil } @@ -454,13 +454,11 @@ func NewEngine(scriptPubKey *externalapi.ScriptPublicKey, tx *externalapi.Domain return nil, scriptError(ErrEvalFalse, "false stack entry at end of script execution") } - vm := Engine{flags: flags, sigCache: sigCache} + vm := Engine{scriptVersion: scriptPubKey.Version, flags: flags, sigCache: sigCache} - if scriptPubKey.Version > constants.MaxScriptPublicKeyVersion { - vm.isKnownVersion = false + if vm.scriptVersion > constants.MaxScriptPublicKeyVersion { return &vm, nil } - vm.isKnownVersion = true parsedScriptSig, err := parseScriptAndVerifySize(scriptSig) if err != nil { return nil, err diff --git a/domain/consensus/utils/txscript/opcode.go b/domain/consensus/utils/txscript/opcode.go index 9706dca98..a0f8f0225 100644 --- a/domain/consensus/utils/txscript/opcode.go +++ b/domain/consensus/utils/txscript/opcode.go @@ -2034,7 +2034,7 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error { script := vm.currentScript() // Generate the signature hash based on the signature hash type. - sigHash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx) + sigHash, err := calcSignatureHash(script, vm.scriptVersion, hashType, &vm.tx, vm.txIdx) if err != nil { vm.dstack.PushBool(false) return nil @@ -2241,7 +2241,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { } // Generate the signature hash based on the signature hash type. - sigHash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx) + sigHash, err := calcSignatureHash(script, vm.scriptVersion, hashType, &vm.tx, vm.txIdx) if err != nil { return err } diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index 683b182b3..a65aa1037 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -6,6 +6,7 @@ package txscript import ( "bytes" + "encoding/binary" "fmt" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" @@ -295,13 +296,13 @@ func CalcSignatureHash(script *externalapi.ScriptPublicKey, hashType SigHashType if err != nil { return nil, errors.Errorf("cannot parse output script: %s", err) } - return calcSignatureHash(parsedScript, hashType, tx, idx) + return calcSignatureHash(parsedScript, script.Version, hashType, tx, idx) } // calcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. -func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *externalapi.DomainTransaction, idx int) (*externalapi.DomainHash, error) { +func calcSignatureHash(prevScriptPublicKey []parsedOpcode, scriptVersion uint16, hashType SigHashType, tx *externalapi.DomainTransaction, idx int) (*externalapi.DomainHash, error) { // The SigHashSingle signature type signs only the corresponding input // and output (the output with the same index number as the input). // @@ -320,8 +321,10 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *external if i == idx { // UnparseScript cannot fail here because removeOpcode // above only returns a valid script. - sigScript, _ := unparseScript(script) - txCopy.Inputs[idx].SignatureScript = sigScript + sigScript, _ := unparseScript(prevScriptPublicKey) + var version [2]byte + binary.LittleEndian.PutUint16(version[:], scriptVersion) + txCopy.Inputs[idx].SignatureScript = append(version[:], sigScript...) } else { txCopy.Inputs[i].SignatureScript = nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go index b9072ddc0..992830996 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_header.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" + "math" ) func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) { @@ -31,7 +32,7 @@ func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) if err != nil { return nil, err } - if x.Version > 0xffff { + if x.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid block header version - bigger then uint16") } return &appmessage.MsgBlockHeader{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go index cf92ffe26..420d3503d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_transaction.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" + "math" ) func (x *KaspadMessage_Transaction) toAppMessage() (appmessage.Message, error) { @@ -30,7 +31,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { outputs := make([]*appmessage.TxOut, len(x.Outputs)) for i, protoOutput := range x.Outputs { - if protoOutput.ScriptPublicKey.Version > 0xFFFF { + if protoOutput.ScriptPublicKey.Version > math.MaxUint16 { return nil, errors.Errorf("The version on ScriptPublicKey is bigger then uint16.") } outputs[i] = &appmessage.TxOut{ @@ -55,7 +56,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) { return nil, err } } - if x.Version > 0xffff { + if x.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid transaction version - bigger then uint16") } return &appmessage.MsgTx{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go index 27e899a67..906598300 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go @@ -3,6 +3,7 @@ package protowire import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/pkg/errors" + "math" ) func (x *KaspadMessage_GetBlockRequest) toAppMessage() (appmessage.Message, error) { @@ -72,7 +73,7 @@ func (x *BlockVerboseData) toAppMessage() (*appmessage.BlockVerboseData, error) transactionVerboseData[i] = appTransactionVerboseDatum } - if x.Version > 0xffff { + if x.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid block header version - bigger then uint16") } @@ -154,7 +155,7 @@ func (x *TransactionVerboseData) toAppMessage() (*appmessage.TransactionVerboseD ScriptPubKey: scriptPubKey, } } - if x.Version > 0xffff { + if x.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid transaction version - bigger then uint16") } return &appmessage.TransactionVerboseData{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go index f52ef0877..926d019a4 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_transaction.go @@ -3,6 +3,7 @@ package protowire import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/pkg/errors" + "math" ) func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) { @@ -71,7 +72,7 @@ func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) { } } - if x.Version > 0xffff { + if x.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid RPC txn version - bigger then uint16") } @@ -89,7 +90,7 @@ func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) { // ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey converts from RpcScriptPubKey to RPCScriptPublicKey. func ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey(toConvert *RpcScriptPublicKey) (*appmessage.RPCScriptPublicKey, error) { - if toConvert.Version > 0xffff { + if toConvert.Version > math.MaxUint16 { return nil, errors.Errorf("Invalid header version - bigger then uint16") } version := uint16(toConvert.Version) From a04a5462aea7fafd4203d0523e5936747881710d Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 6 Jan 2021 12:50:27 +0200 Subject: [PATCH 217/351] Update devnet genesis with older timestamp (#1364) * Update devnet genesis with older timestamp * Update BlueWindow test for new genesis --- .../dagtraversalmanager/window_test.go | 18 +++++++++--------- domain/dagconfig/genesis.go | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index d1faec258..cabcfde43 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -182,12 +182,12 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"C", "D"}, id: "E", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"C", "D"}, id: "F", - expectedWindowWithGenesisPadding: []string{"D", "C", "B", "A", "A", "A", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"C", "D", "B", "A", "A", "A", "A", "A", "A", "A"}, }, { parents: []string{"A"}, @@ -202,37 +202,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "D", "H", "C", "B", "G", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "H", "C", "D", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "D", "H", "C", "B", "G", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "H", "C", "D", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "D", "H", "C", "B", "G", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "C", "D", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "C", "D", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "C", "D", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"}, }, }, "kaspa-simnet": { diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index 62dfbf5ca..b27189c00 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -82,10 +82,10 @@ var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x7a, 0x45, 0xc7, 0x1e, 0x75, 0x91, 0x82, 0x7a, - 0x0f, 0x97, 0xfb, 0x20, 0x35, 0x22, 0x7c, 0x54, - 0xc2, 0x34, 0x4c, 0xc4, 0x85, 0x45, 0xcb, 0xfb, - 0x04, 0x3b, 0x2e, 0x55, 0x63, 0xcb, 0x38, 0xde, + 0x86, 0xd8, 0x94, 0xee, 0x2f, 0x73, 0x62, 0xbd, + 0x8d, 0xa9, 0x5a, 0x2b, 0x45, 0x91, 0xb9, 0x65, + 0xcc, 0x7f, 0x0d, 0xf9, 0x5d, 0x20, 0x3f, 0xf4, + 0x92, 0x37, 0xc2, 0x15, 0xf3, 0x9c, 0x8c, 0x2d, }) // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -106,9 +106,9 @@ var devnetGenesisBlock = externalapi.DomainBlock{ devnetGenesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x176c903cecd, + 0x11e9db49828, 0x1e7fffff, - 0x3bc1, + 0x20a4f, ), Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } From 9ea4c0fa38809da9efc364b40c7313ef26cc791f Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 6 Jan 2021 13:27:02 +0200 Subject: [PATCH 218/351] Add sanity check that makes sure that the utxoset that we save fits the pruningPoints's commitment. (#1366) Co-authored-by: Elichai Turkel --- domain/consensus/factory.go | 1 + .../consensusstatemanager/multisets.go | 9 ---- .../update_pruning_utxo_set.go | 2 +- .../pruningmanager/pruningmanager.go | 49 +++++++++++++++++-- .../utils/utxoserialization/multiset.go | 15 ++++++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 domain/consensus/utils/utxoserialization/multiset.go diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index dec61335c..807455522 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -234,6 +234,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat multisetStore, acceptanceDataStore, blockStore, + blockHeaderStore, utxoDiffStore, genesisHash, dagParams.FinalityDepth(), diff --git a/domain/consensus/processes/consensusstatemanager/multisets.go b/domain/consensus/processes/consensusstatemanager/multisets.go index 8099ed49b..5960dcc14 100644 --- a/domain/consensus/processes/consensusstatemanager/multisets.go +++ b/domain/consensus/processes/consensusstatemanager/multisets.go @@ -6,7 +6,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" ) func (csm *consensusStateManager) calculateMultiset( @@ -107,11 +106,3 @@ func removeUTXOFromMultiset(multiset model.Multiset, entry externalapi.UTXOEntry return nil } - -func calcMultisetFromProtoUTXOSet(protoUTXOSet *utxoserialization.ProtoUTXOSet) (model.Multiset, error) { - ms := multiset.New() - for _, utxo := range protoUTXOSet.Utxos { - ms.Add(utxo.EntryOutpointPair) - } - return ms, nil -} diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index f20d9a215..5ecdb16d3 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -51,7 +51,7 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap return err } - utxoSetMultiSet, err := calcMultisetFromProtoUTXOSet(protoUTXOSet) + utxoSetMultiSet, err := utxoserialization.CalculateMultisetFromProtoUTXOSet(protoUTXOSet) if err != nil { return err } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 883d4453a..7fb43d826 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" ) // pruningManager resolves and manages the current pruning point @@ -24,6 +25,7 @@ type pruningManager struct { multiSetStore model.MultisetStore acceptanceDataStore model.AcceptanceDataStore blocksStore model.BlockStore + blockHeaderStore model.BlockHeaderStore utxoDiffStore model.UTXODiffStore genesisHash *externalapi.DomainHash @@ -47,6 +49,7 @@ func New( multiSetStore model.MultisetStore, acceptanceDataStore model.AcceptanceDataStore, blocksStore model.BlockStore, + blockHeaderStore model.BlockHeaderStore, utxoDiffStore model.UTXODiffStore, genesisHash *externalapi.DomainHash, @@ -66,6 +69,7 @@ func New( multiSetStore: multiSetStore, acceptanceDataStore: acceptanceDataStore, blocksStore: blocksStore, + blockHeaderStore: blockHeaderStore, utxoDiffStore: utxoDiffStore, headerSelectedTipStore: headerSelectedTipStore, genesisHash: genesisHash, @@ -297,19 +301,20 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) return nil } -func (pm *pruningManager) savePruningPoint(blockHash *externalapi.DomainHash) error { +func (pm *pruningManager) savePruningPoint(pruningPointHash *externalapi.DomainHash) error { onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.savePruningPoint") defer onEnd() - utxoIter, err := pm.consensusStateManager.RestorePastUTXOSetIterator(blockHash) + utxoIter, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPointHash) if err != nil { return err } - serializedUtxo, err := serializeUTXOSetIterator(utxoIter) + + serializedUtxo, err := pm.calculateAndValidateSerializedUTXOSet(utxoIter, pruningPointHash) if err != nil { return err } - pm.pruningStore.StagePruningPoint(blockHash, serializedUtxo) + pm.pruningStore.StagePruningPoint(pruningPointHash, serializedUtxo) return nil } @@ -396,14 +401,48 @@ func (pm *pruningManager) pruningPointCandidate() (*externalapi.DomainHash, erro return pm.pruningStore.PruningPointCandidate(pm.databaseContext) } -func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error) { +func (pm *pruningManager) calculateAndValidateSerializedUTXOSet( + iter model.ReadOnlyUTXOSetIterator, pruningPointHash *externalapi.DomainHash) ([]byte, error) { + serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter) if err != nil { return nil, err } + + err = pm.validateUTXOSetFitsCommitment(serializedUtxo, pruningPointHash) + if err != nil { + return nil, err + } + return proto.Marshal(serializedUtxo) } +// validateUTXOSetFitsCommitment makes sure that the calculated UTXOSet of the new pruning point fits the commitment. +// This is a sanity test, to make sure that kaspad doesn't store, and subsequently sends syncing peers the wrong UTXOSet. +func (pm *pruningManager) validateUTXOSetFitsCommitment( + serializedUtxo *utxoserialization.ProtoUTXOSet, pruningPointHash *externalapi.DomainHash) error { + + utxoSetMultiSet, err := utxoserialization.CalculateMultisetFromProtoUTXOSet(serializedUtxo) + if err != nil { + return err + } + utxoSetHash := utxoSetMultiSet.Hash() + + header, err := pm.blockHeaderStore.BlockHeader(pm.databaseContext, pruningPointHash) + if err != nil { + return err + } + expectedUTXOCommitment := header.UTXOCommitment() + + if !expectedUTXOCommitment.Equal(utxoSetHash) { + return errors.Errorf("Calculated UTXOSet for next pruning point %s doesn't match it's UTXO commitment\n"+ + "Calculated UTXOSet hash: %s. Commitment: %s", + pruningPointHash, utxoSetHash, expectedUTXOCommitment) + } + + return nil +} + // finalityScore is the number of finality intervals passed since // the given block. func (pm *pruningManager) finalityScore(blueScore uint64) uint64 { diff --git a/domain/consensus/utils/utxoserialization/multiset.go b/domain/consensus/utils/utxoserialization/multiset.go new file mode 100644 index 000000000..6e62cd0f7 --- /dev/null +++ b/domain/consensus/utils/utxoserialization/multiset.go @@ -0,0 +1,15 @@ +package utxoserialization + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" +) + +// CalculateMultisetFromProtoUTXOSet calculates the Multiset corresponding to the given ProtuUTXOSet +func CalculateMultisetFromProtoUTXOSet(protoUTXOSet *ProtoUTXOSet) (model.Multiset, error) { + ms := multiset.New() + for _, utxo := range protoUTXOSet.Utxos { + ms.Add(utxo.EntryOutpointPair) + } + return ms, nil +} From 26368cd6747c2d4996ac76006ade91081c8c389c Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Wed, 6 Jan 2021 14:04:46 +0200 Subject: [PATCH 219/351] Update to version 0.8.5 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index da43a4ed4..b71a37827 100644 --- a/version/version.go +++ b/version/version.go @@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 appMinor uint = 8 - appPatch uint = 4 + appPatch uint = 5 ) // appBuild is defined as a variable so it can be overridden during the build From 4ad89056c234ca12bfc94772f727be5985d732ca Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 6 Jan 2021 17:26:21 +0200 Subject: [PATCH 220/351] Implement getMempoolEntries (#1369) * Implement getMempoolEntries * Fix comment * Fix comment --- app/rpc/rpchandlers/get_mempool_entries.go | 21 ++++++++++++++++--- .../blocktemplatebuilder.go | 2 +- domain/miningmanager/mempool/mempool.go | 20 ++++++++++++++++-- domain/miningmanager/miningmanager.go | 5 +++++ .../miningmanager/model/interface_mempool.go | 3 ++- 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/app/rpc/rpchandlers/get_mempool_entries.go b/app/rpc/rpchandlers/get_mempool_entries.go index 79b43062d..7aa534635 100644 --- a/app/rpc/rpchandlers/get_mempool_entries.go +++ b/app/rpc/rpchandlers/get_mempool_entries.go @@ -3,12 +3,27 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) // HandleGetMempoolEntries handles the respectively named RPC command func HandleGetMempoolEntries(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { - response := &appmessage.GetMempoolEntriesResponseMessage{} - response.Error = appmessage.RPCErrorf("not implemented") - return response, nil + + transactions := context.Domain.MiningManager().AllTransactions() + entries := make([]*appmessage.MempoolEntry, 0, len(transactions)) + for _, tx := range transactions { + transactionVerboseData, err := context.BuildTransactionVerboseData( + tx, consensushashing.TransactionID(tx).String(), nil, "") + if err != nil { + return nil, err + } + + entries = append(entries, &appmessage.MempoolEntry{ + Fee: tx.Fee, + TransactionVerboseData: transactionVerboseData, + }) + } + + return appmessage.NewGetMempoolEntriesResponseMessage(entries), nil } diff --git a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go index 55906375d..18d74c12a 100644 --- a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go +++ b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go @@ -105,7 +105,7 @@ func New(consensus consensusexternalapi.Consensus, mempool miningmanagerapi.Memp // ----------------------------------- -- func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) { - mempoolTransactions := btb.mempool.Transactions() + mempoolTransactions := btb.mempool.BlockCandidateTransactions() candidateTxs := make([]*candidateTx, 0, len(mempoolTransactions)) for _, tx := range mempoolTransactions { // Calculate the tx value diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index fb973be44..fe06cd61a 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -125,6 +125,22 @@ func (mp *mempool) GetTransaction( return txDesc.DomainTransaction, true } +func (mp *mempool) AllTransactions() []*consensusexternalapi.DomainTransaction { + mp.mtx.RLock() + defer mp.mtx.RUnlock() + + transactions := make([]*consensusexternalapi.DomainTransaction, 0, len(mp.pool)+len(mp.chainedTransactions)) + for _, txDesc := range mp.pool { + transactions = append(transactions, txDesc.DomainTransaction) + } + + for _, txDesc := range mp.chainedTransactions { + transactions = append(transactions, txDesc.DomainTransaction) + } + + return transactions +} + // txDescriptor is a descriptor containing a transaction in the mempool along with // additional metadata. type txDescriptor struct { @@ -841,9 +857,9 @@ func (mp *mempool) ChainedCount() int { return len(mp.chainedTransactions) } -// Transactions returns a slice of all the transactions in the block +// BlockCandidateTransactions returns a slice of all the candidate transactions for the next block // This is safe for concurrent use -func (mp *mempool) Transactions() []*consensusexternalapi.DomainTransaction { +func (mp *mempool) BlockCandidateTransactions() []*consensusexternalapi.DomainTransaction { mp.mtx.RLock() defer mp.mtx.RUnlock() descs := make([]*consensusexternalapi.DomainTransaction, len(mp.pool)) diff --git a/domain/miningmanager/miningmanager.go b/domain/miningmanager/miningmanager.go index 82b66a1ef..5c5ab59f7 100644 --- a/domain/miningmanager/miningmanager.go +++ b/domain/miningmanager/miningmanager.go @@ -10,6 +10,7 @@ import ( type MiningManager interface { GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) + AllTransactions() []*consensusexternalapi.DomainTransaction HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error } @@ -41,3 +42,7 @@ func (mm *miningManager) GetTransaction( return mm.mempool.GetTransaction(transactionID) } + +func (mm *miningManager) AllTransactions() []*consensusexternalapi.DomainTransaction { + return mm.mempool.AllTransactions() +} diff --git a/domain/miningmanager/model/interface_mempool.go b/domain/miningmanager/model/interface_mempool.go index 20bb8ff37..c49be4f96 100644 --- a/domain/miningmanager/model/interface_mempool.go +++ b/domain/miningmanager/model/interface_mempool.go @@ -8,8 +8,9 @@ import ( // are intended to be mined into new blocks type Mempool interface { HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction - Transactions() []*consensusexternalapi.DomainTransaction + BlockCandidateTransactions() []*consensusexternalapi.DomainTransaction ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) + AllTransactions() []*consensusexternalapi.DomainTransaction } From b195301a996a9a37efbfb1ee9620836382d2d9c9 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 6 Jan 2021 17:33:51 +0200 Subject: [PATCH 221/351] Add IsIBDPeer to GetConnectedPeerInfoResponse. (#1367) Co-authored-by: Ori Newman --- app/appmessage/rpc_get_connected_peer_info.go | 1 + app/protocol/flowcontext/blocks.go | 40 +- app/protocol/flowcontext/flow_context.go | 3 +- .../flows/blockrelay/handle_relay_invs.go | 2 +- app/protocol/flows/blockrelay/ibd.go | 2 +- app/protocol/manager.go | 6 + .../rpchandlers/get_connected_peer_info.go | 2 + .../grpcserver/protowire/messages.pb.go | 910 +++++++++--------- .../grpcserver/protowire/messages.proto | 1 + .../protowire/rpc_get_connected_peer_info.go | 2 + 10 files changed, 506 insertions(+), 463 deletions(-) diff --git a/app/appmessage/rpc_get_connected_peer_info.go b/app/appmessage/rpc_get_connected_peer_info.go index 3bb4cbc38..84b55d6f1 100644 --- a/app/appmessage/rpc_get_connected_peer_info.go +++ b/app/appmessage/rpc_get_connected_peer_info.go @@ -46,4 +46,5 @@ type GetConnectedPeerInfoMessage struct { UserAgent string AdvertisedProtocolVersion uint32 TimeConnected int64 + IsIBDPeer bool } diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 657221669..d229a8748 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -1,9 +1,8 @@ package flowcontext import ( - "sync/atomic" - "github.com/kaspanet/kaspad/app/protocol/blocklogger" + peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/pkg/errors" @@ -115,24 +114,45 @@ func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error { // IsIBDRunning returns true if IBD is currently marked as running func (f *FlowContext) IsIBDRunning() bool { - return atomic.LoadUint32(&f.isInIBD) != 0 + f.ibdPeerMutex.RLock() + defer f.ibdPeerMutex.RUnlock() + + return f.ibdPeer != nil } // TrySetIBDRunning attempts to set `isInIBD`. Returns false // if it is already set -func (f *FlowContext) TrySetIBDRunning() bool { - succeeded := atomic.CompareAndSwapUint32(&f.isInIBD, 0, 1) - if succeeded { - log.Infof("IBD started") +func (f *FlowContext) TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool { + f.ibdPeerMutex.Lock() + defer f.ibdPeerMutex.Unlock() + + if f.ibdPeer != nil { + return false } - return succeeded + f.ibdPeer = ibdPeer + log.Infof("IBD started") + + return true } // UnsetIBDRunning unsets isInIBD func (f *FlowContext) UnsetIBDRunning() { - succeeded := atomic.CompareAndSwapUint32(&f.isInIBD, 1, 0) - if !succeeded { + f.ibdPeerMutex.Lock() + defer f.ibdPeerMutex.Unlock() + + if f.ibdPeer == nil { panic("attempted to unset isInIBD when it was not set to begin with") } + + f.ibdPeer = nil log.Infof("IBD finished") } + +// IBDPeer returns the current IBD peer or null if the node is not +// in IBD +func (f *FlowContext) IBDPeer() *peerpkg.Peer { + f.ibdPeerMutex.RLock() + defer f.ibdPeerMutex.RUnlock() + + return f.ibdPeer +} diff --git a/app/protocol/flowcontext/flow_context.go b/app/protocol/flowcontext/flow_context.go index 2af8e5f86..68a899299 100644 --- a/app/protocol/flowcontext/flow_context.go +++ b/app/protocol/flowcontext/flow_context.go @@ -48,7 +48,8 @@ type FlowContext struct { sharedRequestedBlocks *blockrelay.SharedRequestedBlocks - isInIBD uint32 + ibdPeer *peerpkg.Peer + ibdPeerMutex sync.RWMutex peers map[id.ID]*peerpkg.Peer peersMutex sync.RWMutex diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 8b91c5788..3c383d5db 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -31,7 +31,7 @@ type RelayInvsContext interface { AddOrphan(orphanBlock *externalapi.DomainBlock) IsOrphan(blockHash *externalapi.DomainHash) bool IsIBDRunning() bool - TrySetIBDRunning() bool + TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool UnsetIBDRunning() } diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 8ff8a9c36..5cf96cefc 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -13,7 +13,7 @@ import ( ) func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.DomainHash) error { - wasIBDNotRunning := flow.TrySetIBDRunning() + wasIBDNotRunning := flow.TrySetIBDRunning(flow.peer) if !wasIBDNotRunning { log.Debugf("IBD is already running") return nil diff --git a/app/protocol/manager.go b/app/protocol/manager.go index 59a9b5267..102f3dcf0 100644 --- a/app/protocol/manager.go +++ b/app/protocol/manager.go @@ -37,6 +37,12 @@ func (m *Manager) Peers() []*peerpkg.Peer { return m.context.Peers() } +// IBDPeer returns the current IBD peer or null if the node is not +// in IBD +func (m *Manager) IBDPeer() *peerpkg.Peer { + return m.context.IBDPeer() +} + // AddTransaction adds transaction to the mempool and propagates it. func (m *Manager) AddTransaction(tx *externalapi.DomainTransaction) error { return m.context.AddTransaction(tx) diff --git a/app/rpc/rpchandlers/get_connected_peer_info.go b/app/rpc/rpchandlers/get_connected_peer_info.go index e16696e00..37e690b09 100644 --- a/app/rpc/rpchandlers/get_connected_peer_info.go +++ b/app/rpc/rpchandlers/get_connected_peer_info.go @@ -9,6 +9,7 @@ import ( // HandleGetConnectedPeerInfo handles the respectively named RPC command func HandleGetConnectedPeerInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { peers := context.ProtocolManager.Peers() + ibdPeer := context.ProtocolManager.IBDPeer() infos := make([]*appmessage.GetConnectedPeerInfoMessage, 0, len(peers)) for _, peer := range peers { info := &appmessage.GetConnectedPeerInfoMessage{ @@ -20,6 +21,7 @@ func HandleGetConnectedPeerInfo(context *rpccontext.Context, _ *router.Router, _ UserAgent: peer.UserAgent(), AdvertisedProtocolVersion: peer.AdvertisedProtocolVersion(), TimeConnected: peer.TimeConnected().Milliseconds(), + IsIBDPeer: peer == ibdPeer, } infos = append(infos, info) } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index e947ab80c..d53f785f7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -4386,6 +4386,7 @@ type GetConnectedPeerInfoMessage struct { UserAgent string `protobuf:"bytes,8,opt,name=userAgent,proto3" json:"userAgent,omitempty"` AdvertisedProtocolVersion uint32 `protobuf:"varint,9,opt,name=advertisedProtocolVersion,proto3" json:"advertisedProtocolVersion,omitempty"` TimeConnected int64 `protobuf:"varint,10,opt,name=timeConnected,proto3" json:"timeConnected,omitempty"` + IsIbdPeer bool `protobuf:"varint,11,opt,name=isIbdPeer,proto3" json:"isIbdPeer,omitempty"` } func (x *GetConnectedPeerInfoMessage) Reset() { @@ -4476,6 +4477,13 @@ func (x *GetConnectedPeerInfoMessage) GetTimeConnected() int64 { return 0 } +func (x *GetConnectedPeerInfoMessage) GetIsIbdPeer() bool { + if x != nil { + return x.IsIbdPeer + } + return false +} + type AddPeerRequestMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -8553,7 +8561,7 @@ var file_messages_proto_rawDesc = []byte{ 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xb5, 0x02, + 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xd3, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, @@ -8573,468 +8581,470 @@ var file_messages_proto_rawDesc = []byte{ 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, - 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, - 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, - 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, - 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, - 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, - 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, 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, 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, 0xdb, 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, 0x0d, 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, - 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, - 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 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, 0x0d, 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, 0x92, 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 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, - 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, 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, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, + 0x65, 0x65, 0x72, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, + 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, + 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, + 0x65, 0x65, 0x72, 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, + 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x5e, + 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, + 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, + 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, - 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, - 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, - 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, - 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, - 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, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, - 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, - 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, - 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, - 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, - 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, - 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, - 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, - 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x72, 0x6f, 0x72, 0x22, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, + 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, - 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, + 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, + 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, + 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 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, 0x0d, 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, 0x92, 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, 0x4a, + 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 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, + 0x65, 0x6e, 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, 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, - 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, + 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, + 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, + 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, + 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, + 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, + 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, + 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, + 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, + 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 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, 0x82, 0x01, + 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, - 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x32, 0x50, 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x49, 0x0a, 0x0d, 0x4d, + 0x72, 0x65, 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, 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, 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, + 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 236c89af1..5d8913a64 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -447,6 +447,7 @@ message GetConnectedPeerInfoMessage{ string userAgent = 8; uint32 advertisedProtocolVersion = 9; int64 timeConnected = 10; + bool isIbdPeer = 11; } message AddPeerRequestMessage{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go index 17f9621d2..484c6a229 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_connected_peer_info.go @@ -28,6 +28,7 @@ func (x *KaspadMessage_GetConnectedPeerInfoResponse) toAppMessage() (appmessage. UserAgent: info.UserAgent, AdvertisedProtocolVersion: info.AdvertisedProtocolVersion, TimeConnected: info.TimeOffset, + IsIBDPeer: info.IsIbdPeer, } } return &appmessage.GetConnectedPeerInfoResponseMessage{ @@ -52,6 +53,7 @@ func (x *KaspadMessage_GetConnectedPeerInfoResponse) fromAppMessage(message *app UserAgent: info.UserAgent, AdvertisedProtocolVersion: info.AdvertisedProtocolVersion, TimeConnected: info.TimeOffset, + IsIbdPeer: info.IsIBDPeer, } } x.GetConnectedPeerInfoResponse = &GetConnectedPeerInfoResponseMessage{ From 79c5d4595e39d887f452da6f607f896bb45acea6 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 7 Jan 2021 10:00:13 +0200 Subject: [PATCH 222/351] Remove gencerts (#1371) --- cmd/gencerts/gencerts.go | 104 --------------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 cmd/gencerts/gencerts.go diff --git a/cmd/gencerts/gencerts.go b/cmd/gencerts/gencerts.go deleted file mode 100644 index 93a08842b..000000000 --- a/cmd/gencerts/gencerts.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2013-2014 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package main - -import ( - "fmt" - "github.com/pkg/errors" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - flags "github.com/jessevdk/go-flags" - "github.com/kaspanet/kaspad/util" -) - -type config struct { - Directory string `short:"d" long:"directory" description:"Directory to write certificate pair"` - Years int `short:"y" long:"years" description:"How many years a certificate is valid for"` - Organization string `short:"o" long:"org" description:"Organization in certificate"` - ExtraHosts []string `short:"H" long:"host" description:"Additional hosts/IPs to create certificate for"` - Force bool `short:"f" long:"force" description:"Force overwriting of any old certs and keys"` -} - -func main() { - cfg := config{ - Years: 10, - Organization: "gencerts", - } - parser := flags.NewParser(&cfg, flags.Default) - _, err := parser.Parse() - if err != nil { - var flagsErr *flags.Error - if ok := errors.As(err, &flagsErr); !ok || flagsErr.Type != flags.ErrHelp { - parser.WriteHelp(os.Stderr) - } - return - } - - if cfg.Directory == "" { - var err error - cfg.Directory, err = os.Getwd() - if err != nil { - fmt.Fprintf(os.Stderr, "no directory specified and cannot get working directory\n") - os.Exit(1) - } - } - cfg.Directory = cleanAndExpandPath(cfg.Directory) - certFile := filepath.Join(cfg.Directory, "rpc.cert") - keyFile := filepath.Join(cfg.Directory, "rpc.key") - - if !cfg.Force { - if fileExists(certFile) || fileExists(keyFile) { - fmt.Fprintf(os.Stderr, "%s: certificate and/or key files exist; use -f to force\n", cfg.Directory) - os.Exit(1) - } - } - - validUntil := time.Now().Add(time.Duration(cfg.Years) * 365 * 24 * time.Hour) - cert, key, err := util.NewTLSCertPair(cfg.Organization, validUntil, cfg.ExtraHosts) - if err != nil { - fmt.Fprintf(os.Stderr, "cannot generate certificate pair: %s\n", err) - os.Exit(1) - } - - // Write cert and key files. - if err = ioutil.WriteFile(certFile, cert, 0666); err != nil { - fmt.Fprintf(os.Stderr, "cannot write cert: %s\n", err) - os.Exit(1) - } - if err = ioutil.WriteFile(keyFile, key, 0600); err != nil { - os.Remove(certFile) - fmt.Fprintf(os.Stderr, "cannot write key: %s\n", err) - os.Exit(1) - } -} - -// cleanAndExpandPath expands environement variables and leading ~ in the -// passed path, cleans the result, and returns it. -func cleanAndExpandPath(path string) string { - // Expand initial ~ to OS specific home directory. - if strings.HasPrefix(path, "~") { - appHomeDir := util.AppDataDir("gencerts", false) - homeDir := filepath.Dir(appHomeDir) - path = strings.Replace(path, "~", homeDir, 1) - } - - // NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%, - // but they variables can still be expanded via POSIX-style $VARIABLE. - return filepath.Clean(os.ExpandEnv(path)) -} - -// filesExists reports whether the named file or directory exists. -func fileExists(name string) bool { - if _, err := os.Stat(name); err != nil { - if os.IsNotExist(err) { - return false - } - } - return true -} From 82d95c59a31c5f68f7ac48899806006f14088dab Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 7 Jan 2021 11:17:13 +0200 Subject: [PATCH 223/351] Increase log files sizes (#1374) --- infrastructure/logger/logger.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/logger/logger.go b/infrastructure/logger/logger.go index 0776fb79d..28a221cbd 100644 --- a/infrastructure/logger/logger.go +++ b/infrastructure/logger/logger.go @@ -159,7 +159,8 @@ var subsystemLoggers = map[string]*Logger{ // InitLog attaches log file and error log file to the backend log. func InitLog(logFile, errLogFile string) { - err := BackendLog.AddLogFileWithCustomRotator(logFile, LevelTrace, 100*1024, 4) + // 250 MB (MB=1000^2 bytes) + err := BackendLog.AddLogFileWithCustomRotator(logFile, LevelTrace, 1000*250, 32) if err != nil { fmt.Fprintf(os.Stderr, "Error adding log file %s as log rotator for level %s: %s", logFile, LevelTrace, err) os.Exit(1) From 256b7f25f1650699de2a9d480b2e2f085e4377d7 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 7 Jan 2021 16:26:37 +0200 Subject: [PATCH 224/351] Decrease grpc client dial timeout to one second (#1378) --- infrastructure/network/rpcclient/grpcclient/grpcclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/network/rpcclient/grpcclient/grpcclient.go b/infrastructure/network/rpcclient/grpcclient/grpcclient.go index a517e5704..800c609ac 100644 --- a/infrastructure/network/rpcclient/grpcclient/grpcclient.go +++ b/infrastructure/network/rpcclient/grpcclient/grpcclient.go @@ -24,7 +24,7 @@ type GRPCClient struct { // Connect connects to the RPC server with the given address func Connect(address string) (*GRPCClient, error) { - const dialTimeout = 30 * time.Second + const dialTimeout = 1 * time.Second ctx, cancel := context.WithTimeout(context.Background(), dialTimeout) defer cancel() From 541205904ee37a49ebc1cc6d42062b9756e5c1f3 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 7 Jan 2021 16:55:47 +0200 Subject: [PATCH 225/351] Add RPC documentation (#1379) * Split messages.proto to p2p and rpc. * Split messages.proto to p2p and rpc. * Write a short intro to the RPC docs. * Start documenting RPC calls. * Use a custom protoc-gen-doc. * Continue writing RPC documentation. * Finish writing RPC documentation. * Fix a formatting error. * Fix merge errors. * Fix formatting into protowire/README.md. * Rerun go generate .. Co-authored-by: Ori Newman --- .../server/grpcserver/protowire/README.md | 12 +- .../server/grpcserver/protowire/generate.go | 2 +- .../grpcserver/protowire/messages.pb.go | 10128 ++-------------- .../grpcserver/protowire/messages.proto | 653 +- .../server/grpcserver/protowire/p2p.pb.go | 2843 +++++ .../server/grpcserver/protowire/p2p.proto | 237 + .../server/grpcserver/protowire/rpc.md | 927 ++ .../server/grpcserver/protowire/rpc.pb.go | 6184 ++++++++++ .../server/grpcserver/protowire/rpc.proto | 529 + 9 files changed, 11469 insertions(+), 10046 deletions(-) create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/README.md b/infrastructure/network/netadapter/server/grpcserver/protowire/README.md index e48911c74..eb4a0d355 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/README.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/README.md @@ -1,7 +1,15 @@ protowire ========= -1. Download and place in your PATH: https://github.com/protocolbuffers/protobuf/releases/download/v3.12.3/protoc-3.12.3-linux-x86_64.zip +1. Download and place in your PATH: + https://github.com/protocolbuffers/protobuf/releases/download/v3.12.3/protoc-3.12.3-linux-x86_64.zip 2. `go get github.com/golang/protobuf/protoc-gen-go` 3. `go get google.golang.org/grpc/cmd/protoc-gen-go-grpc` -4. In the protowire directory: `go generate .` \ No newline at end of file +4. In the protowire directory: `go generate .` + +Documentation +------------- + +To generate `rpc.md`: +1. `go get -u github.com/kaspanet/protoc-gen-doc/cmd/protoc-gen-doc` +2. In the protowire directory: `protoc --doc_out=. --doc_opt=markdown,rpc.md rpc.proto` diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/generate.go b/infrastructure/network/netadapter/server/grpcserver/protowire/generate.go index 5f4ea81d0..03b5ba749 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/generate.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/generate.go @@ -1,3 +1,3 @@ -//go:generate protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative messages.proto +//go:generate protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative p2p.proto rpc.proto messages.proto package protowire diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index d53f785f7..a3f05bb7f 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -1295,7756 +1295,583 @@ func (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) isKasp func (*KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) isKaspadMessage_Payload() {} -// RequestAddressesMessage start -type RequestAddressesMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IncludeAllSubnetworks bool `protobuf:"varint,1,opt,name=includeAllSubnetworks,proto3" json:"includeAllSubnetworks,omitempty"` - SubnetworkId *SubnetworkId `protobuf:"bytes,2,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` -} - -func (x *RequestAddressesMessage) Reset() { - *x = RequestAddressesMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestAddressesMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestAddressesMessage) ProtoMessage() {} - -func (x *RequestAddressesMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestAddressesMessage.ProtoReflect.Descriptor instead. -func (*RequestAddressesMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{1} -} - -func (x *RequestAddressesMessage) GetIncludeAllSubnetworks() bool { - if x != nil { - return x.IncludeAllSubnetworks - } - return false -} - -func (x *RequestAddressesMessage) GetSubnetworkId() *SubnetworkId { - if x != nil { - return x.SubnetworkId - } - return nil -} - -// AddressesMessage start -type AddressesMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - AddressList []*NetAddress `protobuf:"bytes,1,rep,name=addressList,proto3" json:"addressList,omitempty"` -} - -func (x *AddressesMessage) Reset() { - *x = AddressesMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AddressesMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AddressesMessage) ProtoMessage() {} - -func (x *AddressesMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AddressesMessage.ProtoReflect.Descriptor instead. -func (*AddressesMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{2} -} - -func (x *AddressesMessage) GetAddressList() []*NetAddress { - if x != nil { - return x.AddressList - } - return nil -} - -type NetAddress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Services uint64 `protobuf:"varint,2,opt,name=services,proto3" json:"services,omitempty"` - Ip []byte `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"` - Port uint32 `protobuf:"varint,4,opt,name=port,proto3" json:"port,omitempty"` -} - -func (x *NetAddress) Reset() { - *x = NetAddress{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NetAddress) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NetAddress) ProtoMessage() {} - -func (x *NetAddress) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NetAddress.ProtoReflect.Descriptor instead. -func (*NetAddress) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{3} -} - -func (x *NetAddress) GetTimestamp() int64 { - if x != nil { - return x.Timestamp - } - return 0 -} - -func (x *NetAddress) GetServices() uint64 { - if x != nil { - return x.Services - } - return 0 -} - -func (x *NetAddress) GetIp() []byte { - if x != nil { - return x.Ip - } - return nil -} - -func (x *NetAddress) GetPort() uint32 { - if x != nil { - return x.Port - } - return 0 -} - -type SubnetworkId struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` -} - -func (x *SubnetworkId) Reset() { - *x = SubnetworkId{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubnetworkId) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubnetworkId) ProtoMessage() {} - -func (x *SubnetworkId) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubnetworkId.ProtoReflect.Descriptor instead. -func (*SubnetworkId) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{4} -} - -func (x *SubnetworkId) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -// TransactionMessage start -type TransactionMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - Inputs []*TransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` - Outputs []*TransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` - LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` - SubnetworkId *SubnetworkId `protobuf:"bytes,5,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` - Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"` - PayloadHash *Hash `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` - Payload []byte `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` -} - -func (x *TransactionMessage) Reset() { - *x = TransactionMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionMessage) ProtoMessage() {} - -func (x *TransactionMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionMessage.ProtoReflect.Descriptor instead. -func (*TransactionMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{5} -} - -func (x *TransactionMessage) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *TransactionMessage) GetInputs() []*TransactionInput { - if x != nil { - return x.Inputs - } - return nil -} - -func (x *TransactionMessage) GetOutputs() []*TransactionOutput { - if x != nil { - return x.Outputs - } - return nil -} - -func (x *TransactionMessage) GetLockTime() uint64 { - if x != nil { - return x.LockTime - } - return 0 -} - -func (x *TransactionMessage) GetSubnetworkId() *SubnetworkId { - if x != nil { - return x.SubnetworkId - } - return nil -} - -func (x *TransactionMessage) GetGas() uint64 { - if x != nil { - return x.Gas - } - return 0 -} - -func (x *TransactionMessage) GetPayloadHash() *Hash { - if x != nil { - return x.PayloadHash - } - return nil -} - -func (x *TransactionMessage) GetPayload() []byte { - if x != nil { - return x.Payload - } - return nil -} - -type TransactionInput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PreviousOutpoint *Outpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` - SignatureScript []byte `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` - Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` -} - -func (x *TransactionInput) Reset() { - *x = TransactionInput{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionInput) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionInput) ProtoMessage() {} - -func (x *TransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionInput.ProtoReflect.Descriptor instead. -func (*TransactionInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{6} -} - -func (x *TransactionInput) GetPreviousOutpoint() *Outpoint { - if x != nil { - return x.PreviousOutpoint - } - return nil -} - -func (x *TransactionInput) GetSignatureScript() []byte { - if x != nil { - return x.SignatureScript - } - return nil -} - -func (x *TransactionInput) GetSequence() uint64 { - if x != nil { - return x.Sequence - } - return 0 -} - -type Outpoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TransactionId *TransactionId `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` - Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` -} - -func (x *Outpoint) Reset() { - *x = Outpoint{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Outpoint) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Outpoint) ProtoMessage() {} - -func (x *Outpoint) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Outpoint.ProtoReflect.Descriptor instead. -func (*Outpoint) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{7} -} - -func (x *Outpoint) GetTransactionId() *TransactionId { - if x != nil { - return x.TransactionId - } - return nil -} - -func (x *Outpoint) GetIndex() uint32 { - if x != nil { - return x.Index - } - return 0 -} - -type TransactionId struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` -} - -func (x *TransactionId) Reset() { - *x = TransactionId{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionId) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionId) ProtoMessage() {} - -func (x *TransactionId) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionId.ProtoReflect.Descriptor instead. -func (*TransactionId) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{8} -} - -func (x *TransactionId) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -type ScriptPublicKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Script []byte `protobuf:"bytes,1,opt,name=script,proto3" json:"script,omitempty"` - Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` -} - -func (x *ScriptPublicKey) Reset() { - *x = ScriptPublicKey{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ScriptPublicKey) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ScriptPublicKey) ProtoMessage() {} - -func (x *ScriptPublicKey) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ScriptPublicKey.ProtoReflect.Descriptor instead. -func (*ScriptPublicKey) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{9} -} - -func (x *ScriptPublicKey) GetScript() []byte { - if x != nil { - return x.Script - } - return nil -} - -func (x *ScriptPublicKey) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -type TransactionOutput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - ScriptPublicKey *ScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` -} - -func (x *TransactionOutput) Reset() { - *x = TransactionOutput{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionOutput) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionOutput) ProtoMessage() {} - -func (x *TransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionOutput.ProtoReflect.Descriptor instead. -func (*TransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{10} -} - -func (x *TransactionOutput) GetValue() uint64 { - if x != nil { - return x.Value - } - return 0 -} - -func (x *TransactionOutput) GetScriptPublicKey() *ScriptPublicKey { - if x != nil { - return x.ScriptPublicKey - } - return nil -} - -// BlockMessage start -type BlockMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Header *BlockHeaderMessage `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` - Transactions []*TransactionMessage `protobuf:"bytes,2,rep,name=transactions,proto3" json:"transactions,omitempty"` -} - -func (x *BlockMessage) Reset() { - *x = BlockMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BlockMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BlockMessage) ProtoMessage() {} - -func (x *BlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BlockMessage.ProtoReflect.Descriptor instead. -func (*BlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{11} -} - -func (x *BlockMessage) GetHeader() *BlockHeaderMessage { - if x != nil { - return x.Header - } - return nil -} - -func (x *BlockMessage) GetTransactions() []*TransactionMessage { - if x != nil { - return x.Transactions - } - return nil -} - -type BlockHeaderMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - ParentHashes []*Hash `protobuf:"bytes,2,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` - HashMerkleRoot *Hash `protobuf:"bytes,3,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` - AcceptedIdMerkleRoot *Hash `protobuf:"bytes,4,opt,name=acceptedIdMerkleRoot,proto3" json:"acceptedIdMerkleRoot,omitempty"` - UtxoCommitment *Hash `protobuf:"bytes,5,opt,name=utxoCommitment,proto3" json:"utxoCommitment,omitempty"` - Timestamp int64 `protobuf:"varint,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Bits uint32 `protobuf:"varint,7,opt,name=bits,proto3" json:"bits,omitempty"` - Nonce uint64 `protobuf:"varint,8,opt,name=nonce,proto3" json:"nonce,omitempty"` -} - -func (x *BlockHeaderMessage) Reset() { - *x = BlockHeaderMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BlockHeaderMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BlockHeaderMessage) ProtoMessage() {} - -func (x *BlockHeaderMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BlockHeaderMessage.ProtoReflect.Descriptor instead. -func (*BlockHeaderMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{12} -} - -func (x *BlockHeaderMessage) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *BlockHeaderMessage) GetParentHashes() []*Hash { - if x != nil { - return x.ParentHashes - } - return nil -} - -func (x *BlockHeaderMessage) GetHashMerkleRoot() *Hash { - if x != nil { - return x.HashMerkleRoot - } - return nil -} - -func (x *BlockHeaderMessage) GetAcceptedIdMerkleRoot() *Hash { - if x != nil { - return x.AcceptedIdMerkleRoot - } - return nil -} - -func (x *BlockHeaderMessage) GetUtxoCommitment() *Hash { - if x != nil { - return x.UtxoCommitment - } - return nil -} - -func (x *BlockHeaderMessage) GetTimestamp() int64 { - if x != nil { - return x.Timestamp - } - return 0 -} - -func (x *BlockHeaderMessage) GetBits() uint32 { - if x != nil { - return x.Bits - } - return 0 -} - -func (x *BlockHeaderMessage) GetNonce() uint64 { - if x != nil { - return x.Nonce - } - return 0 -} - -type Hash struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` -} - -func (x *Hash) Reset() { - *x = Hash{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Hash) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Hash) ProtoMessage() {} - -func (x *Hash) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Hash.ProtoReflect.Descriptor instead. -func (*Hash) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{13} -} - -func (x *Hash) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -// GetBlockLocatorMessage start -type RequestBlockLocatorMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LowHash *Hash `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` - HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` - Limit uint32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` -} - -func (x *RequestBlockLocatorMessage) Reset() { - *x = RequestBlockLocatorMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestBlockLocatorMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestBlockLocatorMessage) ProtoMessage() {} - -func (x *RequestBlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestBlockLocatorMessage.ProtoReflect.Descriptor instead. -func (*RequestBlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{14} -} - -func (x *RequestBlockLocatorMessage) GetLowHash() *Hash { - if x != nil { - return x.LowHash - } - return nil -} - -func (x *RequestBlockLocatorMessage) GetHighHash() *Hash { - if x != nil { - return x.HighHash - } - return nil -} - -func (x *RequestBlockLocatorMessage) GetLimit() uint32 { - if x != nil { - return x.Limit - } - return 0 -} - -// BlockLocatorMessage start -type BlockLocatorMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` -} - -func (x *BlockLocatorMessage) Reset() { - *x = BlockLocatorMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BlockLocatorMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BlockLocatorMessage) ProtoMessage() {} - -func (x *BlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BlockLocatorMessage.ProtoReflect.Descriptor instead. -func (*BlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{15} -} - -func (x *BlockLocatorMessage) GetHashes() []*Hash { - if x != nil { - return x.Hashes - } - return nil -} - -// GetBlocksMessage start -type RequestHeadersMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LowHash *Hash `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` - HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` -} - -func (x *RequestHeadersMessage) Reset() { - *x = RequestHeadersMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestHeadersMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestHeadersMessage) ProtoMessage() {} - -func (x *RequestHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestHeadersMessage.ProtoReflect.Descriptor instead. -func (*RequestHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{16} -} - -func (x *RequestHeadersMessage) GetLowHash() *Hash { - if x != nil { - return x.LowHash - } - return nil -} - -func (x *RequestHeadersMessage) GetHighHash() *Hash { - if x != nil { - return x.HighHash - } - return nil -} - -// RequestNextIBDBlocksMessage start -type RequestNextHeadersMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *RequestNextHeadersMessage) Reset() { - *x = RequestNextHeadersMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestNextHeadersMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestNextHeadersMessage) ProtoMessage() {} - -func (x *RequestNextHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestNextHeadersMessage.ProtoReflect.Descriptor instead. -func (*RequestNextHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{17} -} - -// DoneIBDBlocksMessage start -type DoneHeadersMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *DoneHeadersMessage) Reset() { - *x = DoneHeadersMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DoneHeadersMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DoneHeadersMessage) ProtoMessage() {} - -func (x *DoneHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DoneHeadersMessage.ProtoReflect.Descriptor instead. -func (*DoneHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{18} -} - -// RequestRelayBlocksMessage start -type RequestRelayBlocksMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` -} - -func (x *RequestRelayBlocksMessage) Reset() { - *x = RequestRelayBlocksMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestRelayBlocksMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestRelayBlocksMessage) ProtoMessage() {} - -func (x *RequestRelayBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestRelayBlocksMessage.ProtoReflect.Descriptor instead. -func (*RequestRelayBlocksMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{19} -} - -func (x *RequestRelayBlocksMessage) GetHashes() []*Hash { - if x != nil { - return x.Hashes - } - return nil -} - -// RequestTransactionsMessage start -type RequestTransactionsMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Ids []*TransactionId `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` -} - -func (x *RequestTransactionsMessage) Reset() { - *x = RequestTransactionsMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestTransactionsMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestTransactionsMessage) ProtoMessage() {} - -func (x *RequestTransactionsMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestTransactionsMessage.ProtoReflect.Descriptor instead. -func (*RequestTransactionsMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{20} -} - -func (x *RequestTransactionsMessage) GetIds() []*TransactionId { - if x != nil { - return x.Ids - } - return nil -} - -// TransactionNotFoundMessage start -type TransactionNotFoundMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id *TransactionId `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *TransactionNotFoundMessage) Reset() { - *x = TransactionNotFoundMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionNotFoundMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionNotFoundMessage) ProtoMessage() {} - -func (x *TransactionNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionNotFoundMessage.ProtoReflect.Descriptor instead. -func (*TransactionNotFoundMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{21} -} - -func (x *TransactionNotFoundMessage) GetId() *TransactionId { - if x != nil { - return x.Id - } - return nil -} - -// InvRelayBlockMessage start -type InvRelayBlockMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` -} - -func (x *InvRelayBlockMessage) Reset() { - *x = InvRelayBlockMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InvRelayBlockMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InvRelayBlockMessage) ProtoMessage() {} - -func (x *InvRelayBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InvRelayBlockMessage.ProtoReflect.Descriptor instead. -func (*InvRelayBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{22} -} - -func (x *InvRelayBlockMessage) GetHash() *Hash { - if x != nil { - return x.Hash - } - return nil -} - -// InvTransactionMessage start -type InvTransactionsMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Ids []*TransactionId `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` -} - -func (x *InvTransactionsMessage) Reset() { - *x = InvTransactionsMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InvTransactionsMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InvTransactionsMessage) ProtoMessage() {} - -func (x *InvTransactionsMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InvTransactionsMessage.ProtoReflect.Descriptor instead. -func (*InvTransactionsMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{23} -} - -func (x *InvTransactionsMessage) GetIds() []*TransactionId { - if x != nil { - return x.Ids - } - return nil -} - -// PingMessage start -type PingMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` -} - -func (x *PingMessage) Reset() { - *x = PingMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PingMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PingMessage) ProtoMessage() {} - -func (x *PingMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PingMessage.ProtoReflect.Descriptor instead. -func (*PingMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{24} -} - -func (x *PingMessage) GetNonce() uint64 { - if x != nil { - return x.Nonce - } - return 0 -} - -// PongMessage start -type PongMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` -} - -func (x *PongMessage) Reset() { - *x = PongMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PongMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PongMessage) ProtoMessage() {} - -func (x *PongMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PongMessage.ProtoReflect.Descriptor instead. -func (*PongMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{25} -} - -func (x *PongMessage) GetNonce() uint64 { - if x != nil { - return x.Nonce - } - return 0 -} - -// VerackMessage start -type VerackMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *VerackMessage) Reset() { - *x = VerackMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VerackMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VerackMessage) ProtoMessage() {} - -func (x *VerackMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VerackMessage.ProtoReflect.Descriptor instead. -func (*VerackMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{26} -} - -// VersionMessage start -type VersionMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ProtocolVersion uint32 `protobuf:"varint,1,opt,name=protocolVersion,proto3" json:"protocolVersion,omitempty"` - Services uint64 `protobuf:"varint,2,opt,name=services,proto3" json:"services,omitempty"` - Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Address *NetAddress `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` - Id []byte `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` - UserAgent string `protobuf:"bytes,6,opt,name=userAgent,proto3" json:"userAgent,omitempty"` - DisableRelayTx bool `protobuf:"varint,8,opt,name=disableRelayTx,proto3" json:"disableRelayTx,omitempty"` - SubnetworkId *SubnetworkId `protobuf:"bytes,9,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` - Network string `protobuf:"bytes,10,opt,name=network,proto3" json:"network,omitempty"` -} - -func (x *VersionMessage) Reset() { - *x = VersionMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VersionMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VersionMessage) ProtoMessage() {} - -func (x *VersionMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VersionMessage.ProtoReflect.Descriptor instead. -func (*VersionMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{27} -} - -func (x *VersionMessage) GetProtocolVersion() uint32 { - if x != nil { - return x.ProtocolVersion - } - return 0 -} - -func (x *VersionMessage) GetServices() uint64 { - if x != nil { - return x.Services - } - return 0 -} - -func (x *VersionMessage) GetTimestamp() int64 { - if x != nil { - return x.Timestamp - } - return 0 -} - -func (x *VersionMessage) GetAddress() *NetAddress { - if x != nil { - return x.Address - } - return nil -} - -func (x *VersionMessage) GetId() []byte { - if x != nil { - return x.Id - } - return nil -} - -func (x *VersionMessage) GetUserAgent() string { - if x != nil { - return x.UserAgent - } - return "" -} - -func (x *VersionMessage) GetDisableRelayTx() bool { - if x != nil { - return x.DisableRelayTx - } - return false -} - -func (x *VersionMessage) GetSubnetworkId() *SubnetworkId { - if x != nil { - return x.SubnetworkId - } - return nil -} - -func (x *VersionMessage) GetNetwork() string { - if x != nil { - return x.Network - } - return "" -} - -// RejectMessage start -type RejectMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` -} - -func (x *RejectMessage) Reset() { - *x = RejectMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RejectMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RejectMessage) ProtoMessage() {} - -func (x *RejectMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RejectMessage.ProtoReflect.Descriptor instead. -func (*RejectMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{28} -} - -func (x *RejectMessage) GetReason() string { - if x != nil { - return x.Reason - } - return "" -} - -// RequestIBDRootUTXOSetAndBlockMessage start -type RequestIBDRootUTXOSetAndBlockMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IbdRoot *Hash `protobuf:"bytes,1,opt,name=ibdRoot,proto3" json:"ibdRoot,omitempty"` -} - -func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { - *x = RequestIBDRootUTXOSetAndBlockMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestIBDRootUTXOSetAndBlockMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestIBDRootUTXOSetAndBlockMessage) ProtoMessage() {} - -func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestIBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. -func (*RequestIBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{29} -} - -func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { - if x != nil { - return x.IbdRoot - } - return nil -} - -// IBDRootUTXOSetAndBlockMessage start -type IBDRootUTXOSetAndBlockMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - UtxoSet []byte `protobuf:"bytes,1,opt,name=utxoSet,proto3" json:"utxoSet,omitempty"` - Block *BlockMessage `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` -} - -func (x *IBDRootUTXOSetAndBlockMessage) Reset() { - *x = IBDRootUTXOSetAndBlockMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IBDRootUTXOSetAndBlockMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IBDRootUTXOSetAndBlockMessage) ProtoMessage() {} - -func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. -func (*IBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{30} -} - -func (x *IBDRootUTXOSetAndBlockMessage) GetUtxoSet() []byte { - if x != nil { - return x.UtxoSet - } - return nil -} - -func (x *IBDRootUTXOSetAndBlockMessage) GetBlock() *BlockMessage { - if x != nil { - return x.Block - } - return nil -} - -// RequestIBDBlocksMessage start -type RequestIBDBlocksMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` -} - -func (x *RequestIBDBlocksMessage) Reset() { - *x = RequestIBDBlocksMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestIBDBlocksMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestIBDBlocksMessage) ProtoMessage() {} - -func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. -func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{31} -} - -func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { - if x != nil { - return x.Hashes - } - return nil -} - -// IBDRootNotFoundMessage start -type IBDRootNotFoundMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *IBDRootNotFoundMessage) Reset() { - *x = IBDRootNotFoundMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IBDRootNotFoundMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IBDRootNotFoundMessage) ProtoMessage() {} - -func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. -func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{32} -} - -// RequestIBDRootHashMessage start -type RequestIBDRootHashMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *RequestIBDRootHashMessage) Reset() { - *x = RequestIBDRootHashMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestIBDRootHashMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestIBDRootHashMessage) ProtoMessage() {} - -func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestIBDRootHashMessage.ProtoReflect.Descriptor instead. -func (*RequestIBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{33} -} - -// IBDRootHashMessage start -type IBDRootHashMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` -} - -func (x *IBDRootHashMessage) Reset() { - *x = IBDRootHashMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IBDRootHashMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IBDRootHashMessage) ProtoMessage() {} - -func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IBDRootHashMessage.ProtoReflect.Descriptor instead. -func (*IBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} -} - -func (x *IBDRootHashMessage) GetHash() *Hash { - if x != nil { - return x.Hash - } - return nil -} - -// IbdBlockLocatorMessage start -type IbdBlockLocatorMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TargetHash *Hash `protobuf:"bytes,1,opt,name=targetHash,proto3" json:"targetHash,omitempty"` - BlockLocatorHashes []*Hash `protobuf:"bytes,2,rep,name=blockLocatorHashes,proto3" json:"blockLocatorHashes,omitempty"` -} - -func (x *IbdBlockLocatorMessage) Reset() { - *x = IbdBlockLocatorMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IbdBlockLocatorMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IbdBlockLocatorMessage) ProtoMessage() {} - -func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IbdBlockLocatorMessage.ProtoReflect.Descriptor instead. -func (*IbdBlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{35} -} - -func (x *IbdBlockLocatorMessage) GetTargetHash() *Hash { - if x != nil { - return x.TargetHash - } - return nil -} - -func (x *IbdBlockLocatorMessage) GetBlockLocatorHashes() []*Hash { - if x != nil { - return x.BlockLocatorHashes - } - return nil -} - -// IbdBlockLocatorHighestHashMessage start -type IbdBlockLocatorHighestHashMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - HighestHash *Hash `protobuf:"bytes,1,opt,name=highestHash,proto3" json:"highestHash,omitempty"` -} - -func (x *IbdBlockLocatorHighestHashMessage) Reset() { - *x = IbdBlockLocatorHighestHashMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IbdBlockLocatorHighestHashMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IbdBlockLocatorHighestHashMessage) ProtoMessage() {} - -func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IbdBlockLocatorHighestHashMessage.ProtoReflect.Descriptor instead. -func (*IbdBlockLocatorHighestHashMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{36} -} - -func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { - if x != nil { - return x.HighestHash - } - return nil -} - -type BlockHeadersMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - BlockHeaders []*BlockHeaderMessage `protobuf:"bytes,1,rep,name=blockHeaders,proto3" json:"blockHeaders,omitempty"` -} - -func (x *BlockHeadersMessage) Reset() { - *x = BlockHeadersMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BlockHeadersMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BlockHeadersMessage) ProtoMessage() {} - -func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. -func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{37} -} - -func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { - if x != nil { - return x.BlockHeaders - } - return nil -} - -type RPCError struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *RPCError) Reset() { - *x = RPCError{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RPCError) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RPCError) ProtoMessage() {} - -func (x *RPCError) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RPCError.ProtoReflect.Descriptor instead. -func (*RPCError) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{38} -} - -func (x *RPCError) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -type GetCurrentNetworkRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetCurrentNetworkRequestMessage) Reset() { - *x = GetCurrentNetworkRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetCurrentNetworkRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} - -func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. -func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{39} -} - -type GetCurrentNetworkResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CurrentNetwork string `protobuf:"bytes,1,opt,name=currentNetwork,proto3" json:"currentNetwork,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetCurrentNetworkResponseMessage) Reset() { - *x = GetCurrentNetworkResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetCurrentNetworkResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} - -func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. -func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{40} -} - -func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { - if x != nil { - return x.CurrentNetwork - } - return "" -} - -func (x *GetCurrentNetworkResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type SubmitBlockRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Block *BlockMessage `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` -} - -func (x *SubmitBlockRequestMessage) Reset() { - *x = SubmitBlockRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubmitBlockRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubmitBlockRequestMessage) ProtoMessage() {} - -func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. -func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{41} -} - -func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { - if x != nil { - return x.Block - } - return nil -} - -type SubmitBlockResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *SubmitBlockResponseMessage) Reset() { - *x = SubmitBlockResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubmitBlockResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubmitBlockResponseMessage) ProtoMessage() {} - -func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[42] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. -func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{42} -} - -func (x *SubmitBlockResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetBlockTemplateRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PayAddress string `protobuf:"bytes,1,opt,name=payAddress,proto3" json:"payAddress,omitempty"` -} - -func (x *GetBlockTemplateRequestMessage) Reset() { - *x = GetBlockTemplateRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockTemplateRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockTemplateRequestMessage) ProtoMessage() {} - -func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. -func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{43} -} - -func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { - if x != nil { - return x.PayAddress - } - return "" -} - -type GetBlockTemplateResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - BlockMessage *BlockMessage `protobuf:"bytes,1,opt,name=blockMessage,proto3" json:"blockMessage,omitempty"` - IsSynced bool `protobuf:"varint,2,opt,name=isSynced,proto3" json:"isSynced,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetBlockTemplateResponseMessage) Reset() { - *x = GetBlockTemplateResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockTemplateResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockTemplateResponseMessage) ProtoMessage() {} - -func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. -func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{44} -} - -func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { - if x != nil { - return x.BlockMessage - } - return nil -} - -func (x *GetBlockTemplateResponseMessage) GetIsSynced() bool { - if x != nil { - return x.IsSynced - } - return false -} - -func (x *GetBlockTemplateResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type NotifyBlockAddedRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *NotifyBlockAddedRequestMessage) Reset() { - *x = NotifyBlockAddedRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyBlockAddedRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} - -func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[45] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. -func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{45} -} - -type NotifyBlockAddedResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *NotifyBlockAddedResponseMessage) Reset() { - *x = NotifyBlockAddedResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyBlockAddedResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} - -func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[46] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. -func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{46} -} - -func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type BlockAddedNotificationMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Block *BlockMessage `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` -} - -func (x *BlockAddedNotificationMessage) Reset() { - *x = BlockAddedNotificationMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[47] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BlockAddedNotificationMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BlockAddedNotificationMessage) ProtoMessage() {} - -func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[47] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. -func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{47} -} - -func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { - if x != nil { - return x.Block - } - return nil -} - -type GetPeerAddressesRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetPeerAddressesRequestMessage) Reset() { - *x = GetPeerAddressesRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[48] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetPeerAddressesRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetPeerAddressesRequestMessage) ProtoMessage() {} - -func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[48] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. -func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{48} -} - -type GetPeerAddressesResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Addresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` - BannedAddresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,2,rep,name=bannedAddresses,proto3" json:"bannedAddresses,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetPeerAddressesResponseMessage) Reset() { - *x = GetPeerAddressesResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[49] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetPeerAddressesResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetPeerAddressesResponseMessage) ProtoMessage() {} - -func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[49] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. -func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{49} -} - -func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { - if x != nil { - return x.Addresses - } - return nil -} - -func (x *GetPeerAddressesResponseMessage) GetBannedAddresses() []*GetPeerAddressesKnownAddressMessage { - if x != nil { - return x.BannedAddresses - } - return nil -} - -func (x *GetPeerAddressesResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetPeerAddressesKnownAddressMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Addr string `protobuf:"bytes,1,opt,name=Addr,proto3" json:"Addr,omitempty"` -} - -func (x *GetPeerAddressesKnownAddressMessage) Reset() { - *x = GetPeerAddressesKnownAddressMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[50] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetPeerAddressesKnownAddressMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} - -func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[50] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. -func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{50} -} - -func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { - if x != nil { - return x.Addr - } - return "" -} - -type GetSelectedTipHashRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetSelectedTipHashRequestMessage) Reset() { - *x = GetSelectedTipHashRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[51] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetSelectedTipHashRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} - -func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[51] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. -func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{51} -} - -type GetSelectedTipHashResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SelectedTipHash string `protobuf:"bytes,1,opt,name=selectedTipHash,proto3" json:"selectedTipHash,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetSelectedTipHashResponseMessage) Reset() { - *x = GetSelectedTipHashResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[52] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetSelectedTipHashResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} - -func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[52] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. -func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{52} -} - -func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { - if x != nil { - return x.SelectedTipHash - } - return "" -} - -func (x *GetSelectedTipHashResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -// mempool entries start -type MempoolEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Fee uint64 `protobuf:"varint,1,opt,name=fee,proto3" json:"fee,omitempty"` - TransactionVerboseData *TransactionVerboseData `protobuf:"bytes,2,opt,name=transactionVerboseData,proto3" json:"transactionVerboseData,omitempty"` -} - -func (x *MempoolEntry) Reset() { - *x = MempoolEntry{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[53] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MempoolEntry) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MempoolEntry) ProtoMessage() {} - -func (x *MempoolEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[53] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. -func (*MempoolEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{53} -} - -func (x *MempoolEntry) GetFee() uint64 { - if x != nil { - return x.Fee - } - return 0 -} - -func (x *MempoolEntry) GetTransactionVerboseData() *TransactionVerboseData { - if x != nil { - return x.TransactionVerboseData - } - return nil -} - -type GetMempoolEntryRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` -} - -func (x *GetMempoolEntryRequestMessage) Reset() { - *x = GetMempoolEntryRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[54] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetMempoolEntryRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMempoolEntryRequestMessage) ProtoMessage() {} - -func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[54] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. -func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{54} -} - -func (x *GetMempoolEntryRequestMessage) GetTxId() string { - if x != nil { - return x.TxId - } - return "" -} - -type GetMempoolEntryResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Entry *MempoolEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetMempoolEntryResponseMessage) Reset() { - *x = GetMempoolEntryResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[55] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetMempoolEntryResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMempoolEntryResponseMessage) ProtoMessage() {} - -func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[55] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. -func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{55} -} - -func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { - if x != nil { - return x.Entry - } - return nil -} - -func (x *GetMempoolEntryResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetMempoolEntriesRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetMempoolEntriesRequestMessage) Reset() { - *x = GetMempoolEntriesRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[56] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetMempoolEntriesRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} - -func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[56] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. -func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{56} -} - -type GetMempoolEntriesResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Entries []*MempoolEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetMempoolEntriesResponseMessage) Reset() { - *x = GetMempoolEntriesResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[57] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetMempoolEntriesResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} - -func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[57] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. -func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{57} -} - -func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { - if x != nil { - return x.Entries - } - return nil -} - -func (x *GetMempoolEntriesResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetConnectedPeerInfoRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetConnectedPeerInfoRequestMessage) Reset() { - *x = GetConnectedPeerInfoRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[58] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetConnectedPeerInfoRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} - -func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[58] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. -func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{58} -} - -type GetConnectedPeerInfoResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Infos []*GetConnectedPeerInfoMessage `protobuf:"bytes,1,rep,name=infos,proto3" json:"infos,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetConnectedPeerInfoResponseMessage) Reset() { - *x = GetConnectedPeerInfoResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[59] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetConnectedPeerInfoResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} - -func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[59] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. -func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{59} -} - -func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { - if x != nil { - return x.Infos - } - return nil -} - -func (x *GetConnectedPeerInfoResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetConnectedPeerInfoMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` - LastPingDuration int64 `protobuf:"varint,3,opt,name=lastPingDuration,proto3" json:"lastPingDuration,omitempty"` - IsOutbound bool `protobuf:"varint,6,opt,name=isOutbound,proto3" json:"isOutbound,omitempty"` - TimeOffset int64 `protobuf:"varint,7,opt,name=timeOffset,proto3" json:"timeOffset,omitempty"` - UserAgent string `protobuf:"bytes,8,opt,name=userAgent,proto3" json:"userAgent,omitempty"` - AdvertisedProtocolVersion uint32 `protobuf:"varint,9,opt,name=advertisedProtocolVersion,proto3" json:"advertisedProtocolVersion,omitempty"` - TimeConnected int64 `protobuf:"varint,10,opt,name=timeConnected,proto3" json:"timeConnected,omitempty"` - IsIbdPeer bool `protobuf:"varint,11,opt,name=isIbdPeer,proto3" json:"isIbdPeer,omitempty"` -} - -func (x *GetConnectedPeerInfoMessage) Reset() { - *x = GetConnectedPeerInfoMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[60] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetConnectedPeerInfoMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetConnectedPeerInfoMessage) ProtoMessage() {} - -func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[60] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. -func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{60} -} - -func (x *GetConnectedPeerInfoMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *GetConnectedPeerInfoMessage) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -func (x *GetConnectedPeerInfoMessage) GetLastPingDuration() int64 { - if x != nil { - return x.LastPingDuration - } - return 0 -} - -func (x *GetConnectedPeerInfoMessage) GetIsOutbound() bool { - if x != nil { - return x.IsOutbound - } - return false -} - -func (x *GetConnectedPeerInfoMessage) GetTimeOffset() int64 { - if x != nil { - return x.TimeOffset - } - return 0 -} - -func (x *GetConnectedPeerInfoMessage) GetUserAgent() string { - if x != nil { - return x.UserAgent - } - return "" -} - -func (x *GetConnectedPeerInfoMessage) GetAdvertisedProtocolVersion() uint32 { - if x != nil { - return x.AdvertisedProtocolVersion - } - return 0 -} - -func (x *GetConnectedPeerInfoMessage) GetTimeConnected() int64 { - if x != nil { - return x.TimeConnected - } - return 0 -} - -func (x *GetConnectedPeerInfoMessage) GetIsIbdPeer() bool { - if x != nil { - return x.IsIbdPeer - } - return false -} - -type AddPeerRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - IsPermanent bool `protobuf:"varint,2,opt,name=isPermanent,proto3" json:"isPermanent,omitempty"` -} - -func (x *AddPeerRequestMessage) Reset() { - *x = AddPeerRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[61] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AddPeerRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AddPeerRequestMessage) ProtoMessage() {} - -func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[61] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. -func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{61} -} - -func (x *AddPeerRequestMessage) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -func (x *AddPeerRequestMessage) GetIsPermanent() bool { - if x != nil { - return x.IsPermanent - } - return false -} - -type AddPeerResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *AddPeerResponseMessage) Reset() { - *x = AddPeerResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[62] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AddPeerResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AddPeerResponseMessage) ProtoMessage() {} - -func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[62] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. -func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{62} -} - -func (x *AddPeerResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type SubmitTransactionRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Transaction *RpcTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` -} - -func (x *SubmitTransactionRequestMessage) Reset() { - *x = SubmitTransactionRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[63] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubmitTransactionRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubmitTransactionRequestMessage) ProtoMessage() {} - -func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[63] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. -func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{63} -} - -func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { - if x != nil { - return x.Transaction - } - return nil -} - -type SubmitTransactionResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *SubmitTransactionResponseMessage) Reset() { - *x = SubmitTransactionResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[64] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubmitTransactionResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubmitTransactionResponseMessage) ProtoMessage() {} - -func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[64] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. -func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{64} -} - -func (x *SubmitTransactionResponseMessage) GetTransactionId() string { - if x != nil { - return x.TransactionId - } - return "" -} - -func (x *SubmitTransactionResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type NotifyVirtualSelectedParentChainChangedRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { - *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[65] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} - -func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[65] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. -func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{65} -} - -type NotifyVirtualSelectedParentChainChangedResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { - *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[66] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} - -func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[66] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. -func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{66} -} - -func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type VirtualSelectedParentChainChangedNotificationMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RemovedChainBlockHashes []string `protobuf:"bytes,1,rep,name=removedChainBlockHashes,proto3" json:"removedChainBlockHashes,omitempty"` - AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` -} - -func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { - *x = VirtualSelectedParentChainChangedNotificationMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[67] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} - -func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[67] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. -func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{67} -} - -func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { - if x != nil { - return x.RemovedChainBlockHashes - } - return nil -} - -func (x *VirtualSelectedParentChainChangedNotificationMessage) GetAddedChainBlocks() []*ChainBlock { - if x != nil { - return x.AddedChainBlocks - } - return nil -} - -type ChainBlock struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - AcceptedBlocks []*AcceptedBlock `protobuf:"bytes,2,rep,name=acceptedBlocks,proto3" json:"acceptedBlocks,omitempty"` -} - -func (x *ChainBlock) Reset() { - *x = ChainBlock{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[68] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ChainBlock) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ChainBlock) ProtoMessage() {} - -func (x *ChainBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[68] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. -func (*ChainBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{68} -} - -func (x *ChainBlock) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *ChainBlock) GetAcceptedBlocks() []*AcceptedBlock { - if x != nil { - return x.AcceptedBlocks - } - return nil -} - -type AcceptedBlock struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - 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() { - *x = AcceptedBlock{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[69] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AcceptedBlock) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AcceptedBlock) ProtoMessage() {} - -func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[69] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. -func (*AcceptedBlock) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{69} -} - -func (x *AcceptedBlock) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *AcceptedBlock) GetAcceptedTransactionIds() []string { - if x != nil { - return x.AcceptedTransactionIds - } - return nil -} - -type GetBlockRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - SubnetworkId string `protobuf:"bytes,2,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` - IncludeTransactionVerboseData bool `protobuf:"varint,3,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` -} - -func (x *GetBlockRequestMessage) Reset() { - *x = GetBlockRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[70] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockRequestMessage) ProtoMessage() {} - -func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[70] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. -func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{70} -} - -func (x *GetBlockRequestMessage) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *GetBlockRequestMessage) GetSubnetworkId() string { - if x != nil { - return x.SubnetworkId - } - return "" -} - -func (x *GetBlockRequestMessage) GetIncludeTransactionVerboseData() bool { - if x != nil { - return x.IncludeTransactionVerboseData - } - return false -} - -type GetBlockResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - BlockHash string `protobuf:"bytes,1,opt,name=blockHash,proto3" json:"blockHash,omitempty"` - BlockVerboseData *BlockVerboseData `protobuf:"bytes,2,opt,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetBlockResponseMessage) Reset() { - *x = GetBlockResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[71] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockResponseMessage) ProtoMessage() {} - -func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[71] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. -func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{71} -} - -func (x *GetBlockResponseMessage) GetBlockHash() string { - if x != nil { - return x.BlockHash - } - return "" -} - -func (x *GetBlockResponseMessage) GetBlockVerboseData() *BlockVerboseData { - if x != nil { - return x.BlockVerboseData - } - return nil -} - -func (x *GetBlockResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type BlockVerboseData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` - VersionHex string `protobuf:"bytes,3,opt,name=versionHex,proto3" json:"versionHex,omitempty"` - HashMerkleRoot string `protobuf:"bytes,4,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` - AcceptedIDMerkleRoot string `protobuf:"bytes,5,opt,name=acceptedIDMerkleRoot,proto3" json:"acceptedIDMerkleRoot,omitempty"` - UtxoCommitment string `protobuf:"bytes,6,opt,name=utxoCommitment,proto3" json:"utxoCommitment,omitempty"` - TransactionVerboseData []*TransactionVerboseData `protobuf:"bytes,7,rep,name=transactionVerboseData,proto3" json:"transactionVerboseData,omitempty"` - Time int64 `protobuf:"varint,8,opt,name=time,proto3" json:"time,omitempty"` - Nonce uint64 `protobuf:"varint,9,opt,name=nonce,proto3" json:"nonce,omitempty"` - Bits string `protobuf:"bytes,10,opt,name=bits,proto3" json:"bits,omitempty"` - Difficulty float64 `protobuf:"fixed64,11,opt,name=difficulty,proto3" json:"difficulty,omitempty"` - ParentHashes []string `protobuf:"bytes,12,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` - SelectedParentHash string `protobuf:"bytes,13,opt,name=selectedParentHash,proto3" json:"selectedParentHash,omitempty"` - TransactionIDs []string `protobuf:"bytes,14,rep,name=transactionIDs,proto3" json:"transactionIDs,omitempty"` - IsHeaderOnly bool `protobuf:"varint,15,opt,name=isHeaderOnly,proto3" json:"isHeaderOnly,omitempty"` - BlueScore uint64 `protobuf:"varint,16,opt,name=blueScore,proto3" json:"blueScore,omitempty"` -} - -func (x *BlockVerboseData) Reset() { - *x = BlockVerboseData{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[72] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BlockVerboseData) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BlockVerboseData) ProtoMessage() {} - -func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[72] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. -func (*BlockVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{72} -} - -func (x *BlockVerboseData) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *BlockVerboseData) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *BlockVerboseData) GetVersionHex() string { - if x != nil { - return x.VersionHex - } - return "" -} - -func (x *BlockVerboseData) GetHashMerkleRoot() string { - if x != nil { - return x.HashMerkleRoot - } - return "" -} - -func (x *BlockVerboseData) GetAcceptedIDMerkleRoot() string { - if x != nil { - return x.AcceptedIDMerkleRoot - } - return "" -} - -func (x *BlockVerboseData) GetUtxoCommitment() string { - if x != nil { - return x.UtxoCommitment - } - return "" -} - -func (x *BlockVerboseData) GetTransactionVerboseData() []*TransactionVerboseData { - if x != nil { - return x.TransactionVerboseData - } - return nil -} - -func (x *BlockVerboseData) GetTime() int64 { - if x != nil { - return x.Time - } - return 0 -} - -func (x *BlockVerboseData) GetNonce() uint64 { - if x != nil { - return x.Nonce - } - return 0 -} - -func (x *BlockVerboseData) GetBits() string { - if x != nil { - return x.Bits - } - return "" -} - -func (x *BlockVerboseData) GetDifficulty() float64 { - if x != nil { - return x.Difficulty - } - return 0 -} - -func (x *BlockVerboseData) GetParentHashes() []string { - if x != nil { - return x.ParentHashes - } - return nil -} - -func (x *BlockVerboseData) GetSelectedParentHash() string { - if x != nil { - return x.SelectedParentHash - } - return "" -} - -func (x *BlockVerboseData) GetTransactionIDs() []string { - if x != nil { - return x.TransactionIDs - } - return nil -} - -func (x *BlockVerboseData) GetIsHeaderOnly() bool { - if x != nil { - return x.IsHeaderOnly - } - return false -} - -func (x *BlockVerboseData) GetBlueScore() uint64 { - if x != nil { - return x.BlueScore - } - return 0 -} - -type TransactionVerboseData struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` - Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` - Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` - Version uint32 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` - LockTime uint64 `protobuf:"varint,5,opt,name=lockTime,proto3" json:"lockTime,omitempty"` - SubnetworkId string `protobuf:"bytes,6,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` - Gas uint64 `protobuf:"varint,7,opt,name=gas,proto3" json:"gas,omitempty"` - PayloadHash string `protobuf:"bytes,8,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` - Payload string `protobuf:"bytes,9,opt,name=payload,proto3" json:"payload,omitempty"` - TransactionVerboseInputs []*TransactionVerboseInput `protobuf:"bytes,10,rep,name=transactionVerboseInputs,proto3" json:"transactionVerboseInputs,omitempty"` - TransactionVerboseOutputs []*TransactionVerboseOutput `protobuf:"bytes,11,rep,name=transactionVerboseOutputs,proto3" json:"transactionVerboseOutputs,omitempty"` - BlockHash string `protobuf:"bytes,12,opt,name=blockHash,proto3" json:"blockHash,omitempty"` - Time uint64 `protobuf:"varint,13,opt,name=time,proto3" json:"time,omitempty"` - BlockTime uint64 `protobuf:"varint,14,opt,name=blockTime,proto3" json:"blockTime,omitempty"` -} - -func (x *TransactionVerboseData) Reset() { - *x = TransactionVerboseData{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[73] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionVerboseData) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionVerboseData) ProtoMessage() {} - -func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[73] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. -func (*TransactionVerboseData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{73} -} - -func (x *TransactionVerboseData) GetTxId() string { - if x != nil { - return x.TxId - } - return "" -} - -func (x *TransactionVerboseData) GetHash() string { - if x != nil { - return x.Hash - } - return "" -} - -func (x *TransactionVerboseData) GetSize() uint64 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *TransactionVerboseData) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *TransactionVerboseData) GetLockTime() uint64 { - if x != nil { - return x.LockTime - } - return 0 -} - -func (x *TransactionVerboseData) GetSubnetworkId() string { - if x != nil { - return x.SubnetworkId - } - return "" -} - -func (x *TransactionVerboseData) GetGas() uint64 { - if x != nil { - return x.Gas - } - return 0 -} - -func (x *TransactionVerboseData) GetPayloadHash() string { - if x != nil { - return x.PayloadHash - } - return "" -} - -func (x *TransactionVerboseData) GetPayload() string { - if x != nil { - return x.Payload - } - return "" -} - -func (x *TransactionVerboseData) GetTransactionVerboseInputs() []*TransactionVerboseInput { - if x != nil { - return x.TransactionVerboseInputs - } - return nil -} - -func (x *TransactionVerboseData) GetTransactionVerboseOutputs() []*TransactionVerboseOutput { - if x != nil { - return x.TransactionVerboseOutputs - } - return nil -} - -func (x *TransactionVerboseData) GetBlockHash() string { - if x != nil { - return x.BlockHash - } - return "" -} - -func (x *TransactionVerboseData) GetTime() uint64 { - if x != nil { - return x.Time - } - return 0 -} - -func (x *TransactionVerboseData) GetBlockTime() uint64 { - if x != nil { - return x.BlockTime - } - return 0 -} - -type TransactionVerboseInput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` - OutputIndex uint32 `protobuf:"varint,2,opt,name=outputIndex,proto3" json:"outputIndex,omitempty"` - ScriptSig *ScriptSig `protobuf:"bytes,3,opt,name=scriptSig,proto3" json:"scriptSig,omitempty"` - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` -} - -func (x *TransactionVerboseInput) Reset() { - *x = TransactionVerboseInput{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[74] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionVerboseInput) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionVerboseInput) ProtoMessage() {} - -func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[74] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. -func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{74} -} - -func (x *TransactionVerboseInput) GetTxId() string { - if x != nil { - return x.TxId - } - return "" -} - -func (x *TransactionVerboseInput) GetOutputIndex() uint32 { - if x != nil { - return x.OutputIndex - } - return 0 -} - -func (x *TransactionVerboseInput) GetScriptSig() *ScriptSig { - if x != nil { - return x.ScriptSig - } - return nil -} - -func (x *TransactionVerboseInput) GetSequence() uint64 { - if x != nil { - return x.Sequence - } - return 0 -} - -type ScriptSig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Asm string `protobuf:"bytes,1,opt,name=asm,proto3" json:"asm,omitempty"` - Hex string `protobuf:"bytes,2,opt,name=hex,proto3" json:"hex,omitempty"` -} - -func (x *ScriptSig) Reset() { - *x = ScriptSig{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[75] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ScriptSig) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ScriptSig) ProtoMessage() {} - -func (x *ScriptSig) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[75] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. -func (*ScriptSig) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{75} -} - -func (x *ScriptSig) GetAsm() string { - if x != nil { - return x.Asm - } - return "" -} - -func (x *ScriptSig) GetHex() string { - if x != nil { - return x.Hex - } - return "" -} - -type TransactionVerboseOutput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` - Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` - ScriptPublicKey *ScriptPublicKeyResult `protobuf:"bytes,3,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` -} - -func (x *TransactionVerboseOutput) Reset() { - *x = TransactionVerboseOutput{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[76] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionVerboseOutput) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionVerboseOutput) ProtoMessage() {} - -func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[76] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. -func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{76} -} - -func (x *TransactionVerboseOutput) GetValue() uint64 { - if x != nil { - return x.Value - } - return 0 -} - -func (x *TransactionVerboseOutput) GetIndex() uint32 { - if x != nil { - return x.Index - } - return 0 -} - -func (x *TransactionVerboseOutput) GetScriptPublicKey() *ScriptPublicKeyResult { - if x != nil { - return x.ScriptPublicKey - } - return nil -} - -type ScriptPublicKeyResult struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Asm string `protobuf:"bytes,1,opt,name=asm,proto3" json:"asm,omitempty"` - Hex string `protobuf:"bytes,2,opt,name=hex,proto3" json:"hex,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` -} - -func (x *ScriptPublicKeyResult) Reset() { - *x = ScriptPublicKeyResult{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[77] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ScriptPublicKeyResult) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ScriptPublicKeyResult) ProtoMessage() {} - -func (x *ScriptPublicKeyResult) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[77] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ScriptPublicKeyResult.ProtoReflect.Descriptor instead. -func (*ScriptPublicKeyResult) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{77} -} - -func (x *ScriptPublicKeyResult) GetAsm() string { - if x != nil { - return x.Asm - } - return "" -} - -func (x *ScriptPublicKeyResult) GetHex() string { - if x != nil { - return x.Hex - } - return "" -} - -func (x *ScriptPublicKeyResult) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *ScriptPublicKeyResult) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -type GetSubnetworkRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SubnetworkId string `protobuf:"bytes,1,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` -} - -func (x *GetSubnetworkRequestMessage) Reset() { - *x = GetSubnetworkRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[78] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetSubnetworkRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetSubnetworkRequestMessage) ProtoMessage() {} - -func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[78] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. -func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{78} -} - -func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { - if x != nil { - return x.SubnetworkId - } - return "" -} - -type GetSubnetworkResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - GasLimit uint64 `protobuf:"varint,1,opt,name=gasLimit,proto3" json:"gasLimit,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetSubnetworkResponseMessage) Reset() { - *x = GetSubnetworkResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[79] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetSubnetworkResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetSubnetworkResponseMessage) ProtoMessage() {} - -func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[79] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. -func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{79} -} - -func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { - if x != nil { - return x.GasLimit - } - return 0 -} - -func (x *GetSubnetworkResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetVirtualSelectedParentChainFromBlockRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - StartHash string `protobuf:"bytes,1,opt,name=startHash,proto3" json:"startHash,omitempty"` -} - -func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { - *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[80] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} - -func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[80] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. -func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{80} -} - -func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { - if x != nil { - return x.StartHash - } - return "" -} - -type GetVirtualSelectedParentChainFromBlockResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RemovedChainBlockHashes []string `protobuf:"bytes,1,rep,name=removedChainBlockHashes,proto3" json:"removedChainBlockHashes,omitempty"` - AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { - *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[81] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} - -func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[81] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. -func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{81} -} - -func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { - if x != nil { - return x.RemovedChainBlockHashes - } - return nil -} - -func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetAddedChainBlocks() []*ChainBlock { - if x != nil { - return x.AddedChainBlocks - } - return nil -} - -func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetBlocksRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - LowHash string `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` - IncludeBlockHexes bool `protobuf:"varint,2,opt,name=includeBlockHexes,proto3" json:"includeBlockHexes,omitempty"` - IncludeBlockVerboseData bool `protobuf:"varint,3,opt,name=includeBlockVerboseData,proto3" json:"includeBlockVerboseData,omitempty"` - IncludeTransactionVerboseData bool `protobuf:"varint,4,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` -} - -func (x *GetBlocksRequestMessage) Reset() { - *x = GetBlocksRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[82] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlocksRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlocksRequestMessage) ProtoMessage() {} - -func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[82] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. -func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{82} -} - -func (x *GetBlocksRequestMessage) GetLowHash() string { - if x != nil { - return x.LowHash - } - return "" -} - -func (x *GetBlocksRequestMessage) GetIncludeBlockHexes() bool { - if x != nil { - return x.IncludeBlockHexes - } - return false -} - -func (x *GetBlocksRequestMessage) GetIncludeBlockVerboseData() bool { - if x != nil { - return x.IncludeBlockVerboseData - } - return false -} - -func (x *GetBlocksRequestMessage) GetIncludeTransactionVerboseData() bool { - if x != nil { - return x.IncludeTransactionVerboseData - } - return false -} - -type GetBlocksResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - BlockHashes []string `protobuf:"bytes,1,rep,name=blockHashes,proto3" json:"blockHashes,omitempty"` - BlockHexes []string `protobuf:"bytes,2,rep,name=blockHexes,proto3" json:"blockHexes,omitempty"` - BlockVerboseData []*BlockVerboseData `protobuf:"bytes,3,rep,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetBlocksResponseMessage) Reset() { - *x = GetBlocksResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[83] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlocksResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlocksResponseMessage) ProtoMessage() {} - -func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[83] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. -func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{83} -} - -func (x *GetBlocksResponseMessage) GetBlockHashes() []string { - if x != nil { - return x.BlockHashes - } - return nil -} - -func (x *GetBlocksResponseMessage) GetBlockHexes() []string { - if x != nil { - return x.BlockHexes - } - return nil -} - -func (x *GetBlocksResponseMessage) GetBlockVerboseData() []*BlockVerboseData { - if x != nil { - return x.BlockVerboseData - } - return nil -} - -func (x *GetBlocksResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetBlockCountRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetBlockCountRequestMessage) Reset() { - *x = GetBlockCountRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[84] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockCountRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockCountRequestMessage) ProtoMessage() {} - -func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[84] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. -func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{84} -} - -type GetBlockCountResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - BlockCount uint64 `protobuf:"varint,1,opt,name=blockCount,proto3" json:"blockCount,omitempty"` - HeaderCount uint64 `protobuf:"varint,2,opt,name=headerCount,proto3" json:"headerCount,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetBlockCountResponseMessage) Reset() { - *x = GetBlockCountResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[85] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockCountResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockCountResponseMessage) ProtoMessage() {} - -func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[85] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. -func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{85} -} - -func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { - if x != nil { - return x.BlockCount - } - return 0 -} - -func (x *GetBlockCountResponseMessage) GetHeaderCount() uint64 { - if x != nil { - return x.HeaderCount - } - return 0 -} - -func (x *GetBlockCountResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetBlockDagInfoRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetBlockDagInfoRequestMessage) Reset() { - *x = GetBlockDagInfoRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[86] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockDagInfoRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} - -func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[86] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. -func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{86} -} - -type GetBlockDagInfoResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - NetworkName string `protobuf:"bytes,1,opt,name=networkName,proto3" json:"networkName,omitempty"` - BlockCount uint64 `protobuf:"varint,2,opt,name=blockCount,proto3" json:"blockCount,omitempty"` - HeaderCount uint64 `protobuf:"varint,3,opt,name=headerCount,proto3" json:"headerCount,omitempty"` - TipHashes []string `protobuf:"bytes,4,rep,name=tipHashes,proto3" json:"tipHashes,omitempty"` - Difficulty float64 `protobuf:"fixed64,5,opt,name=difficulty,proto3" json:"difficulty,omitempty"` - PastMedianTime int64 `protobuf:"varint,6,opt,name=pastMedianTime,proto3" json:"pastMedianTime,omitempty"` - VirtualParentHashes []string `protobuf:"bytes,7,rep,name=virtualParentHashes,proto3" json:"virtualParentHashes,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetBlockDagInfoResponseMessage) Reset() { - *x = GetBlockDagInfoResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[87] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetBlockDagInfoResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} - -func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[87] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. -func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{87} -} - -func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { - if x != nil { - return x.NetworkName - } - return "" -} - -func (x *GetBlockDagInfoResponseMessage) GetBlockCount() uint64 { - if x != nil { - return x.BlockCount - } - return 0 -} - -func (x *GetBlockDagInfoResponseMessage) GetHeaderCount() uint64 { - if x != nil { - return x.HeaderCount - } - return 0 -} - -func (x *GetBlockDagInfoResponseMessage) GetTipHashes() []string { - if x != nil { - return x.TipHashes - } - return nil -} - -func (x *GetBlockDagInfoResponseMessage) GetDifficulty() float64 { - if x != nil { - return x.Difficulty - } - return 0 -} - -func (x *GetBlockDagInfoResponseMessage) GetPastMedianTime() int64 { - if x != nil { - return x.PastMedianTime - } - return 0 -} - -func (x *GetBlockDagInfoResponseMessage) GetVirtualParentHashes() []string { - if x != nil { - return x.VirtualParentHashes - } - return nil -} - -func (x *GetBlockDagInfoResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type ResolveFinalityConflictRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FinalityBlockHash string `protobuf:"bytes,1,opt,name=finalityBlockHash,proto3" json:"finalityBlockHash,omitempty"` -} - -func (x *ResolveFinalityConflictRequestMessage) Reset() { - *x = ResolveFinalityConflictRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[88] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ResolveFinalityConflictRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} - -func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[88] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. -func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{88} -} - -func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { - if x != nil { - return x.FinalityBlockHash - } - return "" -} - -type ResolveFinalityConflictResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *ResolveFinalityConflictResponseMessage) Reset() { - *x = ResolveFinalityConflictResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[89] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ResolveFinalityConflictResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} - -func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[89] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. -func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{89} -} - -func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type NotifyFinalityConflictsRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *NotifyFinalityConflictsRequestMessage) Reset() { - *x = NotifyFinalityConflictsRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[90] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyFinalityConflictsRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} - -func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[90] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. -func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{90} -} - -type NotifyFinalityConflictsResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *NotifyFinalityConflictsResponseMessage) Reset() { - *x = NotifyFinalityConflictsResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[91] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyFinalityConflictsResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} - -func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[91] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. -func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{91} -} - -func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type FinalityConflictNotificationMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ViolatingBlockHash string `protobuf:"bytes,1,opt,name=violatingBlockHash,proto3" json:"violatingBlockHash,omitempty"` -} - -func (x *FinalityConflictNotificationMessage) Reset() { - *x = FinalityConflictNotificationMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[92] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FinalityConflictNotificationMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FinalityConflictNotificationMessage) ProtoMessage() {} - -func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[92] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. -func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{92} -} - -func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { - if x != nil { - return x.ViolatingBlockHash - } - return "" -} - -type FinalityConflictResolvedNotificationMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FinalityBlockHash string `protobuf:"bytes,1,opt,name=finalityBlockHash,proto3" json:"finalityBlockHash,omitempty"` -} - -func (x *FinalityConflictResolvedNotificationMessage) Reset() { - *x = FinalityConflictResolvedNotificationMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[93] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FinalityConflictResolvedNotificationMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} - -func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[93] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. -func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{93} -} - -func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { - if x != nil { - return x.FinalityBlockHash - } - return "" -} - -type ShutDownRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *ShutDownRequestMessage) Reset() { - *x = ShutDownRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[94] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ShutDownRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ShutDownRequestMessage) ProtoMessage() {} - -func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[94] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. -func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{94} -} - -type ShutDownResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *ShutDownResponseMessage) Reset() { - *x = ShutDownResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[95] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ShutDownResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ShutDownResponseMessage) ProtoMessage() {} - -func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[95] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. -func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{95} -} - -func (x *ShutDownResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetHeadersRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - StartHash string `protobuf:"bytes,1,opt,name=startHash,proto3" json:"startHash,omitempty"` - Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - IsAscending bool `protobuf:"varint,3,opt,name=isAscending,proto3" json:"isAscending,omitempty"` -} - -func (x *GetHeadersRequestMessage) Reset() { - *x = GetHeadersRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[96] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetHeadersRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetHeadersRequestMessage) ProtoMessage() {} - -func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[96] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. -func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{96} -} - -func (x *GetHeadersRequestMessage) GetStartHash() string { - if x != nil { - return x.StartHash - } - return "" -} - -func (x *GetHeadersRequestMessage) GetLimit() uint64 { - if x != nil { - return x.Limit - } - return 0 -} - -func (x *GetHeadersRequestMessage) GetIsAscending() bool { - if x != nil { - return x.IsAscending - } - return false -} - -type GetHeadersResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Headers []string `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetHeadersResponseMessage) Reset() { - *x = GetHeadersResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[97] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetHeadersResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetHeadersResponseMessage) ProtoMessage() {} - -func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[97] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. -func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{97} -} - -func (x *GetHeadersResponseMessage) GetHeaders() []string { - if x != nil { - return x.Headers - } - return nil -} - -func (x *GetHeadersResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type NotifyUtxosChangedRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` -} - -func (x *NotifyUtxosChangedRequestMessage) Reset() { - *x = NotifyUtxosChangedRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[98] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyUtxosChangedRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} - -func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[98] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. -func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{98} -} - -func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { - if x != nil { - return x.Addresses - } - return nil -} - -type NotifyUtxosChangedResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *NotifyUtxosChangedResponseMessage) Reset() { - *x = NotifyUtxosChangedResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[99] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyUtxosChangedResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} - -func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[99] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. -func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{99} -} - -func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type UtxosChangedNotificationMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Added []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=added,proto3" json:"added,omitempty"` - Removed []*UtxosByAddressesEntry `protobuf:"bytes,2,rep,name=removed,proto3" json:"removed,omitempty"` -} - -func (x *UtxosChangedNotificationMessage) Reset() { - *x = UtxosChangedNotificationMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[100] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UtxosChangedNotificationMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UtxosChangedNotificationMessage) ProtoMessage() {} - -func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[100] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. -func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{100} -} - -func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { - if x != nil { - return x.Added - } - return nil -} - -func (x *UtxosChangedNotificationMessage) GetRemoved() []*UtxosByAddressesEntry { - if x != nil { - return x.Removed - } - return nil -} - -type UtxosByAddressesEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Outpoint *RpcOutpoint `protobuf:"bytes,2,opt,name=outpoint,proto3" json:"outpoint,omitempty"` - UtxoEntry *RpcUtxoEntry `protobuf:"bytes,3,opt,name=utxoEntry,proto3" json:"utxoEntry,omitempty"` -} - -func (x *UtxosByAddressesEntry) Reset() { - *x = UtxosByAddressesEntry{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[101] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UtxosByAddressesEntry) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UtxosByAddressesEntry) ProtoMessage() {} - -func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[101] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. -func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{101} -} - -func (x *UtxosByAddressesEntry) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - -func (x *UtxosByAddressesEntry) GetOutpoint() *RpcOutpoint { - if x != nil { - return x.Outpoint - } - return nil -} - -func (x *UtxosByAddressesEntry) GetUtxoEntry() *RpcUtxoEntry { - if x != nil { - return x.UtxoEntry - } - return nil -} - -type RpcTransaction struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - Inputs []*RpcTransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` - Outputs []*RpcTransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` - LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` - SubnetworkId string `protobuf:"bytes,5,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` - Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"` - PayloadHash string `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` - Payload string `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` -} - -func (x *RpcTransaction) Reset() { - *x = RpcTransaction{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[102] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RpcTransaction) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RpcTransaction) ProtoMessage() {} - -func (x *RpcTransaction) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[102] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. -func (*RpcTransaction) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{102} -} - -func (x *RpcTransaction) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *RpcTransaction) GetInputs() []*RpcTransactionInput { - if x != nil { - return x.Inputs - } - return nil -} - -func (x *RpcTransaction) GetOutputs() []*RpcTransactionOutput { - if x != nil { - return x.Outputs - } - return nil -} - -func (x *RpcTransaction) GetLockTime() uint64 { - if x != nil { - return x.LockTime - } - return 0 -} - -func (x *RpcTransaction) GetSubnetworkId() string { - if x != nil { - return x.SubnetworkId - } - return "" -} - -func (x *RpcTransaction) GetGas() uint64 { - if x != nil { - return x.Gas - } - return 0 -} - -func (x *RpcTransaction) GetPayloadHash() string { - if x != nil { - return x.PayloadHash - } - return "" -} - -func (x *RpcTransaction) GetPayload() string { - if x != nil { - return x.Payload - } - return "" -} - -type RpcTransactionInput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PreviousOutpoint *RpcOutpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` - SignatureScript string `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` - Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` -} - -func (x *RpcTransactionInput) Reset() { - *x = RpcTransactionInput{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[103] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RpcTransactionInput) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RpcTransactionInput) ProtoMessage() {} - -func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[103] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. -func (*RpcTransactionInput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{103} -} - -func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { - if x != nil { - return x.PreviousOutpoint - } - return nil -} - -func (x *RpcTransactionInput) GetSignatureScript() string { - if x != nil { - return x.SignatureScript - } - return "" -} - -func (x *RpcTransactionInput) GetSequence() uint64 { - if x != nil { - return x.Sequence - } - return 0 -} - -type RpcScriptPublicKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - ScriptPublicKey string `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` -} - -func (x *RpcScriptPublicKey) Reset() { - *x = RpcScriptPublicKey{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[104] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RpcScriptPublicKey) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RpcScriptPublicKey) ProtoMessage() {} - -func (x *RpcScriptPublicKey) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[104] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RpcScriptPublicKey.ProtoReflect.Descriptor instead. -func (*RpcScriptPublicKey) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{104} -} - -func (x *RpcScriptPublicKey) GetVersion() uint32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *RpcScriptPublicKey) GetScriptPublicKey() string { - if x != nil { - return x.ScriptPublicKey - } - return "" -} - -type RpcTransactionOutput struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` - ScriptPublicKey *RpcScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` -} - -func (x *RpcTransactionOutput) Reset() { - *x = RpcTransactionOutput{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[105] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RpcTransactionOutput) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RpcTransactionOutput) ProtoMessage() {} - -func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[105] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. -func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{105} -} - -func (x *RpcTransactionOutput) GetAmount() uint64 { - if x != nil { - return x.Amount - } - return 0 -} - -func (x *RpcTransactionOutput) GetScriptPublicKey() *RpcScriptPublicKey { - if x != nil { - return x.ScriptPublicKey - } - return nil -} - -type RpcOutpoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` - Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` -} - -func (x *RpcOutpoint) Reset() { - *x = RpcOutpoint{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[106] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RpcOutpoint) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RpcOutpoint) ProtoMessage() {} - -func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[106] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. -func (*RpcOutpoint) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{106} -} - -func (x *RpcOutpoint) GetTransactionId() string { - if x != nil { - return x.TransactionId - } - return "" -} - -func (x *RpcOutpoint) GetIndex() uint32 { - if x != nil { - return x.Index - } - return 0 -} - -type RpcUtxoEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` - ScriptPublicKey *RpcScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` - BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` - IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` -} - -func (x *RpcUtxoEntry) Reset() { - *x = RpcUtxoEntry{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[107] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RpcUtxoEntry) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RpcUtxoEntry) ProtoMessage() {} - -func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[107] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. -func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{107} -} - -func (x *RpcUtxoEntry) GetAmount() uint64 { - if x != nil { - return x.Amount - } - return 0 -} - -func (x *RpcUtxoEntry) GetScriptPublicKey() *RpcScriptPublicKey { - if x != nil { - return x.ScriptPublicKey - } - return nil -} - -func (x *RpcUtxoEntry) GetBlockBlueScore() uint64 { - if x != nil { - return x.BlockBlueScore - } - return 0 -} - -func (x *RpcUtxoEntry) GetIsCoinbase() bool { - if x != nil { - return x.IsCoinbase - } - return false -} - -type GetUtxosByAddressesRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` -} - -func (x *GetUtxosByAddressesRequestMessage) Reset() { - *x = GetUtxosByAddressesRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[108] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetUtxosByAddressesRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} - -func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[108] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. -func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{108} -} - -func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { - if x != nil { - return x.Addresses - } - return nil -} - -type GetUtxosByAddressesResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Entries []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetUtxosByAddressesResponseMessage) Reset() { - *x = GetUtxosByAddressesResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[109] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetUtxosByAddressesResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} - -func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[109] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. -func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{109} -} - -func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { - if x != nil { - return x.Entries - } - return nil -} - -func (x *GetUtxosByAddressesResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type GetVirtualSelectedParentBlueScoreRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { - *x = GetVirtualSelectedParentBlueScoreRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[110] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} - -func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[110] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. -func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{110} -} - -type GetVirtualSelectedParentBlueScoreResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - BlueScore uint64 `protobuf:"varint,1,opt,name=blueScore,proto3" json:"blueScore,omitempty"` - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { - *x = GetVirtualSelectedParentBlueScoreResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[111] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} - -func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[111] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. -func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{111} -} - -func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { - if x != nil { - return x.BlueScore - } - return 0 -} - -func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { - *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[112] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[112] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. -func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{112} -} - -type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` -} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { - *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[113] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[113] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. -func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{113} -} - -func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { - if x != nil { - return x.Error - } - return nil -} - -type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - VirtualSelectedParentBlueScore uint64 `protobuf:"varint,1,opt,name=virtualSelectedParentBlueScore,proto3" json:"virtualSelectedParentBlueScore,omitempty"` -} - -func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { - *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[114] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} - -func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[114] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. -func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{114} -} - -func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { - if x != nil { - return x.VirtualSelectedParentBlueScore - } - return 0 -} - var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0xd6, 0x45, 0x0a, 0x0d, - 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, - 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x0b, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x59, - 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, - 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x12, 0x4a, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, - 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x44, 0x6f, 0x6e, - 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xd6, 0x45, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x12, 0x2f, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x41, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, + 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, + 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x44, + 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0b, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x56, + 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x59, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x35, 0x0a, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x08, + 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x2c, + 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x32, 0x0a, 0x06, + 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, + 0x12, 0x35, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x15, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, + 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x16, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, + 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, + 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x77, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, + 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x69, - 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x08, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x47, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x69, 0x6e, - 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x4d, 0x0a, 0x0f, 0x69, - 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0f, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x49, 0x6e, 0x76, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x69, - 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x2c, 0x0a, 0x04, 0x70, 0x6f, 0x6e, 0x67, - 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x04, 0x70, 0x6f, 0x6e, 0x67, 0x12, 0x32, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, - 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x72, 0x61, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x59, 0x0a, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, - 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, - 0x12, 0x77, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, - 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x62, 0x0a, 0x16, 0x69, 0x62, 0x64, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, + 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, + 0x62, 0x0a, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, + 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, + 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, - 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, - 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, - 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, - 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, - 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x56, - 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, + 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, + 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, + 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x69, 0x62, - 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, - 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, - 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, - 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, - 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x69, - 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, - 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, - 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, + 0x48, 0x00, 0x52, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, + 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, + 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, + 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, + 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, + 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, + 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, + 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, + 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, + 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, + 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, - 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, - 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, + 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, - 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, - 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, - 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, - 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, + 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x14, 0x67, - 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, 0x52, 0x15, - 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 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, 0x48, - 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, + 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, + 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, - 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, - 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, - 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, - 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x1e, 0x6e, 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, 0x12, - 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, - 0x6e, 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, 0x12, - 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, - 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, - 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, - 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, - 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, - 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, - 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, - 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, 0x0a, 0x0c, - 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, - 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, - 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3f, 0x0a, - 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, - 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x43, 0x0a, - 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x22, 0x6f, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 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, 0x44, 0x0a, - 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0c, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, - 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, - 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x68, - 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x43, 0x0a, - 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, - 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, 0x61, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, - 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, 0x74, 0x78, - 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, - 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, - 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, - 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3e, - 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x6f, - 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, - 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x22, - 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, - 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x6c, - 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, - 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, 0x49, 0x6e, - 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x23, 0x0a, - 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, - 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x61, 0x63, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x26, - 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, - 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, - 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, - 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, - 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, 0x42, 0x44, - 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x74, - 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x74, 0x78, - 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, - 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, - 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, - 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, - 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, - 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x58, - 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 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, - 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 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, 0x4e, 0x0a, 0x1d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, - 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, - 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, - 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 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, - 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, - 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x33, 0x0a, 0x1d, - 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, - 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, - 0x72, 0x79, 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, 0x21, - 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, - 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, 0xd3, 0x02, - 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, - 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, - 0x65, 0x65, 0x72, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, - 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, - 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, - 0x65, 0x65, 0x72, 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, 0x5e, - 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, - 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, - 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, - 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, - 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, - 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, - 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 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, 0x0d, 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, 0x92, 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, 0x4a, - 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, - 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, - 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, - 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, - 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, - 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, - 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, - 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, - 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, - 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, - 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, - 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, - 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, + 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, + 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, + 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, + 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, 0x18, 0x8d, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, + 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, + 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, + 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, + 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, + 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, + 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, - 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 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, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 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, 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 ( @@ -9059,312 +1886,193 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 115) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_messages_proto_goTypes = []interface{}{ (*KaspadMessage)(nil), // 0: protowire.KaspadMessage - (*RequestAddressesMessage)(nil), // 1: protowire.RequestAddressesMessage - (*AddressesMessage)(nil), // 2: protowire.AddressesMessage - (*NetAddress)(nil), // 3: protowire.NetAddress - (*SubnetworkId)(nil), // 4: protowire.SubnetworkId - (*TransactionMessage)(nil), // 5: protowire.TransactionMessage - (*TransactionInput)(nil), // 6: protowire.TransactionInput - (*Outpoint)(nil), // 7: protowire.Outpoint - (*TransactionId)(nil), // 8: protowire.TransactionId - (*ScriptPublicKey)(nil), // 9: protowire.ScriptPublicKey - (*TransactionOutput)(nil), // 10: protowire.TransactionOutput - (*BlockMessage)(nil), // 11: protowire.BlockMessage - (*BlockHeaderMessage)(nil), // 12: protowire.BlockHeaderMessage - (*Hash)(nil), // 13: protowire.Hash - (*RequestBlockLocatorMessage)(nil), // 14: protowire.RequestBlockLocatorMessage - (*BlockLocatorMessage)(nil), // 15: protowire.BlockLocatorMessage - (*RequestHeadersMessage)(nil), // 16: protowire.RequestHeadersMessage - (*RequestNextHeadersMessage)(nil), // 17: protowire.RequestNextHeadersMessage - (*DoneHeadersMessage)(nil), // 18: protowire.DoneHeadersMessage - (*RequestRelayBlocksMessage)(nil), // 19: protowire.RequestRelayBlocksMessage - (*RequestTransactionsMessage)(nil), // 20: protowire.RequestTransactionsMessage - (*TransactionNotFoundMessage)(nil), // 21: protowire.TransactionNotFoundMessage - (*InvRelayBlockMessage)(nil), // 22: protowire.InvRelayBlockMessage - (*InvTransactionsMessage)(nil), // 23: protowire.InvTransactionsMessage - (*PingMessage)(nil), // 24: protowire.PingMessage - (*PongMessage)(nil), // 25: protowire.PongMessage - (*VerackMessage)(nil), // 26: protowire.VerackMessage - (*VersionMessage)(nil), // 27: protowire.VersionMessage - (*RejectMessage)(nil), // 28: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IBDRootUTXOSetAndBlockMessage)(nil), // 30: protowire.IBDRootUTXOSetAndBlockMessage - (*RequestIBDBlocksMessage)(nil), // 31: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 32: protowire.IBDRootNotFoundMessage - (*RequestIBDRootHashMessage)(nil), // 33: protowire.RequestIBDRootHashMessage - (*IBDRootHashMessage)(nil), // 34: protowire.IBDRootHashMessage - (*IbdBlockLocatorMessage)(nil), // 35: protowire.IbdBlockLocatorMessage - (*IbdBlockLocatorHighestHashMessage)(nil), // 36: protowire.IbdBlockLocatorHighestHashMessage - (*BlockHeadersMessage)(nil), // 37: protowire.BlockHeadersMessage - (*RPCError)(nil), // 38: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 39: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 40: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 41: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 42: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 43: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 44: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 45: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 46: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 47: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 48: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 49: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 50: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 51: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 52: protowire.GetSelectedTipHashResponseMessage - (*MempoolEntry)(nil), // 53: protowire.MempoolEntry - (*GetMempoolEntryRequestMessage)(nil), // 54: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 55: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 56: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 57: protowire.GetMempoolEntriesResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 58: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 59: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 60: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 61: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 62: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 63: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 64: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 65: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 66: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 67: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*ChainBlock)(nil), // 68: protowire.ChainBlock - (*AcceptedBlock)(nil), // 69: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 70: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 71: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 72: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 73: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 74: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 75: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 76: protowire.TransactionVerboseOutput - (*ScriptPublicKeyResult)(nil), // 77: protowire.ScriptPublicKeyResult - (*GetSubnetworkRequestMessage)(nil), // 78: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 79: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 80: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 81: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 82: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 83: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 84: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 85: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 86: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 87: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 88: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 89: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 90: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 91: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 92: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 93: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 94: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 95: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 96: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 97: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 98: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 99: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 100: protowire.UtxosChangedNotificationMessage - (*UtxosByAddressesEntry)(nil), // 101: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 102: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 103: protowire.RpcTransactionInput - (*RpcScriptPublicKey)(nil), // 104: protowire.RpcScriptPublicKey - (*RpcTransactionOutput)(nil), // 105: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 106: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 107: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 108: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 109: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 110: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 111: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 112: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 113: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 114: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*AddressesMessage)(nil), // 1: protowire.AddressesMessage + (*BlockMessage)(nil), // 2: protowire.BlockMessage + (*TransactionMessage)(nil), // 3: protowire.TransactionMessage + (*RequestBlockLocatorMessage)(nil), // 4: protowire.RequestBlockLocatorMessage + (*BlockLocatorMessage)(nil), // 5: protowire.BlockLocatorMessage + (*RequestAddressesMessage)(nil), // 6: protowire.RequestAddressesMessage + (*RequestHeadersMessage)(nil), // 7: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 8: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 9: protowire.DoneHeadersMessage + (*RequestRelayBlocksMessage)(nil), // 10: protowire.RequestRelayBlocksMessage + (*RequestTransactionsMessage)(nil), // 11: protowire.RequestTransactionsMessage + (*InvRelayBlockMessage)(nil), // 12: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 13: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 14: protowire.PingMessage + (*PongMessage)(nil), // 15: protowire.PongMessage + (*VerackMessage)(nil), // 16: protowire.VerackMessage + (*VersionMessage)(nil), // 17: protowire.VersionMessage + (*TransactionNotFoundMessage)(nil), // 18: protowire.TransactionNotFoundMessage + (*RejectMessage)(nil), // 19: protowire.RejectMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 20: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IBDRootUTXOSetAndBlockMessage)(nil), // 21: protowire.IBDRootUTXOSetAndBlockMessage + (*RequestIBDBlocksMessage)(nil), // 22: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 23: protowire.IBDRootNotFoundMessage + (*RequestIBDRootHashMessage)(nil), // 24: protowire.RequestIBDRootHashMessage + (*IBDRootHashMessage)(nil), // 25: protowire.IBDRootHashMessage + (*IbdBlockLocatorMessage)(nil), // 26: protowire.IbdBlockLocatorMessage + (*IbdBlockLocatorHighestHashMessage)(nil), // 27: protowire.IbdBlockLocatorHighestHashMessage + (*BlockHeadersMessage)(nil), // 28: protowire.BlockHeadersMessage + (*GetCurrentNetworkRequestMessage)(nil), // 29: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 30: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 31: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 32: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 33: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 34: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 35: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 36: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 37: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 38: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 39: protowire.GetPeerAddressesResponseMessage + (*GetSelectedTipHashRequestMessage)(nil), // 40: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 41: protowire.GetSelectedTipHashResponseMessage + (*GetMempoolEntryRequestMessage)(nil), // 42: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 43: protowire.GetMempoolEntryResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 44: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 45: protowire.GetConnectedPeerInfoResponseMessage + (*AddPeerRequestMessage)(nil), // 46: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 47: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 48: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 49: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 50: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 51: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 52: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*GetBlockRequestMessage)(nil), // 53: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 54: protowire.GetBlockResponseMessage + (*GetSubnetworkRequestMessage)(nil), // 55: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 56: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 57: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 58: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 59: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 60: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 61: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 62: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 63: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 64: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 65: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 66: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 67: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 68: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 69: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 70: protowire.FinalityConflictResolvedNotificationMessage + (*GetMempoolEntriesRequestMessage)(nil), // 71: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 72: protowire.GetMempoolEntriesResponseMessage + (*ShutDownRequestMessage)(nil), // 73: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 74: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 75: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 76: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 77: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 78: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 79: protowire.UtxosChangedNotificationMessage + (*GetUtxosByAddressesRequestMessage)(nil), // 80: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 81: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 82: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 83: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 84: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 85: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 86: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ - 2, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage - 11, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage - 5, // 2: protowire.KaspadMessage.transaction:type_name -> protowire.TransactionMessage - 14, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage - 15, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage - 1, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage - 16, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage - 17, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage - 18, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage - 19, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage - 20, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage - 11, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage - 22, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage - 23, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage - 24, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage - 25, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage - 26, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage - 27, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage - 21, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage - 28, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 29, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage - 30, // 21: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage - 31, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 32, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 33, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage - 34, // 25: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage - 35, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage - 36, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage - 37, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage - 39, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 40, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 41, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 42, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 43, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 44, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 45, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 46, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 47, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 48, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 49, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 51, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 52, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 54, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 55, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 58, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 59, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 61, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 62, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 63, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 64, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 65, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 66, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 67, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 70, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 71, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 78, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 79, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 80, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 81, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 82, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 83, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 84, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 85, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 86, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 87, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 88, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 89, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 90, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 91, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 92, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 93, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 56, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 57, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 94, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 95, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 96, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 97, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 98, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 99, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 100, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 108, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 109, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 110, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 111, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 112, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 113, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 114, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 4, // 87: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId - 3, // 88: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress - 6, // 89: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput - 10, // 90: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput - 4, // 91: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 13, // 92: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash - 7, // 93: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint - 8, // 94: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId - 9, // 95: protowire.TransactionOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKey - 12, // 96: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage - 5, // 97: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage - 13, // 98: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash - 13, // 99: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash - 13, // 100: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash - 13, // 101: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash - 13, // 102: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash - 13, // 103: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash - 13, // 104: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash - 13, // 105: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash - 13, // 106: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash - 13, // 107: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash - 8, // 108: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId - 8, // 109: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId - 13, // 110: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash - 8, // 111: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId - 3, // 112: protowire.VersionMessage.address:type_name -> protowire.NetAddress - 4, // 113: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 13, // 114: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 11, // 115: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 13, // 116: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 13, // 117: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash - 13, // 118: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash - 13, // 119: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash - 13, // 120: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash - 12, // 121: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage - 38, // 122: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 11, // 123: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 38, // 124: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 11, // 125: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 38, // 126: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 38, // 127: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 11, // 128: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 50, // 129: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 50, // 130: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 38, // 131: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 38, // 132: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 73, // 133: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 53, // 134: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 38, // 135: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 53, // 136: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 38, // 137: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 60, // 138: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 38, // 139: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 38, // 140: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 102, // 141: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 38, // 142: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 38, // 143: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 68, // 144: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 69, // 145: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 72, // 146: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 38, // 147: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 73, // 148: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 74, // 149: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 76, // 150: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 75, // 151: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 77, // 152: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult - 38, // 153: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 68, // 154: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 38, // 155: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 72, // 156: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 38, // 157: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 38, // 158: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 38, // 159: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 38, // 160: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 38, // 161: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 38, // 162: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 38, // 163: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 38, // 164: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 101, // 165: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 101, // 166: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 106, // 167: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 107, // 168: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 103, // 169: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 105, // 170: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 106, // 171: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 104, // 172: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 104, // 173: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 101, // 174: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 38, // 175: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 38, // 176: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 38, // 177: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 0, // 178: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 179: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 180: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 181: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 180, // [180:182] is the sub-list for method output_type - 178, // [178:180] is the sub-list for method input_type - 178, // [178:178] is the sub-list for extension type_name - 178, // [178:178] is the sub-list for extension extendee - 0, // [0:178] is the sub-list for field type_name + 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage + 2, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage + 3, // 2: protowire.KaspadMessage.transaction:type_name -> protowire.TransactionMessage + 4, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage + 5, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage + 6, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage + 7, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage + 8, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage + 9, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage + 10, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage + 11, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage + 2, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage + 12, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage + 13, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage + 14, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage + 15, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage + 16, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage + 17, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage + 18, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage + 19, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage + 20, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage + 21, // 21: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage + 22, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage + 23, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage + 24, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage + 25, // 25: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage + 26, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage + 27, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage + 28, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage + 29, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 30, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 31, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 32, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 33, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 34, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 35, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 36, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 37, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 38, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 39, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 40, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 41, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 42, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 43, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 44, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 45, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 46, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 47, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 48, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 49, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 50, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 51, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 52, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 53, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 54, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 55, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 56, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 57, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 58, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 59, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 60, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 61, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 62, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 63, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 64, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 65, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 66, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 67, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 68, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 69, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 70, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 71, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 72, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 73, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 74, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 75, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 76, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 77, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 78, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 79, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 80, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 81, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 82, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 83, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 84, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 85, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 86, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 0, // 87: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 88: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 89: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 90: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 89, // [89:91] is the sub-list for method output_type + 87, // [87:89] is the sub-list for method input_type + 87, // [87:87] is the sub-list for extension type_name + 87, // [87:87] is the sub-list for extension extendee + 0, // [0:87] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -9372,6 +2080,8 @@ func file_messages_proto_init() { if File_messages_proto != nil { return } + file_p2p_proto_init() + file_rpc_proto_init() if !protoimpl.UnsafeEnabled { file_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*KaspadMessage); i { @@ -9385,1374 +2095,6 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestAddressesMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddressesMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NetAddress); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubnetworkId); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionInput); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Outpoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionId); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPublicKey); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionOutput); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockHeaderMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Hash); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestBlockLocatorMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockLocatorMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestHeadersMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestNextHeadersMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DoneHeadersMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestRelayBlocksMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestTransactionsMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionNotFoundMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InvRelayBlockMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InvTransactionsMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PongMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VerackMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RejectMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDBlocksMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootNotFoundMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootHashMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootHashMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorHighestHashMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockHeadersMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCError); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCurrentNetworkResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitBlockResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockTemplateResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyBlockAddedResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockAddedNotificationMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPeerAddressesKnownAddressMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSelectedTipHashResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MempoolEntry); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntryResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMempoolEntriesResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConnectedPeerInfoMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddPeerResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitTransactionResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChainBlock); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptedBlock); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlockVerboseData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseInput); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptSig); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionVerboseOutput); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ScriptPublicKeyResult); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSubnetworkResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlocksResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[85].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockCountResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[86].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[87].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBlockDagInfoResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[88].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[89].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResolveFinalityConflictResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[90].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[91].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyFinalityConflictsResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[92].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictNotificationMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[93].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FinalityConflictResolvedNotificationMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[94].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[95].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutDownResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[96].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[97].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHeadersResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[98].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[99].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyUtxosChangedResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[100].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosChangedNotificationMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[101].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UtxosByAddressesEntry); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[102].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransaction); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionInput); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcScriptPublicKey); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionOutput); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcOutpoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcUtxoEntry); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[112].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[113].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[114].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } file_messages_proto_msgTypes[0].OneofWrappers = []interface{}{ (*KaspadMessage_Addresses)(nil), @@ -10849,7 +2191,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 115, + NumMessages: 1, NumExtensions: 0, NumServices: 2, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 5d8913a64..f22669001 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -3,6 +3,9 @@ package protowire; option go_package = "github.com/kaspanet/kaspad/protowire"; +import "p2p.proto"; +import "rpc.proto"; + message KaspadMessage { oneof payload { AddressesMessage addresses = 1; @@ -96,660 +99,10 @@ message KaspadMessage { } } -///////////////////////////////////////////////////////////////////////////// -// P2P // -///////////////////////////////////////////////////////////////////////////// - -// RequestAddressesMessage start -message RequestAddressesMessage{ - bool includeAllSubnetworks = 1; - SubnetworkId subnetworkId = 2; -} -// RequestAddressesMessage end - -// AddressesMessage start -message AddressesMessage{ - repeated NetAddress addressList = 1; -} - -message NetAddress{ - int64 timestamp = 1; - uint64 services = 2; - bytes ip = 3; - uint32 port = 4; -} - -message SubnetworkId{ - bytes bytes = 1; -} -// AddressesMessage end - -// TransactionMessage start -message TransactionMessage{ - uint32 version = 1; - repeated TransactionInput inputs = 2; - repeated TransactionOutput outputs = 3; - uint64 lockTime = 4; - SubnetworkId subnetworkId = 5; - uint64 gas = 6; - Hash payloadHash = 7; - bytes payload = 8; -} - -message TransactionInput{ - Outpoint previousOutpoint = 1; - bytes signatureScript = 2; - uint64 sequence = 3; -} - -message Outpoint{ - TransactionId transactionId = 1; - uint32 index = 2; -} - -message TransactionId{ - bytes bytes = 1; -} -message ScriptPublicKey { - bytes script = 1; - uint32 version = 2; -} - -message TransactionOutput{ - uint64 value = 1; - ScriptPublicKey scriptPublicKey = 2; -} -// TransactionMessage end - -// BlockMessage start -message BlockMessage{ - BlockHeaderMessage header = 1; - repeated TransactionMessage transactions = 2; -} - -message BlockHeaderMessage{ - uint32 version = 1; - repeated Hash parentHashes = 2; - Hash hashMerkleRoot = 3; - Hash acceptedIdMerkleRoot = 4; - Hash utxoCommitment = 5; - int64 timestamp = 6; - uint32 bits = 7; - uint64 nonce = 8; -} - -message Hash{ - bytes bytes = 1; -} -// BlockMessage end - -// GetBlockLocatorMessage start -message RequestBlockLocatorMessage{ - Hash lowHash = 1; - Hash highHash = 2; - uint32 limit = 3; -} -// GetBlockLocatorMessage end - -// BlockLocatorMessage start -message BlockLocatorMessage{ - repeated Hash hashes = 1; -} -// BlockLocatorMessage end - -// GetBlocksMessage start -message RequestHeadersMessage{ - Hash lowHash = 1; - Hash highHash = 2; -} -// GetBlocksMessage end - -// RequestNextIBDBlocksMessage start -message RequestNextHeadersMessage{ -} -// RequestNextIBDBlocksMessage end - -// DoneIBDBlocksMessage start -message DoneHeadersMessage{ -} -// DoneIBDBlocksMessage end - -// RequestRelayBlocksMessage start -message RequestRelayBlocksMessage{ - repeated Hash hashes = 1; -} -// RequestRelayBlocksMessage end - -// RequestTransactionsMessage start -message RequestTransactionsMessage { - repeated TransactionId ids = 1; -} -// GetTransactionsMessage end - -// TransactionNotFoundMessage start -message TransactionNotFoundMessage{ - TransactionId id = 1; -} -// TransactionsNotFoundMessage end - -// InvRelayBlockMessage start -message InvRelayBlockMessage{ - Hash hash = 1; -} -// InvRelayBlockMessage end - -// InvTransactionMessage start -message InvTransactionsMessage{ - repeated TransactionId ids = 1; -} -// InvTransactionMessage end - -// PingMessage start -message PingMessage{ - uint64 nonce = 1; -} -// PingMessage end - -// PongMessage start -message PongMessage{ - uint64 nonce = 1; -} -// PongMessage end - -// VerackMessage start -message VerackMessage{ -} -// VerackMessage end - -// VersionMessage start -message VersionMessage{ - uint32 protocolVersion = 1; - uint64 services = 2; - int64 timestamp = 3; - NetAddress address = 4; - bytes id = 5; - string userAgent = 6; - bool disableRelayTx = 8; - SubnetworkId subnetworkId = 9; - string network = 10; -} -// VersionMessage end - -// RejectMessage start -message RejectMessage{ - string reason = 1; -} -// RejectMessage end - -// RequestIBDRootUTXOSetAndBlockMessage start -message RequestIBDRootUTXOSetAndBlockMessage{ - Hash ibdRoot = 1; -} -// RequestIBDRootUTXOSetAndBlockMessage end - -// IBDRootUTXOSetAndBlockMessage start -message IBDRootUTXOSetAndBlockMessage{ - bytes utxoSet = 1; - BlockMessage block = 2; -} -// IBDRootUTXOSetAndBlockMessage end - -// RequestIBDBlocksMessage start -message RequestIBDBlocksMessage{ - repeated Hash hashes = 1; -} -// RequestIBDBlocksMessage end - -// IBDRootNotFoundMessage start -message IBDRootNotFoundMessage{ -} -// IBDRootNotFoundMessage end - -// RequestIBDRootHashMessage start -message RequestIBDRootHashMessage{ -} -// RequestIBDRootHashMessage end - -// IBDRootHashMessage start -message IBDRootHashMessage{ - Hash hash = 1; -} -// IBDRootHashMessage end - -// IbdBlockLocatorMessage start -message IbdBlockLocatorMessage { - Hash targetHash = 1; - repeated Hash blockLocatorHashes = 2; -} -// IbdBlockLocatorMessage end - -// IbdBlockLocatorHighestHashMessage start -message IbdBlockLocatorHighestHashMessage { - Hash highestHash = 1; -} -// IbdBlockLocatorHighestHashMessage end - -message BlockHeadersMessage { - repeated BlockHeaderMessage blockHeaders = 1; -} - service P2P { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} } -///////////////////////////////////////////////////////////////////////////// -// RPC // -///////////////////////////////////////////////////////////////////////////// - -message RPCError{ - string message = 1; -} - -message GetCurrentNetworkRequestMessage{ -} - -message GetCurrentNetworkResponseMessage{ - string currentNetwork = 1; - RPCError error = 1000; -} - -message SubmitBlockRequestMessage{ - BlockMessage block = 1; -} - -message SubmitBlockResponseMessage{ - RPCError error = 1000; -} - -message GetBlockTemplateRequestMessage{ - string payAddress = 1; -} - -message GetBlockTemplateResponseMessage{ - BlockMessage blockMessage = 1; - bool isSynced = 2; - - RPCError error = 1000; -} - -message NotifyBlockAddedRequestMessage{ -} - -message NotifyBlockAddedResponseMessage{ - RPCError error = 1000; -} - -message BlockAddedNotificationMessage{ - BlockMessage block = 1; -} - -message GetPeerAddressesRequestMessage{ -} - -message GetPeerAddressesResponseMessage{ - repeated GetPeerAddressesKnownAddressMessage addresses = 1; - repeated GetPeerAddressesKnownAddressMessage bannedAddresses = 2; - RPCError error = 1000; -} - -message GetPeerAddressesKnownAddressMessage { - string Addr = 1; -} - -message GetSelectedTipHashRequestMessage{ -} - -message GetSelectedTipHashResponseMessage{ - string selectedTipHash = 1; - RPCError error = 1000; -} - -// mempool entries start -message MempoolEntry{ - uint64 fee = 1; - TransactionVerboseData transactionVerboseData = 2; -} - -message GetMempoolEntryRequestMessage{ - string txId = 1; -} - -message GetMempoolEntryResponseMessage{ - MempoolEntry entry = 1; - - RPCError error = 1000; -} - -message GetMempoolEntriesRequestMessage{ -} - -message GetMempoolEntriesResponseMessage{ - repeated MempoolEntry entries = 1; - - RPCError error = 1000; -} -// mempool entries end - -message GetConnectedPeerInfoRequestMessage{ -} - -message GetConnectedPeerInfoResponseMessage{ - repeated GetConnectedPeerInfoMessage infos = 1; - RPCError error = 1000; -} - -message GetConnectedPeerInfoMessage{ - string id = 1; - string address = 2; - int64 lastPingDuration = 3; - bool isOutbound = 6; - int64 timeOffset = 7; - string userAgent = 8; - uint32 advertisedProtocolVersion = 9; - int64 timeConnected = 10; - bool isIbdPeer = 11; -} - -message AddPeerRequestMessage{ - string address = 1; - bool isPermanent = 2; -} - -message AddPeerResponseMessage{ - RPCError error = 1000; -} - -message SubmitTransactionRequestMessage{ - RpcTransaction transaction = 1; -} - -message SubmitTransactionResponseMessage{ - string transactionId = 1; - - RPCError error = 1000; -} - -message NotifyVirtualSelectedParentChainChangedRequestMessage{ -} - -message NotifyVirtualSelectedParentChainChangedResponseMessage{ - RPCError error = 1000; -} - -message VirtualSelectedParentChainChangedNotificationMessage{ - repeated string removedChainBlockHashes = 1; - repeated ChainBlock addedChainBlocks = 2; -} - -message ChainBlock{ - string hash = 1; - repeated AcceptedBlock acceptedBlocks = 2; -} - -message AcceptedBlock{ - string hash = 1; - repeated string acceptedTransactionIds = 2; -} - -message GetBlockRequestMessage{ - string hash = 1; - string subnetworkId = 2; - bool includeTransactionVerboseData = 3; -} - -message GetBlockResponseMessage{ - string blockHash = 1; - BlockVerboseData blockVerboseData = 2; - RPCError error = 1000; -} - -message BlockVerboseData{ - string hash = 1; - uint32 version = 2; - string versionHex = 3; - string hashMerkleRoot = 4; - string acceptedIDMerkleRoot = 5; - string utxoCommitment = 6; - repeated TransactionVerboseData transactionVerboseData = 7; - int64 time = 8; - uint64 nonce = 9; - string bits = 10; - double difficulty = 11; - repeated string parentHashes = 12; - string selectedParentHash = 13; - repeated string transactionIDs = 14; - bool isHeaderOnly = 15; - uint64 blueScore = 16; -} - -message TransactionVerboseData{ - string txId = 1; - string hash = 2; - uint64 size = 3; - uint32 version = 4; - uint64 lockTime = 5; - string subnetworkId = 6; - uint64 gas = 7; - string payloadHash = 8; - string payload = 9; - repeated TransactionVerboseInput transactionVerboseInputs = 10; - repeated TransactionVerboseOutput transactionVerboseOutputs = 11; - string blockHash = 12; - uint64 time = 13; - uint64 blockTime = 14; -} - -message TransactionVerboseInput{ - string txId = 1; - uint32 outputIndex = 2; - ScriptSig scriptSig = 3; - uint64 sequence = 4; -} - -message ScriptSig{ - string asm = 1; - string hex = 2; -} - -message TransactionVerboseOutput{ - uint64 value = 1; - uint32 index = 2; - ScriptPublicKeyResult scriptPublicKey = 3; -} - -message ScriptPublicKeyResult{ - string asm = 1; - string hex = 2; - string type = 3; - string address = 4; -} - -message GetSubnetworkRequestMessage{ - string subnetworkId = 1; -} - -message GetSubnetworkResponseMessage{ - uint64 gasLimit = 1; - RPCError error = 1000; -} - -message GetVirtualSelectedParentChainFromBlockRequestMessage{ - string startHash = 1; -} - -message GetVirtualSelectedParentChainFromBlockResponseMessage{ - repeated string removedChainBlockHashes = 1; - repeated ChainBlock addedChainBlocks = 2; - - RPCError error = 1000; -} - -message GetBlocksRequestMessage{ - string lowHash = 1; - bool includeBlockHexes = 2; - bool includeBlockVerboseData = 3; - bool includeTransactionVerboseData = 4; -} - -message GetBlocksResponseMessage{ - repeated string blockHashes = 1; - repeated string blockHexes = 2; - repeated BlockVerboseData blockVerboseData = 3; - RPCError error = 1000; -} - -message GetBlockCountRequestMessage{ -} - -message GetBlockCountResponseMessage{ - uint64 blockCount = 1; - uint64 headerCount = 2; - RPCError error = 1000; -} - -message GetBlockDagInfoRequestMessage{ -} - -message GetBlockDagInfoResponseMessage{ - string networkName = 1; - uint64 blockCount = 2; - uint64 headerCount = 3; - repeated string tipHashes = 4; - double difficulty = 5; - int64 pastMedianTime = 6; - repeated string virtualParentHashes = 7; - RPCError error = 1000; -} - -message ResolveFinalityConflictRequestMessage{ - string finalityBlockHash = 1; -} - -message ResolveFinalityConflictResponseMessage{ - RPCError error = 1000; -} - -message NotifyFinalityConflictsRequestMessage{ -} - -message NotifyFinalityConflictsResponseMessage{ - RPCError error = 1000; -} - -message FinalityConflictNotificationMessage{ - string violatingBlockHash = 1; -} - -message FinalityConflictResolvedNotificationMessage{ - string finalityBlockHash = 1; -} - -message ShutDownRequestMessage{ -} - -message ShutDownResponseMessage{ - RPCError error = 1000; -} - -message GetHeadersRequestMessage{ - string startHash = 1; - uint64 limit = 2; - bool isAscending = 3; -} - -message GetHeadersResponseMessage{ - repeated string headers = 1; - RPCError error = 1000; -} - -message NotifyUtxosChangedRequestMessage { - repeated string addresses = 1; -} - -message NotifyUtxosChangedResponseMessage { - RPCError error = 1000; -} - -message UtxosChangedNotificationMessage { - repeated UtxosByAddressesEntry added = 1; - repeated UtxosByAddressesEntry removed = 2; -} - -message UtxosByAddressesEntry { - string address = 1; - RpcOutpoint outpoint = 2; - RpcUtxoEntry utxoEntry = 3; -} - -message RpcTransaction { - uint32 version = 1; - repeated RpcTransactionInput inputs = 2; - repeated RpcTransactionOutput outputs = 3; - uint64 lockTime = 4; - string subnetworkId = 5; - uint64 gas = 6; - string payloadHash = 7; - string payload = 8; -} - -message RpcTransactionInput { - RpcOutpoint previousOutpoint = 1; - string signatureScript = 2; - uint64 sequence = 3; -} - -message RpcScriptPublicKey { - uint32 version = 1; - string scriptPublicKey = 2; -} - -message RpcTransactionOutput { - uint64 amount = 1; - RpcScriptPublicKey scriptPublicKey = 2; -} - -message RpcOutpoint { - string transactionId = 1; - uint32 index = 2; -} - -message RpcUtxoEntry { - uint64 amount = 1; - RpcScriptPublicKey scriptPublicKey = 2; - uint64 blockBlueScore = 3; - bool isCoinbase = 4; -} - -message GetUtxosByAddressesRequestMessage { - repeated string addresses = 1; -} - -message GetUtxosByAddressesResponseMessage { - repeated UtxosByAddressesEntry entries = 1; - - RPCError error = 1000; -} - -message GetVirtualSelectedParentBlueScoreRequestMessage { -} - -message GetVirtualSelectedParentBlueScoreResponseMessage { - uint64 blueScore = 1; - - RPCError error = 1000; -} - -message NotifyVirtualSelectedParentBlueScoreChangedRequestMessage { -} - -message NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { - RPCError error = 1000; -} - -message VirtualSelectedParentBlueScoreChangedNotificationMessage { - uint64 virtualSelectedParentBlueScore = 1; -} - service RPC { rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} } \ No newline at end of file diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go new file mode 100644 index 000000000..8fc332a65 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go @@ -0,0 +1,2843 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.12.3 +// source: p2p.proto + +package protowire + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// RequestAddressesMessage start +type RequestAddressesMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IncludeAllSubnetworks bool `protobuf:"varint,1,opt,name=includeAllSubnetworks,proto3" json:"includeAllSubnetworks,omitempty"` + SubnetworkId *SubnetworkId `protobuf:"bytes,2,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` +} + +func (x *RequestAddressesMessage) Reset() { + *x = RequestAddressesMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestAddressesMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestAddressesMessage) ProtoMessage() {} + +func (x *RequestAddressesMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestAddressesMessage.ProtoReflect.Descriptor instead. +func (*RequestAddressesMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{0} +} + +func (x *RequestAddressesMessage) GetIncludeAllSubnetworks() bool { + if x != nil { + return x.IncludeAllSubnetworks + } + return false +} + +func (x *RequestAddressesMessage) GetSubnetworkId() *SubnetworkId { + if x != nil { + return x.SubnetworkId + } + return nil +} + +// AddressesMessage start +type AddressesMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressList []*NetAddress `protobuf:"bytes,1,rep,name=addressList,proto3" json:"addressList,omitempty"` +} + +func (x *AddressesMessage) Reset() { + *x = AddressesMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddressesMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddressesMessage) ProtoMessage() {} + +func (x *AddressesMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddressesMessage.ProtoReflect.Descriptor instead. +func (*AddressesMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{1} +} + +func (x *AddressesMessage) GetAddressList() []*NetAddress { + if x != nil { + return x.AddressList + } + return nil +} + +type NetAddress struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Services uint64 `protobuf:"varint,2,opt,name=services,proto3" json:"services,omitempty"` + Ip []byte `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"` + Port uint32 `protobuf:"varint,4,opt,name=port,proto3" json:"port,omitempty"` +} + +func (x *NetAddress) Reset() { + *x = NetAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NetAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetAddress) ProtoMessage() {} + +func (x *NetAddress) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetAddress.ProtoReflect.Descriptor instead. +func (*NetAddress) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{2} +} + +func (x *NetAddress) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *NetAddress) GetServices() uint64 { + if x != nil { + return x.Services + } + return 0 +} + +func (x *NetAddress) GetIp() []byte { + if x != nil { + return x.Ip + } + return nil +} + +func (x *NetAddress) GetPort() uint32 { + if x != nil { + return x.Port + } + return 0 +} + +type SubnetworkId struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` +} + +func (x *SubnetworkId) Reset() { + *x = SubnetworkId{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubnetworkId) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubnetworkId) ProtoMessage() {} + +func (x *SubnetworkId) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubnetworkId.ProtoReflect.Descriptor instead. +func (*SubnetworkId) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{3} +} + +func (x *SubnetworkId) GetBytes() []byte { + if x != nil { + return x.Bytes + } + return nil +} + +// TransactionMessage start +type TransactionMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Inputs []*TransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*TransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` + LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` + SubnetworkId *SubnetworkId `protobuf:"bytes,5,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"` + PayloadHash *Hash `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` + Payload []byte `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *TransactionMessage) Reset() { + *x = TransactionMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionMessage) ProtoMessage() {} + +func (x *TransactionMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionMessage.ProtoReflect.Descriptor instead. +func (*TransactionMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{4} +} + +func (x *TransactionMessage) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *TransactionMessage) GetInputs() []*TransactionInput { + if x != nil { + return x.Inputs + } + return nil +} + +func (x *TransactionMessage) GetOutputs() []*TransactionOutput { + if x != nil { + return x.Outputs + } + return nil +} + +func (x *TransactionMessage) GetLockTime() uint64 { + if x != nil { + return x.LockTime + } + return 0 +} + +func (x *TransactionMessage) GetSubnetworkId() *SubnetworkId { + if x != nil { + return x.SubnetworkId + } + return nil +} + +func (x *TransactionMessage) GetGas() uint64 { + if x != nil { + return x.Gas + } + return 0 +} + +func (x *TransactionMessage) GetPayloadHash() *Hash { + if x != nil { + return x.PayloadHash + } + return nil +} + +func (x *TransactionMessage) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +type TransactionInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PreviousOutpoint *Outpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` + SignatureScript []byte `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` + Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (x *TransactionInput) Reset() { + *x = TransactionInput{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionInput) ProtoMessage() {} + +func (x *TransactionInput) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionInput.ProtoReflect.Descriptor instead. +func (*TransactionInput) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{5} +} + +func (x *TransactionInput) GetPreviousOutpoint() *Outpoint { + if x != nil { + return x.PreviousOutpoint + } + return nil +} + +func (x *TransactionInput) GetSignatureScript() []byte { + if x != nil { + return x.SignatureScript + } + return nil +} + +func (x *TransactionInput) GetSequence() uint64 { + if x != nil { + return x.Sequence + } + return 0 +} + +type Outpoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TransactionId *TransactionId `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` +} + +func (x *Outpoint) Reset() { + *x = Outpoint{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Outpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Outpoint) ProtoMessage() {} + +func (x *Outpoint) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Outpoint.ProtoReflect.Descriptor instead. +func (*Outpoint) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{6} +} + +func (x *Outpoint) GetTransactionId() *TransactionId { + if x != nil { + return x.TransactionId + } + return nil +} + +func (x *Outpoint) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +type TransactionId struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` +} + +func (x *TransactionId) Reset() { + *x = TransactionId{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionId) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionId) ProtoMessage() {} + +func (x *TransactionId) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionId.ProtoReflect.Descriptor instead. +func (*TransactionId) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{7} +} + +func (x *TransactionId) GetBytes() []byte { + if x != nil { + return x.Bytes + } + return nil +} + +type ScriptPublicKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Script []byte `protobuf:"bytes,1,opt,name=script,proto3" json:"script,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` +} + +func (x *ScriptPublicKey) Reset() { + *x = ScriptPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScriptPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScriptPublicKey) ProtoMessage() {} + +func (x *ScriptPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScriptPublicKey.ProtoReflect.Descriptor instead. +func (*ScriptPublicKey) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{8} +} + +func (x *ScriptPublicKey) GetScript() []byte { + if x != nil { + return x.Script + } + return nil +} + +func (x *ScriptPublicKey) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +type TransactionOutput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + ScriptPublicKey *ScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` +} + +func (x *TransactionOutput) Reset() { + *x = TransactionOutput{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionOutput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionOutput) ProtoMessage() {} + +func (x *TransactionOutput) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionOutput.ProtoReflect.Descriptor instead. +func (*TransactionOutput) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{9} +} + +func (x *TransactionOutput) GetValue() uint64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *TransactionOutput) GetScriptPublicKey() *ScriptPublicKey { + if x != nil { + return x.ScriptPublicKey + } + return nil +} + +// BlockMessage start +type BlockMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Header *BlockHeaderMessage `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + Transactions []*TransactionMessage `protobuf:"bytes,2,rep,name=transactions,proto3" json:"transactions,omitempty"` +} + +func (x *BlockMessage) Reset() { + *x = BlockMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockMessage) ProtoMessage() {} + +func (x *BlockMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockMessage.ProtoReflect.Descriptor instead. +func (*BlockMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{10} +} + +func (x *BlockMessage) GetHeader() *BlockHeaderMessage { + if x != nil { + return x.Header + } + return nil +} + +func (x *BlockMessage) GetTransactions() []*TransactionMessage { + if x != nil { + return x.Transactions + } + return nil +} + +type BlockHeaderMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + ParentHashes []*Hash `protobuf:"bytes,2,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` + HashMerkleRoot *Hash `protobuf:"bytes,3,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` + AcceptedIdMerkleRoot *Hash `protobuf:"bytes,4,opt,name=acceptedIdMerkleRoot,proto3" json:"acceptedIdMerkleRoot,omitempty"` + UtxoCommitment *Hash `protobuf:"bytes,5,opt,name=utxoCommitment,proto3" json:"utxoCommitment,omitempty"` + Timestamp int64 `protobuf:"varint,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Bits uint32 `protobuf:"varint,7,opt,name=bits,proto3" json:"bits,omitempty"` + Nonce uint64 `protobuf:"varint,8,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (x *BlockHeaderMessage) Reset() { + *x = BlockHeaderMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockHeaderMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockHeaderMessage) ProtoMessage() {} + +func (x *BlockHeaderMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockHeaderMessage.ProtoReflect.Descriptor instead. +func (*BlockHeaderMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{11} +} + +func (x *BlockHeaderMessage) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *BlockHeaderMessage) GetParentHashes() []*Hash { + if x != nil { + return x.ParentHashes + } + return nil +} + +func (x *BlockHeaderMessage) GetHashMerkleRoot() *Hash { + if x != nil { + return x.HashMerkleRoot + } + return nil +} + +func (x *BlockHeaderMessage) GetAcceptedIdMerkleRoot() *Hash { + if x != nil { + return x.AcceptedIdMerkleRoot + } + return nil +} + +func (x *BlockHeaderMessage) GetUtxoCommitment() *Hash { + if x != nil { + return x.UtxoCommitment + } + return nil +} + +func (x *BlockHeaderMessage) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *BlockHeaderMessage) GetBits() uint32 { + if x != nil { + return x.Bits + } + return 0 +} + +func (x *BlockHeaderMessage) GetNonce() uint64 { + if x != nil { + return x.Nonce + } + return 0 +} + +type Hash struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` +} + +func (x *Hash) Reset() { + *x = Hash{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Hash) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Hash) ProtoMessage() {} + +func (x *Hash) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Hash.ProtoReflect.Descriptor instead. +func (*Hash) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{12} +} + +func (x *Hash) GetBytes() []byte { + if x != nil { + return x.Bytes + } + return nil +} + +// GetBlockLocatorMessage start +type RequestBlockLocatorMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LowHash *Hash `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` + HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` + Limit uint32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` +} + +func (x *RequestBlockLocatorMessage) Reset() { + *x = RequestBlockLocatorMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestBlockLocatorMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestBlockLocatorMessage) ProtoMessage() {} + +func (x *RequestBlockLocatorMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestBlockLocatorMessage.ProtoReflect.Descriptor instead. +func (*RequestBlockLocatorMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{13} +} + +func (x *RequestBlockLocatorMessage) GetLowHash() *Hash { + if x != nil { + return x.LowHash + } + return nil +} + +func (x *RequestBlockLocatorMessage) GetHighHash() *Hash { + if x != nil { + return x.HighHash + } + return nil +} + +func (x *RequestBlockLocatorMessage) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +// BlockLocatorMessage start +type BlockLocatorMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` +} + +func (x *BlockLocatorMessage) Reset() { + *x = BlockLocatorMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockLocatorMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockLocatorMessage) ProtoMessage() {} + +func (x *BlockLocatorMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockLocatorMessage.ProtoReflect.Descriptor instead. +func (*BlockLocatorMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{14} +} + +func (x *BlockLocatorMessage) GetHashes() []*Hash { + if x != nil { + return x.Hashes + } + return nil +} + +// GetBlocksMessage start +type RequestHeadersMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LowHash *Hash `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` + HighHash *Hash `protobuf:"bytes,2,opt,name=highHash,proto3" json:"highHash,omitempty"` +} + +func (x *RequestHeadersMessage) Reset() { + *x = RequestHeadersMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestHeadersMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestHeadersMessage) ProtoMessage() {} + +func (x *RequestHeadersMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestHeadersMessage.ProtoReflect.Descriptor instead. +func (*RequestHeadersMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{15} +} + +func (x *RequestHeadersMessage) GetLowHash() *Hash { + if x != nil { + return x.LowHash + } + return nil +} + +func (x *RequestHeadersMessage) GetHighHash() *Hash { + if x != nil { + return x.HighHash + } + return nil +} + +// RequestNextIBDBlocksMessage start +type RequestNextHeadersMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RequestNextHeadersMessage) Reset() { + *x = RequestNextHeadersMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestNextHeadersMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestNextHeadersMessage) ProtoMessage() {} + +func (x *RequestNextHeadersMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestNextHeadersMessage.ProtoReflect.Descriptor instead. +func (*RequestNextHeadersMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{16} +} + +// DoneIBDBlocksMessage start +type DoneHeadersMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DoneHeadersMessage) Reset() { + *x = DoneHeadersMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DoneHeadersMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DoneHeadersMessage) ProtoMessage() {} + +func (x *DoneHeadersMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DoneHeadersMessage.ProtoReflect.Descriptor instead. +func (*DoneHeadersMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{17} +} + +// RequestRelayBlocksMessage start +type RequestRelayBlocksMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` +} + +func (x *RequestRelayBlocksMessage) Reset() { + *x = RequestRelayBlocksMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestRelayBlocksMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestRelayBlocksMessage) ProtoMessage() {} + +func (x *RequestRelayBlocksMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestRelayBlocksMessage.ProtoReflect.Descriptor instead. +func (*RequestRelayBlocksMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{18} +} + +func (x *RequestRelayBlocksMessage) GetHashes() []*Hash { + if x != nil { + return x.Hashes + } + return nil +} + +// RequestTransactionsMessage start +type RequestTransactionsMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []*TransactionId `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` +} + +func (x *RequestTransactionsMessage) Reset() { + *x = RequestTransactionsMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestTransactionsMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestTransactionsMessage) ProtoMessage() {} + +func (x *RequestTransactionsMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestTransactionsMessage.ProtoReflect.Descriptor instead. +func (*RequestTransactionsMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{19} +} + +func (x *RequestTransactionsMessage) GetIds() []*TransactionId { + if x != nil { + return x.Ids + } + return nil +} + +// TransactionNotFoundMessage start +type TransactionNotFoundMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id *TransactionId `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *TransactionNotFoundMessage) Reset() { + *x = TransactionNotFoundMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionNotFoundMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionNotFoundMessage) ProtoMessage() {} + +func (x *TransactionNotFoundMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionNotFoundMessage.ProtoReflect.Descriptor instead. +func (*TransactionNotFoundMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{20} +} + +func (x *TransactionNotFoundMessage) GetId() *TransactionId { + if x != nil { + return x.Id + } + return nil +} + +// InvRelayBlockMessage start +type InvRelayBlockMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (x *InvRelayBlockMessage) Reset() { + *x = InvRelayBlockMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvRelayBlockMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvRelayBlockMessage) ProtoMessage() {} + +func (x *InvRelayBlockMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvRelayBlockMessage.ProtoReflect.Descriptor instead. +func (*InvRelayBlockMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{21} +} + +func (x *InvRelayBlockMessage) GetHash() *Hash { + if x != nil { + return x.Hash + } + return nil +} + +// InvTransactionMessage start +type InvTransactionsMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []*TransactionId `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` +} + +func (x *InvTransactionsMessage) Reset() { + *x = InvTransactionsMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InvTransactionsMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InvTransactionsMessage) ProtoMessage() {} + +func (x *InvTransactionsMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InvTransactionsMessage.ProtoReflect.Descriptor instead. +func (*InvTransactionsMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{22} +} + +func (x *InvTransactionsMessage) GetIds() []*TransactionId { + if x != nil { + return x.Ids + } + return nil +} + +// PingMessage start +type PingMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (x *PingMessage) Reset() { + *x = PingMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PingMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingMessage) ProtoMessage() {} + +func (x *PingMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingMessage.ProtoReflect.Descriptor instead. +func (*PingMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{23} +} + +func (x *PingMessage) GetNonce() uint64 { + if x != nil { + return x.Nonce + } + return 0 +} + +// PongMessage start +type PongMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (x *PongMessage) Reset() { + *x = PongMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PongMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PongMessage) ProtoMessage() {} + +func (x *PongMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PongMessage.ProtoReflect.Descriptor instead. +func (*PongMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{24} +} + +func (x *PongMessage) GetNonce() uint64 { + if x != nil { + return x.Nonce + } + return 0 +} + +// VerackMessage start +type VerackMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *VerackMessage) Reset() { + *x = VerackMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerackMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerackMessage) ProtoMessage() {} + +func (x *VerackMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerackMessage.ProtoReflect.Descriptor instead. +func (*VerackMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{25} +} + +// VersionMessage start +type VersionMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProtocolVersion uint32 `protobuf:"varint,1,opt,name=protocolVersion,proto3" json:"protocolVersion,omitempty"` + Services uint64 `protobuf:"varint,2,opt,name=services,proto3" json:"services,omitempty"` + Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Address *NetAddress `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` + Id []byte `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` + UserAgent string `protobuf:"bytes,6,opt,name=userAgent,proto3" json:"userAgent,omitempty"` + DisableRelayTx bool `protobuf:"varint,8,opt,name=disableRelayTx,proto3" json:"disableRelayTx,omitempty"` + SubnetworkId *SubnetworkId `protobuf:"bytes,9,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + Network string `protobuf:"bytes,10,opt,name=network,proto3" json:"network,omitempty"` +} + +func (x *VersionMessage) Reset() { + *x = VersionMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VersionMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VersionMessage) ProtoMessage() {} + +func (x *VersionMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VersionMessage.ProtoReflect.Descriptor instead. +func (*VersionMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{26} +} + +func (x *VersionMessage) GetProtocolVersion() uint32 { + if x != nil { + return x.ProtocolVersion + } + return 0 +} + +func (x *VersionMessage) GetServices() uint64 { + if x != nil { + return x.Services + } + return 0 +} + +func (x *VersionMessage) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *VersionMessage) GetAddress() *NetAddress { + if x != nil { + return x.Address + } + return nil +} + +func (x *VersionMessage) GetId() []byte { + if x != nil { + return x.Id + } + return nil +} + +func (x *VersionMessage) GetUserAgent() string { + if x != nil { + return x.UserAgent + } + return "" +} + +func (x *VersionMessage) GetDisableRelayTx() bool { + if x != nil { + return x.DisableRelayTx + } + return false +} + +func (x *VersionMessage) GetSubnetworkId() *SubnetworkId { + if x != nil { + return x.SubnetworkId + } + return nil +} + +func (x *VersionMessage) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +// RejectMessage start +type RejectMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` +} + +func (x *RejectMessage) Reset() { + *x = RejectMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RejectMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RejectMessage) ProtoMessage() {} + +func (x *RejectMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RejectMessage.ProtoReflect.Descriptor instead. +func (*RejectMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{27} +} + +func (x *RejectMessage) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +// RequestIBDRootUTXOSetAndBlockMessage start +type RequestIBDRootUTXOSetAndBlockMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IbdRoot *Hash `protobuf:"bytes,1,opt,name=ibdRoot,proto3" json:"ibdRoot,omitempty"` +} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { + *x = RequestIBDRootUTXOSetAndBlockMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestIBDRootUTXOSetAndBlockMessage) ProtoMessage() {} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestIBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. +func (*RequestIBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{28} +} + +func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { + if x != nil { + return x.IbdRoot + } + return nil +} + +// IBDRootUTXOSetAndBlockMessage start +type IBDRootUTXOSetAndBlockMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UtxoSet []byte `protobuf:"bytes,1,opt,name=utxoSet,proto3" json:"utxoSet,omitempty"` + Block *BlockMessage `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` +} + +func (x *IBDRootUTXOSetAndBlockMessage) Reset() { + *x = IBDRootUTXOSetAndBlockMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IBDRootUTXOSetAndBlockMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IBDRootUTXOSetAndBlockMessage) ProtoMessage() {} + +func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. +func (*IBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{29} +} + +func (x *IBDRootUTXOSetAndBlockMessage) GetUtxoSet() []byte { + if x != nil { + return x.UtxoSet + } + return nil +} + +func (x *IBDRootUTXOSetAndBlockMessage) GetBlock() *BlockMessage { + if x != nil { + return x.Block + } + return nil +} + +// RequestIBDBlocksMessage start +type RequestIBDBlocksMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hashes []*Hash `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty"` +} + +func (x *RequestIBDBlocksMessage) Reset() { + *x = RequestIBDBlocksMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestIBDBlocksMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestIBDBlocksMessage) ProtoMessage() {} + +func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. +func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{30} +} + +func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { + if x != nil { + return x.Hashes + } + return nil +} + +// IBDRootNotFoundMessage start +type IBDRootNotFoundMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *IBDRootNotFoundMessage) Reset() { + *x = IBDRootNotFoundMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IBDRootNotFoundMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IBDRootNotFoundMessage) ProtoMessage() {} + +func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. +func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{31} +} + +// RequestIBDRootHashMessage start +type RequestIBDRootHashMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RequestIBDRootHashMessage) Reset() { + *x = RequestIBDRootHashMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestIBDRootHashMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestIBDRootHashMessage) ProtoMessage() {} + +func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestIBDRootHashMessage.ProtoReflect.Descriptor instead. +func (*RequestIBDRootHashMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{32} +} + +// IBDRootHashMessage start +type IBDRootHashMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (x *IBDRootHashMessage) Reset() { + *x = IBDRootHashMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IBDRootHashMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IBDRootHashMessage) ProtoMessage() {} + +func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IBDRootHashMessage.ProtoReflect.Descriptor instead. +func (*IBDRootHashMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{33} +} + +func (x *IBDRootHashMessage) GetHash() *Hash { + if x != nil { + return x.Hash + } + return nil +} + +// IbdBlockLocatorMessage start +type IbdBlockLocatorMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TargetHash *Hash `protobuf:"bytes,1,opt,name=targetHash,proto3" json:"targetHash,omitempty"` + BlockLocatorHashes []*Hash `protobuf:"bytes,2,rep,name=blockLocatorHashes,proto3" json:"blockLocatorHashes,omitempty"` +} + +func (x *IbdBlockLocatorMessage) Reset() { + *x = IbdBlockLocatorMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IbdBlockLocatorMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IbdBlockLocatorMessage) ProtoMessage() {} + +func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IbdBlockLocatorMessage.ProtoReflect.Descriptor instead. +func (*IbdBlockLocatorMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{34} +} + +func (x *IbdBlockLocatorMessage) GetTargetHash() *Hash { + if x != nil { + return x.TargetHash + } + return nil +} + +func (x *IbdBlockLocatorMessage) GetBlockLocatorHashes() []*Hash { + if x != nil { + return x.BlockLocatorHashes + } + return nil +} + +// IbdBlockLocatorHighestHashMessage start +type IbdBlockLocatorHighestHashMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HighestHash *Hash `protobuf:"bytes,1,opt,name=highestHash,proto3" json:"highestHash,omitempty"` +} + +func (x *IbdBlockLocatorHighestHashMessage) Reset() { + *x = IbdBlockLocatorHighestHashMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IbdBlockLocatorHighestHashMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IbdBlockLocatorHighestHashMessage) ProtoMessage() {} + +func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IbdBlockLocatorHighestHashMessage.ProtoReflect.Descriptor instead. +func (*IbdBlockLocatorHighestHashMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{35} +} + +func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { + if x != nil { + return x.HighestHash + } + return nil +} + +type BlockHeadersMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockHeaders []*BlockHeaderMessage `protobuf:"bytes,1,rep,name=blockHeaders,proto3" json:"blockHeaders,omitempty"` +} + +func (x *BlockHeadersMessage) Reset() { + *x = BlockHeadersMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockHeadersMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockHeadersMessage) ProtoMessage() {} + +func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. +func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{36} +} + +func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { + if x != nil { + return x.BlockHeaders + } + return nil +} + +var File_p2p_proto protoreflect.FileDescriptor + +var file_p2p_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x34, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x22, 0x6a, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x24, + 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, + 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, + 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x31, 0x0a, + 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 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, 0x08, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x99, 0x01, 0x0a, 0x10, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, + 0x3f, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, + 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x25, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, + 0x43, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x6f, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 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, + 0x44, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, + 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0xe2, 0x02, 0x0a, 0x12, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, + 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, + 0x43, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, + 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x14, + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x64, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, + 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x37, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0e, 0x75, + 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x62, + 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x1c, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, + 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, + 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x22, 0x3e, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x22, 0x6f, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6c, 0x6f, 0x77, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x07, 0x6c, 0x6f, 0x77, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x2b, 0x0a, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x68, 0x69, 0x67, 0x68, 0x48, 0x61, 0x73, + 0x68, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, + 0x0a, 0x12, 0x44, 0x6f, 0x6e, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x1a, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, + 0x03, 0x69, 0x64, 0x73, 0x22, 0x46, 0x0a, 0x1a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x28, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3b, 0x0a, 0x14, + 0x49, 0x6e, 0x76, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x44, 0x0a, 0x16, 0x49, 0x6e, 0x76, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, + 0x23, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, + 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x23, 0x0a, 0x0b, 0x50, 0x6f, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x56, 0x65, 0x72, + 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, 0x0e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, + 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x2f, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, + 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x54, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x78, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, + 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, + 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, + 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, + 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, + 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, + 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, + 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, + 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, + 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 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 ( + file_p2p_proto_rawDescOnce sync.Once + file_p2p_proto_rawDescData = file_p2p_proto_rawDesc +) + +func file_p2p_proto_rawDescGZIP() []byte { + file_p2p_proto_rawDescOnce.Do(func() { + file_p2p_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_proto_rawDescData) + }) + return file_p2p_proto_rawDescData +} + +var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 37) +var file_p2p_proto_goTypes = []interface{}{ + (*RequestAddressesMessage)(nil), // 0: protowire.RequestAddressesMessage + (*AddressesMessage)(nil), // 1: protowire.AddressesMessage + (*NetAddress)(nil), // 2: protowire.NetAddress + (*SubnetworkId)(nil), // 3: protowire.SubnetworkId + (*TransactionMessage)(nil), // 4: protowire.TransactionMessage + (*TransactionInput)(nil), // 5: protowire.TransactionInput + (*Outpoint)(nil), // 6: protowire.Outpoint + (*TransactionId)(nil), // 7: protowire.TransactionId + (*ScriptPublicKey)(nil), // 8: protowire.ScriptPublicKey + (*TransactionOutput)(nil), // 9: protowire.TransactionOutput + (*BlockMessage)(nil), // 10: protowire.BlockMessage + (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage + (*Hash)(nil), // 12: protowire.Hash + (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage + (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage + (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage + (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage + (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage + (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage + (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 23: protowire.PingMessage + (*PongMessage)(nil), // 24: protowire.PongMessage + (*VerackMessage)(nil), // 25: protowire.VerackMessage + (*VersionMessage)(nil), // 26: protowire.VersionMessage + (*RejectMessage)(nil), // 27: protowire.RejectMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage + (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage + (*RequestIBDRootHashMessage)(nil), // 32: protowire.RequestIBDRootHashMessage + (*IBDRootHashMessage)(nil), // 33: protowire.IBDRootHashMessage + (*IbdBlockLocatorMessage)(nil), // 34: protowire.IbdBlockLocatorMessage + (*IbdBlockLocatorHighestHashMessage)(nil), // 35: protowire.IbdBlockLocatorHighestHashMessage + (*BlockHeadersMessage)(nil), // 36: protowire.BlockHeadersMessage +} +var file_p2p_proto_depIdxs = []int32{ + 3, // 0: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId + 2, // 1: protowire.AddressesMessage.addressList:type_name -> protowire.NetAddress + 5, // 2: protowire.TransactionMessage.inputs:type_name -> protowire.TransactionInput + 9, // 3: protowire.TransactionMessage.outputs:type_name -> protowire.TransactionOutput + 3, // 4: protowire.TransactionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 5: protowire.TransactionMessage.payloadHash:type_name -> protowire.Hash + 6, // 6: protowire.TransactionInput.previousOutpoint:type_name -> protowire.Outpoint + 7, // 7: protowire.Outpoint.transactionId:type_name -> protowire.TransactionId + 8, // 8: protowire.TransactionOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKey + 11, // 9: protowire.BlockMessage.header:type_name -> protowire.BlockHeaderMessage + 4, // 10: protowire.BlockMessage.transactions:type_name -> protowire.TransactionMessage + 12, // 11: protowire.BlockHeaderMessage.parentHashes:type_name -> protowire.Hash + 12, // 12: protowire.BlockHeaderMessage.hashMerkleRoot:type_name -> protowire.Hash + 12, // 13: protowire.BlockHeaderMessage.acceptedIdMerkleRoot:type_name -> protowire.Hash + 12, // 14: protowire.BlockHeaderMessage.utxoCommitment:type_name -> protowire.Hash + 12, // 15: protowire.RequestBlockLocatorMessage.lowHash:type_name -> protowire.Hash + 12, // 16: protowire.RequestBlockLocatorMessage.highHash:type_name -> protowire.Hash + 12, // 17: protowire.BlockLocatorMessage.hashes:type_name -> protowire.Hash + 12, // 18: protowire.RequestHeadersMessage.lowHash:type_name -> protowire.Hash + 12, // 19: protowire.RequestHeadersMessage.highHash:type_name -> protowire.Hash + 12, // 20: protowire.RequestRelayBlocksMessage.hashes:type_name -> protowire.Hash + 7, // 21: protowire.RequestTransactionsMessage.ids:type_name -> protowire.TransactionId + 7, // 22: protowire.TransactionNotFoundMessage.id:type_name -> protowire.TransactionId + 12, // 23: protowire.InvRelayBlockMessage.hash:type_name -> protowire.Hash + 7, // 24: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId + 2, // 25: protowire.VersionMessage.address:type_name -> protowire.NetAddress + 3, // 26: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId + 12, // 27: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash + 10, // 28: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage + 12, // 29: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 12, // 30: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash + 12, // 31: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash + 12, // 32: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash + 12, // 33: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash + 11, // 34: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage + 35, // [35:35] is the sub-list for method output_type + 35, // [35:35] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 35, // [35:35] is the sub-list for extension extendee + 0, // [0:35] is the sub-list for field type_name +} + +func init() { file_p2p_proto_init() } +func file_p2p_proto_init() { + if File_p2p_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_p2p_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestAddressesMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddressesMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NetAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubnetworkId); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionInput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Outpoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionId); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScriptPublicKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionOutput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockHeaderMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Hash); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestBlockLocatorMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockLocatorMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestHeadersMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestNextHeadersMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DoneHeadersMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestRelayBlocksMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestTransactionsMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionNotFoundMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvRelayBlockMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InvTransactionsMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PingMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PongMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerackMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VersionMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RejectMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestIBDBlocksMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IBDRootNotFoundMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestIBDRootHashMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IBDRootHashMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorHighestHashMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockHeadersMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_p2p_proto_rawDesc, + NumEnums: 0, + NumMessages: 37, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_p2p_proto_goTypes, + DependencyIndexes: file_p2p_proto_depIdxs, + MessageInfos: file_p2p_proto_msgTypes, + }.Build() + File_p2p_proto = out.File + file_p2p_proto_rawDesc = nil + file_p2p_proto_goTypes = nil + file_p2p_proto_depIdxs = nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto new file mode 100644 index 000000000..cbc34d1da --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto @@ -0,0 +1,237 @@ +syntax = "proto3"; +package protowire; + +option go_package = "github.com/kaspanet/kaspad/protowire"; + +// RequestAddressesMessage start +message RequestAddressesMessage{ + bool includeAllSubnetworks = 1; + SubnetworkId subnetworkId = 2; +} +// RequestAddressesMessage end + +// AddressesMessage start +message AddressesMessage{ + repeated NetAddress addressList = 1; +} + +message NetAddress{ + int64 timestamp = 1; + uint64 services = 2; + bytes ip = 3; + uint32 port = 4; +} + +message SubnetworkId{ + bytes bytes = 1; +} +// AddressesMessage end + +// TransactionMessage start +message TransactionMessage{ + uint32 version = 1; + repeated TransactionInput inputs = 2; + repeated TransactionOutput outputs = 3; + uint64 lockTime = 4; + SubnetworkId subnetworkId = 5; + uint64 gas = 6; + Hash payloadHash = 7; + bytes payload = 8; +} + +message TransactionInput{ + Outpoint previousOutpoint = 1; + bytes signatureScript = 2; + uint64 sequence = 3; +} + +message Outpoint{ + TransactionId transactionId = 1; + uint32 index = 2; +} + +message TransactionId{ + bytes bytes = 1; +} +message ScriptPublicKey { + bytes script = 1; + uint32 version = 2; +} + +message TransactionOutput{ + uint64 value = 1; + ScriptPublicKey scriptPublicKey = 2; +} +// TransactionMessage end + +// BlockMessage start +message BlockMessage{ + BlockHeaderMessage header = 1; + repeated TransactionMessage transactions = 2; +} + +message BlockHeaderMessage{ + uint32 version = 1; + repeated Hash parentHashes = 2; + Hash hashMerkleRoot = 3; + Hash acceptedIdMerkleRoot = 4; + Hash utxoCommitment = 5; + int64 timestamp = 6; + uint32 bits = 7; + uint64 nonce = 8; +} + +message Hash{ + bytes bytes = 1; +} +// BlockMessage end + +// GetBlockLocatorMessage start +message RequestBlockLocatorMessage{ + Hash lowHash = 1; + Hash highHash = 2; + uint32 limit = 3; +} +// GetBlockLocatorMessage end + +// BlockLocatorMessage start +message BlockLocatorMessage{ + repeated Hash hashes = 1; +} +// BlockLocatorMessage end + +// GetBlocksMessage start +message RequestHeadersMessage{ + Hash lowHash = 1; + Hash highHash = 2; +} +// GetBlocksMessage end + +// RequestNextIBDBlocksMessage start +message RequestNextHeadersMessage{ +} +// RequestNextIBDBlocksMessage end + +// DoneIBDBlocksMessage start +message DoneHeadersMessage{ +} +// DoneIBDBlocksMessage end + +// RequestRelayBlocksMessage start +message RequestRelayBlocksMessage{ + repeated Hash hashes = 1; +} +// RequestRelayBlocksMessage end + +// RequestTransactionsMessage start +message RequestTransactionsMessage { + repeated TransactionId ids = 1; +} +// GetTransactionsMessage end + +// TransactionNotFoundMessage start +message TransactionNotFoundMessage{ + TransactionId id = 1; +} +// TransactionsNotFoundMessage end + +// InvRelayBlockMessage start +message InvRelayBlockMessage{ + Hash hash = 1; +} +// InvRelayBlockMessage end + +// InvTransactionMessage start +message InvTransactionsMessage{ + repeated TransactionId ids = 1; +} +// InvTransactionMessage end + +// PingMessage start +message PingMessage{ + uint64 nonce = 1; +} +// PingMessage end + +// PongMessage start +message PongMessage{ + uint64 nonce = 1; +} +// PongMessage end + +// VerackMessage start +message VerackMessage{ +} +// VerackMessage end + +// VersionMessage start +message VersionMessage{ + uint32 protocolVersion = 1; + uint64 services = 2; + int64 timestamp = 3; + NetAddress address = 4; + bytes id = 5; + string userAgent = 6; + bool disableRelayTx = 8; + SubnetworkId subnetworkId = 9; + string network = 10; +} +// VersionMessage end + +// RejectMessage start +message RejectMessage{ + string reason = 1; +} +// RejectMessage end + +// RequestIBDRootUTXOSetAndBlockMessage start +message RequestIBDRootUTXOSetAndBlockMessage{ + Hash ibdRoot = 1; +} +// RequestIBDRootUTXOSetAndBlockMessage end + +// IBDRootUTXOSetAndBlockMessage start +message IBDRootUTXOSetAndBlockMessage{ + bytes utxoSet = 1; + BlockMessage block = 2; +} +// IBDRootUTXOSetAndBlockMessage end + +// RequestIBDBlocksMessage start +message RequestIBDBlocksMessage{ + repeated Hash hashes = 1; +} +// RequestIBDBlocksMessage end + +// IBDRootNotFoundMessage start +message IBDRootNotFoundMessage{ +} +// IBDRootNotFoundMessage end + +// RequestIBDRootHashMessage start +message RequestIBDRootHashMessage{ +} +// RequestIBDRootHashMessage end + +// IBDRootHashMessage start +message IBDRootHashMessage{ + Hash hash = 1; +} +// IBDRootHashMessage end + +// IbdBlockLocatorMessage start +message IbdBlockLocatorMessage { + Hash targetHash = 1; + repeated Hash blockLocatorHashes = 2; +} +// IbdBlockLocatorMessage end + +// IbdBlockLocatorHighestHashMessage start +message IbdBlockLocatorHighestHashMessage { + Hash highestHash = 1; +} +// IbdBlockLocatorHighestHashMessage end + +message BlockHeadersMessage { + repeated BlockHeaderMessage blockHeaders = 1; +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md new file mode 100644 index 000000000..afafc28a7 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -0,0 +1,927 @@ +# Protocol Documentation + + +## Table of Contents + +- [rpc.proto](#rpc.proto) + - [RPCError](#protowire.RPCError) + - [GetCurrentNetworkRequestMessage](#protowire.GetCurrentNetworkRequestMessage) + - [GetCurrentNetworkResponseMessage](#protowire.GetCurrentNetworkResponseMessage) + - [SubmitBlockRequestMessage](#protowire.SubmitBlockRequestMessage) + - [SubmitBlockResponseMessage](#protowire.SubmitBlockResponseMessage) + - [GetBlockTemplateRequestMessage](#protowire.GetBlockTemplateRequestMessage) + - [GetBlockTemplateResponseMessage](#protowire.GetBlockTemplateResponseMessage) + - [NotifyBlockAddedRequestMessage](#protowire.NotifyBlockAddedRequestMessage) + - [NotifyBlockAddedResponseMessage](#protowire.NotifyBlockAddedResponseMessage) + - [BlockAddedNotificationMessage](#protowire.BlockAddedNotificationMessage) + - [GetPeerAddressesRequestMessage](#protowire.GetPeerAddressesRequestMessage) + - [GetPeerAddressesResponseMessage](#protowire.GetPeerAddressesResponseMessage) + - [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) + - [GetSelectedTipHashRequestMessage](#protowire.GetSelectedTipHashRequestMessage) + - [GetSelectedTipHashResponseMessage](#protowire.GetSelectedTipHashResponseMessage) + - [GetMempoolEntryRequestMessage](#protowire.GetMempoolEntryRequestMessage) + - [GetMempoolEntryResponseMessage](#protowire.GetMempoolEntryResponseMessage) + - [GetMempoolEntriesRequestMessage](#protowire.GetMempoolEntriesRequestMessage) + - [GetMempoolEntriesResponseMessage](#protowire.GetMempoolEntriesResponseMessage) + - [MempoolEntry](#protowire.MempoolEntry) + - [GetConnectedPeerInfoRequestMessage](#protowire.GetConnectedPeerInfoRequestMessage) + - [GetConnectedPeerInfoResponseMessage](#protowire.GetConnectedPeerInfoResponseMessage) + - [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage) + - [AddPeerRequestMessage](#protowire.AddPeerRequestMessage) + - [AddPeerResponseMessage](#protowire.AddPeerResponseMessage) + - [SubmitTransactionRequestMessage](#protowire.SubmitTransactionRequestMessage) + - [SubmitTransactionResponseMessage](#protowire.SubmitTransactionResponseMessage) + - [NotifyVirtualSelectedParentChainChangedRequestMessage](#protowire.NotifyVirtualSelectedParentChainChangedRequestMessage) + - [NotifyVirtualSelectedParentChainChangedResponseMessage](#protowire.NotifyVirtualSelectedParentChainChangedResponseMessage) + - [VirtualSelectedParentChainChangedNotificationMessage](#protowire.VirtualSelectedParentChainChangedNotificationMessage) + - [ChainBlock](#protowire.ChainBlock) + - [AcceptedBlock](#protowire.AcceptedBlock) + - [GetBlockRequestMessage](#protowire.GetBlockRequestMessage) + - [GetBlockResponseMessage](#protowire.GetBlockResponseMessage) + - [BlockVerboseData](#protowire.BlockVerboseData) + - [TransactionVerboseData](#protowire.TransactionVerboseData) + - [TransactionVerboseInput](#protowire.TransactionVerboseInput) + - [ScriptSig](#protowire.ScriptSig) + - [TransactionVerboseOutput](#protowire.TransactionVerboseOutput) + - [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult) + - [GetSubnetworkRequestMessage](#protowire.GetSubnetworkRequestMessage) + - [GetSubnetworkResponseMessage](#protowire.GetSubnetworkResponseMessage) + - [GetVirtualSelectedParentChainFromBlockRequestMessage](#protowire.GetVirtualSelectedParentChainFromBlockRequestMessage) + - [GetVirtualSelectedParentChainFromBlockResponseMessage](#protowire.GetVirtualSelectedParentChainFromBlockResponseMessage) + - [GetBlocksRequestMessage](#protowire.GetBlocksRequestMessage) + - [GetBlocksResponseMessage](#protowire.GetBlocksResponseMessage) + - [GetBlockCountRequestMessage](#protowire.GetBlockCountRequestMessage) + - [GetBlockCountResponseMessage](#protowire.GetBlockCountResponseMessage) + - [GetBlockDagInfoRequestMessage](#protowire.GetBlockDagInfoRequestMessage) + - [GetBlockDagInfoResponseMessage](#protowire.GetBlockDagInfoResponseMessage) + - [ResolveFinalityConflictRequestMessage](#protowire.ResolveFinalityConflictRequestMessage) + - [ResolveFinalityConflictResponseMessage](#protowire.ResolveFinalityConflictResponseMessage) + - [NotifyFinalityConflictsRequestMessage](#protowire.NotifyFinalityConflictsRequestMessage) + - [NotifyFinalityConflictsResponseMessage](#protowire.NotifyFinalityConflictsResponseMessage) + - [FinalityConflictNotificationMessage](#protowire.FinalityConflictNotificationMessage) + - [FinalityConflictResolvedNotificationMessage](#protowire.FinalityConflictResolvedNotificationMessage) + - [ShutDownRequestMessage](#protowire.ShutDownRequestMessage) + - [ShutDownResponseMessage](#protowire.ShutDownResponseMessage) + - [GetHeadersRequestMessage](#protowire.GetHeadersRequestMessage) + - [GetHeadersResponseMessage](#protowire.GetHeadersResponseMessage) + - [NotifyUtxosChangedRequestMessage](#protowire.NotifyUtxosChangedRequestMessage) + - [NotifyUtxosChangedResponseMessage](#protowire.NotifyUtxosChangedResponseMessage) + - [UtxosChangedNotificationMessage](#protowire.UtxosChangedNotificationMessage) + - [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) + - [RpcTransaction](#protowire.RpcTransaction) + - [RpcTransactionInput](#protowire.RpcTransactionInput) + - [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) + - [RpcTransactionOutput](#protowire.RpcTransactionOutput) + - [RpcOutpoint](#protowire.RpcOutpoint) + - [RpcUtxoEntry](#protowire.RpcUtxoEntry) + - [GetUtxosByAddressesRequestMessage](#protowire.GetUtxosByAddressesRequestMessage) + - [GetUtxosByAddressesResponseMessage](#protowire.GetUtxosByAddressesResponseMessage) + - [GetVirtualSelectedParentBlueScoreRequestMessage](#protowire.GetVirtualSelectedParentBlueScoreRequestMessage) + - [GetVirtualSelectedParentBlueScoreResponseMessage](#protowire.GetVirtualSelectedParentBlueScoreResponseMessage) + - [NotifyVirtualSelectedParentBlueScoreChangedRequestMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) + - [NotifyVirtualSelectedParentBlueScoreChangedResponseMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) + - [VirtualSelectedParentBlueScoreChangedNotificationMessage](#protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage) + +- [Scalar Value Types](#scalar-value-types) + + + + +

Top

+ +## rpc.proto +RPC-related types. Request messages, response messages, and dependant types. + +Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto) + +Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a ResponseMessage ( +likewise wrapped in a KaspadMessage) respective to the original RequestMessage. + +**IMPORTANT:** This API is a work in progress and is subject to break between versions. + + + + +### RPCError + +RPCError represents a generic non-internal error. + +Receivers of any ResponseMessage are expected to check whether its error field is not null. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| message | [string](#string) | | | + + + +### GetCurrentNetworkRequestMessage + +GetCurrentNetworkRequestMessage requests the network kaspad is currently running against. + +Possible networks are: Mainnet, Testnet, Simnet, Devnet + + + +### GetCurrentNetworkResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| currentNetwork | [string](#string) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### SubmitBlockRequestMessage + +SubmitBlockRequestMessage requests to submit a block into the DAG. Blocks are generally expected to have been generated +using the getBlockTemplate call. + +See: GetBlockTemplateRequestMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| block | [BlockMessage](#protowire.BlockMessage) | | | + + + +### SubmitBlockResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetBlockTemplateRequestMessage + +GetBlockTemplateRequestMessage requests a current block template. Callers are expected to solve the block template and +submit it using the submitBlock call + +See: SubmitBlockRequestMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| payAddress | [string](#string) | | Which kaspa address should the coinbase block reward transaction pay into | + + + +### GetBlockTemplateResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| blockMessage | [BlockMessage](#protowire.BlockMessage) | | | +| isSynced | [bool](#bool) | | Whether kaspad thinks that it's synced. Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. That is because when kaspad isn't in sync with the rest of the network there's a high chance the block will never be accepted, thus the solving effort would have been wasted. | +| error | [RPCError](#protowire.RPCError) | | | + + + +### NotifyBlockAddedRequestMessage + +NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications. + +See: BlockAddedNotificationMessage + + + +### NotifyBlockAddedResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### BlockAddedNotificationMessage + +BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted) +into the DAG. + +See: NotifyBlockAddedRequestMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| block | [BlockMessage](#protowire.BlockMessage) | | | + + + +### GetPeerAddressesRequestMessage + +GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the current network. (mainnet, testnet, +etc.) + + + +### GetPeerAddressesResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| addresses | [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) | repeated | | +| bannedAddresses | [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetPeerAddressesKnownAddressMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| Addr | [string](#string) | | | + + + +### GetSelectedTipHashRequestMessage + +GetSelectedTipHashRequestMessage requests the hash of the current virtual's selected parent. + + + +### GetSelectedTipHashResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| selectedTipHash | [string](#string) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetMempoolEntryRequestMessage + +GetMempoolEntryRequestMessage requests information about a specific transaction in the mempool. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| txId | [string](#string) | | The transaction's TransactionID. | + + + +### GetMempoolEntryResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| entry | [MempoolEntry](#protowire.MempoolEntry) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetMempoolEntriesRequestMessage + +GetMempoolEntriesRequestMessage requests information about all the transactions currently in the mempool. + + + +### GetMempoolEntriesResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| entries | [MempoolEntry](#protowire.MempoolEntry) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### MempoolEntry + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| fee | [uint64](#uint64) | | | +| transactionVerboseData | [TransactionVerboseData](#protowire.TransactionVerboseData) | | | + + + +### GetConnectedPeerInfoRequestMessage + +GetConnectedPeerInfoRequestMessage requests information about all the p2p peers currently connected to this kaspad. + + + +### GetConnectedPeerInfoResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| infos | [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetConnectedPeerInfoMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| id | [string](#string) | | | +| address | [string](#string) | | | +| lastPingDuration | [int64](#int64) | | How long did the last ping/pong exchange take | +| isOutbound | [bool](#bool) | | Whether this kaspad initiated the connection | +| timeOffset | [int64](#int64) | | | +| userAgent | [string](#string) | | | +| advertisedProtocolVersion | [uint32](#uint32) | | The protocol version that this peer claims to support | +| timeConnected | [int64](#int64) | | The timestamp of when this peer connected to this kaspad | +| isIbdPeer | [bool](#bool) | | Whether this peer is the IBD peer (if IBD is running) | + + + +### AddPeerRequestMessage + +AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. This will, in most cases, result in kaspad +connecting to said peer. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| address | [string](#string) | | | +| isPermanent | [bool](#bool) | | Whether to keep attempting to connect to this peer after disconnection | + + + +### AddPeerResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### SubmitTransactionRequestMessage + +SubmitTransactionRequestMessage submits a transaction to the mempool + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| transaction | [RpcTransaction](#protowire.RpcTransaction) | | | + + + +### SubmitTransactionResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| transactionId | [string](#string) | | The transaction ID of the submitted transaction | +| error | [RPCError](#protowire.RPCError) | | | + + + +### NotifyVirtualSelectedParentChainChangedRequestMessage + +NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged +notifications. + +See: VirtualSelectedParentChainChangedNotificationMessage + + + +### NotifyVirtualSelectedParentChainChangedResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### VirtualSelectedParentChainChangedNotificationMessage + +VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent chain had changed. + +See: NotifyVirtualSelectedParentChainChangedRequestMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| removedChainBlockHashes | [string](#string) | repeated | The chain blocks that were removed, in high-to-low order | +| addedChainBlocks | [ChainBlock](#protowire.ChainBlock) | repeated | The chain blocks that were added, in low-to-high order | + + + +### ChainBlock + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| hash | [string](#string) | | | +| acceptedBlocks | [AcceptedBlock](#protowire.AcceptedBlock) | repeated | | + + + +### AcceptedBlock + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| hash | [string](#string) | | | +| acceptedTransactionIds | [string](#string) | repeated | | + + + +### GetBlockRequestMessage + +GetBlockRequestMessage requests information about a specific block + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| hash | [string](#string) | | The hash of the requested block | +| subnetworkId | [string](#string) | | | +| includeTransactionVerboseData | [bool](#bool) | | Whether to include transaction data in the response | + + + +### GetBlockResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| blockHash | [string](#string) | | | +| blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### BlockVerboseData + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| hash | [string](#string) | | | +| version | [uint32](#uint32) | | | +| versionHex | [string](#string) | | | +| hashMerkleRoot | [string](#string) | | | +| acceptedIDMerkleRoot | [string](#string) | | | +| utxoCommitment | [string](#string) | | | +| transactionVerboseData | [TransactionVerboseData](#protowire.TransactionVerboseData) | repeated | | +| time | [int64](#int64) | | | +| nonce | [uint64](#uint64) | | | +| bits | [string](#string) | | | +| difficulty | [double](#double) | | | +| parentHashes | [string](#string) | repeated | | +| selectedParentHash | [string](#string) | | | +| transactionIDs | [string](#string) | repeated | | +| isHeaderOnly | [bool](#bool) | | | +| blueScore | [uint64](#uint64) | | | + + + +### TransactionVerboseData + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| txId | [string](#string) | | | +| hash | [string](#string) | | | +| size | [uint64](#uint64) | | | +| version | [uint32](#uint32) | | | +| lockTime | [uint64](#uint64) | | | +| subnetworkId | [string](#string) | | | +| gas | [uint64](#uint64) | | | +| payloadHash | [string](#string) | | | +| payload | [string](#string) | | | +| transactionVerboseInputs | [TransactionVerboseInput](#protowire.TransactionVerboseInput) | repeated | | +| transactionVerboseOutputs | [TransactionVerboseOutput](#protowire.TransactionVerboseOutput) | repeated | | +| blockHash | [string](#string) | | | +| time | [uint64](#uint64) | | | +| blockTime | [uint64](#uint64) | | | + + + +### TransactionVerboseInput + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| txId | [string](#string) | | | +| outputIndex | [uint32](#uint32) | | | +| scriptSig | [ScriptSig](#protowire.ScriptSig) | | | +| sequence | [uint64](#uint64) | | | + + + +### ScriptSig + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| asm | [string](#string) | | | +| hex | [string](#string) | | | + + + +### TransactionVerboseOutput + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| value | [uint64](#uint64) | | | +| index | [uint32](#uint32) | | | +| scriptPublicKey | [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult) | | | + + + +### ScriptPublicKeyResult + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| asm | [string](#string) | | | +| hex | [string](#string) | | | +| type | [string](#string) | | | +| address | [string](#string) | | | + + + +### GetSubnetworkRequestMessage + +GetSubnetworkRequestMessage requests information about a specific subnetwork + +Currently unimplemented + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| subnetworkId | [string](#string) | | | + + + +### GetSubnetworkResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| gasLimit | [uint64](#uint64) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetVirtualSelectedParentChainFromBlockRequestMessage + +GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected parent chain from some startHash to +this kaspad's current virtual + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| startHash | [string](#string) | | | + + + + + + + + +### GetVirtualSelectedParentChainFromBlockResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| removedChainBlockHashes | [string](#string) | repeated | The chain blocks that were removed, in high-to-low order | +| addedChainBlocks | [ChainBlock](#protowire.ChainBlock) | repeated | The chain blocks that were added, in low-to-high order | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetBlocksRequestMessage + +GetBlocksRequestMessage requests blocks between a certain block lowHash up to this kaspad's current virtual. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| lowHash | [string](#string) | | | +| includeBlockHexes | [bool](#bool) | | | +| includeBlockVerboseData | [bool](#bool) | | | +| includeTransactionVerboseData | [bool](#bool) | | | + + + +### GetBlocksResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| blockHashes | [string](#string) | repeated | | +| blockHexes | [string](#string) | repeated | | +| blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetBlockCountRequestMessage + +GetBlockCountRequestMessage requests the current number of blocks in this kaspad. Note that this number may decrease as +pruning occurs. + + + +### GetBlockCountResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| blockCount | [uint64](#uint64) | | | +| headerCount | [uint64](#uint64) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetBlockDagInfoRequestMessage + +GetBlockDagInfoRequestMessage requests general information about the current state of this kaspad's DAG. + + + +### GetBlockDagInfoResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| networkName | [string](#string) | | | +| blockCount | [uint64](#uint64) | | | +| headerCount | [uint64](#uint64) | | | +| tipHashes | [string](#string) | repeated | | +| difficulty | [double](#double) | | | +| pastMedianTime | [int64](#int64) | | | +| virtualParentHashes | [string](#string) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### ResolveFinalityConflictRequestMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| finalityBlockHash | [string](#string) | | | + + + +### ResolveFinalityConflictResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### NotifyFinalityConflictsRequestMessage + + + +### NotifyFinalityConflictsResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### FinalityConflictNotificationMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| violatingBlockHash | [string](#string) | | | + + + +### FinalityConflictResolvedNotificationMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| finalityBlockHash | [string](#string) | | | + + + +### ShutDownRequestMessage + +ShutDownRequestMessage shuts down this kaspad. + + + +### ShutDownResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetHeadersRequestMessage + +GetHeadersRequestMessage requests headers between the given startHash and the current virtual, up to the given limit. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| startHash | [string](#string) | | | +| limit | [uint64](#uint64) | | | +| isAscending | [bool](#bool) | | | + + + +### GetHeadersResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| headers | [string](#string) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### NotifyUtxosChangedRequestMessage + +NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications for the given addresses. + +This call is only available when this kaspad was started with `--utxoindex` + +See: UtxosChangedNotificationMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| addresses | [string](#string) | repeated | | + + + +### NotifyUtxosChangedResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + +### UtxosChangedNotificationMessage + +UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated. + +See: NotifyUtxosChangedRequestMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| added | [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) | repeated | | +| removed | [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) | repeated | | + + + +### UtxosByAddressesEntry + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| address | [string](#string) | | | +| outpoint | [RpcOutpoint](#protowire.RpcOutpoint) | | | +| utxoEntry | [RpcUtxoEntry](#protowire.RpcUtxoEntry) | | | + + + + + + + + +### RpcTransaction + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| version | [uint32](#uint32) | | | +| inputs | [RpcTransactionInput](#protowire.RpcTransactionInput) | repeated | | +| outputs | [RpcTransactionOutput](#protowire.RpcTransactionOutput) | repeated | | +| lockTime | [uint64](#uint64) | | | +| subnetworkId | [string](#string) | | | +| gas | [uint64](#uint64) | | | +| payloadHash | [string](#string) | | | +| payload | [string](#string) | | | + + + + + + + + +### RpcTransactionInput + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| previousOutpoint | [RpcOutpoint](#protowire.RpcOutpoint) | | | +| signatureScript | [string](#string) | | | +| sequence | [uint64](#uint64) | | | + + + +### RpcScriptPublicKey + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| version | [uint32](#uint32) | | | +| scriptPublicKey | [string](#string) | | | + + + +### RpcTransactionOutput + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| amount | [uint64](#uint64) | | | +| scriptPublicKey | [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) | | | + + + +### RpcOutpoint + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| transactionId | [string](#string) | | | +| index | [uint32](#uint32) | | | + + + +### RpcUtxoEntry + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| amount | [uint64](#uint64) | | | +| scriptPublicKey | [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) | | | +| blockBlueScore | [uint64](#uint64) | | | +| isCoinbase | [bool](#bool) | | | + + + +### GetUtxosByAddressesRequestMessage + +GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses + +This call is only available when this kaspad was started with `--utxoindex` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| addresses | [string](#string) | repeated | | + + + +### GetUtxosByAddressesResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| entries | [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) | repeated | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### GetVirtualSelectedParentBlueScoreRequestMessage + +GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent of the virtual +block. + + + +### GetVirtualSelectedParentBlueScoreResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| blueScore | [uint64](#uint64) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + +### NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + +NotifyVirtualSelectedParentBlueScoreChangedRequestMessage registers this connection for +virtualSelectedParentBlueScoreChanged notifications. + +See: VirtualSelectedParentBlueScoreChangedNotificationMessage + + + +### NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + + + + + + +### VirtualSelectedParentBlueScoreChangedNotificationMessage + +VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score of the virtual's selected +parent changes. + +See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| virtualSelectedParentBlueScore | [uint64](#uint64) | | | + + + + + + + + + + + + + + + +## Scalar Value Types + +| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby | +| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- | +| double | | double | double | float | float64 | double | float | Float | +| float | | float | float | float | float32 | float | float | Float | +| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) | +| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum | +| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) | +| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) | +| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) | +| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum | +| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) | +| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum | +| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) | +| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum | +| bool | | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | +| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) | +| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) | + diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go new file mode 100644 index 000000000..097751b97 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -0,0 +1,6184 @@ +// RPC-related types. Request messages, response messages, and dependant types. +// +// Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto) +// +// Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a +// ResponseMessage (likewise wrapped in a KaspadMessage) respective to the original RequestMessage. +// +// **IMPORTANT:** This API is a work in progress and is subject to break between versions. +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.12.3 +// source: rpc.proto + +package protowire + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// RPCError represents a generic non-internal error. +// +// Receivers of any ResponseMessage are expected to check whether its error field is not null. +type RPCError struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *RPCError) Reset() { + *x = RPCError{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RPCError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RPCError) ProtoMessage() {} + +func (x *RPCError) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RPCError.ProtoReflect.Descriptor instead. +func (*RPCError) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{0} +} + +func (x *RPCError) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// GetCurrentNetworkRequestMessage requests the network kaspad is currently running against. +// +// Possible networks are: Mainnet, Testnet, Simnet, Devnet +type GetCurrentNetworkRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetCurrentNetworkRequestMessage) Reset() { + *x = GetCurrentNetworkRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetCurrentNetworkRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCurrentNetworkRequestMessage) ProtoMessage() {} + +func (x *GetCurrentNetworkRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCurrentNetworkRequestMessage.ProtoReflect.Descriptor instead. +func (*GetCurrentNetworkRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{1} +} + +type GetCurrentNetworkResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CurrentNetwork string `protobuf:"bytes,1,opt,name=currentNetwork,proto3" json:"currentNetwork,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetCurrentNetworkResponseMessage) Reset() { + *x = GetCurrentNetworkResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetCurrentNetworkResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCurrentNetworkResponseMessage) ProtoMessage() {} + +func (x *GetCurrentNetworkResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCurrentNetworkResponseMessage.ProtoReflect.Descriptor instead. +func (*GetCurrentNetworkResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{2} +} + +func (x *GetCurrentNetworkResponseMessage) GetCurrentNetwork() string { + if x != nil { + return x.CurrentNetwork + } + return "" +} + +func (x *GetCurrentNetworkResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// SubmitBlockRequestMessage requests to submit a block into the DAG. +// Blocks are generally expected to have been generated using the getBlockTemplate call. +// +// See: GetBlockTemplateRequestMessage +type SubmitBlockRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Block *BlockMessage `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` +} + +func (x *SubmitBlockRequestMessage) Reset() { + *x = SubmitBlockRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitBlockRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitBlockRequestMessage) ProtoMessage() {} + +func (x *SubmitBlockRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitBlockRequestMessage.ProtoReflect.Descriptor instead. +func (*SubmitBlockRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{3} +} + +func (x *SubmitBlockRequestMessage) GetBlock() *BlockMessage { + if x != nil { + return x.Block + } + return nil +} + +type SubmitBlockResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *SubmitBlockResponseMessage) Reset() { + *x = SubmitBlockResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitBlockResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitBlockResponseMessage) ProtoMessage() {} + +func (x *SubmitBlockResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitBlockResponseMessage.ProtoReflect.Descriptor instead. +func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{4} +} + +func (x *SubmitBlockResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetBlockTemplateRequestMessage requests a current block template. +// Callers are expected to solve the block template and submit it using the submitBlock call +// +// See: SubmitBlockRequestMessage +type GetBlockTemplateRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Which kaspa address should the coinbase block reward transaction pay into + PayAddress string `protobuf:"bytes,1,opt,name=payAddress,proto3" json:"payAddress,omitempty"` +} + +func (x *GetBlockTemplateRequestMessage) Reset() { + *x = GetBlockTemplateRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockTemplateRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockTemplateRequestMessage) ProtoMessage() {} + +func (x *GetBlockTemplateRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockTemplateRequestMessage.ProtoReflect.Descriptor instead. +func (*GetBlockTemplateRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{5} +} + +func (x *GetBlockTemplateRequestMessage) GetPayAddress() string { + if x != nil { + return x.PayAddress + } + return "" +} + +type GetBlockTemplateResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockMessage *BlockMessage `protobuf:"bytes,1,opt,name=blockMessage,proto3" json:"blockMessage,omitempty"` + // Whether kaspad thinks that it's synced. + // Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. + // That is because when kaspad isn't in sync with the rest of the network there's a high + // chance the block will never be accepted, thus the solving effort would have been wasted. + IsSynced bool `protobuf:"varint,2,opt,name=isSynced,proto3" json:"isSynced,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetBlockTemplateResponseMessage) Reset() { + *x = GetBlockTemplateResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockTemplateResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockTemplateResponseMessage) ProtoMessage() {} + +func (x *GetBlockTemplateResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockTemplateResponseMessage.ProtoReflect.Descriptor instead. +func (*GetBlockTemplateResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{6} +} + +func (x *GetBlockTemplateResponseMessage) GetBlockMessage() *BlockMessage { + if x != nil { + return x.BlockMessage + } + return nil +} + +func (x *GetBlockTemplateResponseMessage) GetIsSynced() bool { + if x != nil { + return x.IsSynced + } + return false +} + +func (x *GetBlockTemplateResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications. +// +// See: BlockAddedNotificationMessage +type NotifyBlockAddedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NotifyBlockAddedRequestMessage) Reset() { + *x = NotifyBlockAddedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyBlockAddedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyBlockAddedRequestMessage) ProtoMessage() {} + +func (x *NotifyBlockAddedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyBlockAddedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyBlockAddedRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{7} +} + +type NotifyBlockAddedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyBlockAddedResponseMessage) Reset() { + *x = NotifyBlockAddedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyBlockAddedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyBlockAddedResponseMessage) ProtoMessage() {} + +func (x *NotifyBlockAddedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyBlockAddedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyBlockAddedResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{8} +} + +func (x *NotifyBlockAddedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted) +// into the DAG. +// +// See: NotifyBlockAddedRequestMessage +type BlockAddedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Block *BlockMessage `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` +} + +func (x *BlockAddedNotificationMessage) Reset() { + *x = BlockAddedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockAddedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockAddedNotificationMessage) ProtoMessage() {} + +func (x *BlockAddedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockAddedNotificationMessage.ProtoReflect.Descriptor instead. +func (*BlockAddedNotificationMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{9} +} + +func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { + if x != nil { + return x.Block + } + return nil +} + +// GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the +// current network. (mainnet, testnet, etc.) +type GetPeerAddressesRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetPeerAddressesRequestMessage) Reset() { + *x = GetPeerAddressesRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPeerAddressesRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPeerAddressesRequestMessage) ProtoMessage() {} + +func (x *GetPeerAddressesRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPeerAddressesRequestMessage.ProtoReflect.Descriptor instead. +func (*GetPeerAddressesRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{10} +} + +type GetPeerAddressesResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` + BannedAddresses []*GetPeerAddressesKnownAddressMessage `protobuf:"bytes,2,rep,name=bannedAddresses,proto3" json:"bannedAddresses,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetPeerAddressesResponseMessage) Reset() { + *x = GetPeerAddressesResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPeerAddressesResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPeerAddressesResponseMessage) ProtoMessage() {} + +func (x *GetPeerAddressesResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPeerAddressesResponseMessage.ProtoReflect.Descriptor instead. +func (*GetPeerAddressesResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{11} +} + +func (x *GetPeerAddressesResponseMessage) GetAddresses() []*GetPeerAddressesKnownAddressMessage { + if x != nil { + return x.Addresses + } + return nil +} + +func (x *GetPeerAddressesResponseMessage) GetBannedAddresses() []*GetPeerAddressesKnownAddressMessage { + if x != nil { + return x.BannedAddresses + } + return nil +} + +func (x *GetPeerAddressesResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type GetPeerAddressesKnownAddressMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addr string `protobuf:"bytes,1,opt,name=Addr,proto3" json:"Addr,omitempty"` +} + +func (x *GetPeerAddressesKnownAddressMessage) Reset() { + *x = GetPeerAddressesKnownAddressMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPeerAddressesKnownAddressMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPeerAddressesKnownAddressMessage) ProtoMessage() {} + +func (x *GetPeerAddressesKnownAddressMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPeerAddressesKnownAddressMessage.ProtoReflect.Descriptor instead. +func (*GetPeerAddressesKnownAddressMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{12} +} + +func (x *GetPeerAddressesKnownAddressMessage) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +// GetSelectedTipHashRequestMessage requests the hash of the current virtual's +// selected parent. +type GetSelectedTipHashRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetSelectedTipHashRequestMessage) Reset() { + *x = GetSelectedTipHashRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSelectedTipHashRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSelectedTipHashRequestMessage) ProtoMessage() {} + +func (x *GetSelectedTipHashRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSelectedTipHashRequestMessage.ProtoReflect.Descriptor instead. +func (*GetSelectedTipHashRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{13} +} + +type GetSelectedTipHashResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SelectedTipHash string `protobuf:"bytes,1,opt,name=selectedTipHash,proto3" json:"selectedTipHash,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetSelectedTipHashResponseMessage) Reset() { + *x = GetSelectedTipHashResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSelectedTipHashResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSelectedTipHashResponseMessage) ProtoMessage() {} + +func (x *GetSelectedTipHashResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSelectedTipHashResponseMessage.ProtoReflect.Descriptor instead. +func (*GetSelectedTipHashResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{14} +} + +func (x *GetSelectedTipHashResponseMessage) GetSelectedTipHash() string { + if x != nil { + return x.SelectedTipHash + } + return "" +} + +func (x *GetSelectedTipHashResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetMempoolEntryRequestMessage requests information about a specific transaction +// in the mempool. +type GetMempoolEntryRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The transaction's TransactionID. + TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` +} + +func (x *GetMempoolEntryRequestMessage) Reset() { + *x = GetMempoolEntryRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMempoolEntryRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMempoolEntryRequestMessage) ProtoMessage() {} + +func (x *GetMempoolEntryRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMempoolEntryRequestMessage.ProtoReflect.Descriptor instead. +func (*GetMempoolEntryRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{15} +} + +func (x *GetMempoolEntryRequestMessage) GetTxId() string { + if x != nil { + return x.TxId + } + return "" +} + +type GetMempoolEntryResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entry *MempoolEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetMempoolEntryResponseMessage) Reset() { + *x = GetMempoolEntryResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMempoolEntryResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMempoolEntryResponseMessage) ProtoMessage() {} + +func (x *GetMempoolEntryResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMempoolEntryResponseMessage.ProtoReflect.Descriptor instead. +func (*GetMempoolEntryResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{16} +} + +func (x *GetMempoolEntryResponseMessage) GetEntry() *MempoolEntry { + if x != nil { + return x.Entry + } + return nil +} + +func (x *GetMempoolEntryResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetMempoolEntriesRequestMessage requests information about all the transactions +// currently in the mempool. +type GetMempoolEntriesRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetMempoolEntriesRequestMessage) Reset() { + *x = GetMempoolEntriesRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMempoolEntriesRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMempoolEntriesRequestMessage) ProtoMessage() {} + +func (x *GetMempoolEntriesRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMempoolEntriesRequestMessage.ProtoReflect.Descriptor instead. +func (*GetMempoolEntriesRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{17} +} + +type GetMempoolEntriesResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entries []*MempoolEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetMempoolEntriesResponseMessage) Reset() { + *x = GetMempoolEntriesResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMempoolEntriesResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMempoolEntriesResponseMessage) ProtoMessage() {} + +func (x *GetMempoolEntriesResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMempoolEntriesResponseMessage.ProtoReflect.Descriptor instead. +func (*GetMempoolEntriesResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{18} +} + +func (x *GetMempoolEntriesResponseMessage) GetEntries() []*MempoolEntry { + if x != nil { + return x.Entries + } + return nil +} + +func (x *GetMempoolEntriesResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type MempoolEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Fee uint64 `protobuf:"varint,1,opt,name=fee,proto3" json:"fee,omitempty"` + TransactionVerboseData *TransactionVerboseData `protobuf:"bytes,2,opt,name=transactionVerboseData,proto3" json:"transactionVerboseData,omitempty"` +} + +func (x *MempoolEntry) Reset() { + *x = MempoolEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MempoolEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MempoolEntry) ProtoMessage() {} + +func (x *MempoolEntry) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MempoolEntry.ProtoReflect.Descriptor instead. +func (*MempoolEntry) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{19} +} + +func (x *MempoolEntry) GetFee() uint64 { + if x != nil { + return x.Fee + } + return 0 +} + +func (x *MempoolEntry) GetTransactionVerboseData() *TransactionVerboseData { + if x != nil { + return x.TransactionVerboseData + } + return nil +} + +// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers +// currently connected to this kaspad. +type GetConnectedPeerInfoRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetConnectedPeerInfoRequestMessage) Reset() { + *x = GetConnectedPeerInfoRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetConnectedPeerInfoRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConnectedPeerInfoRequestMessage) ProtoMessage() {} + +func (x *GetConnectedPeerInfoRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConnectedPeerInfoRequestMessage.ProtoReflect.Descriptor instead. +func (*GetConnectedPeerInfoRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{20} +} + +type GetConnectedPeerInfoResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Infos []*GetConnectedPeerInfoMessage `protobuf:"bytes,1,rep,name=infos,proto3" json:"infos,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetConnectedPeerInfoResponseMessage) Reset() { + *x = GetConnectedPeerInfoResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetConnectedPeerInfoResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConnectedPeerInfoResponseMessage) ProtoMessage() {} + +func (x *GetConnectedPeerInfoResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConnectedPeerInfoResponseMessage.ProtoReflect.Descriptor instead. +func (*GetConnectedPeerInfoResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{21} +} + +func (x *GetConnectedPeerInfoResponseMessage) GetInfos() []*GetConnectedPeerInfoMessage { + if x != nil { + return x.Infos + } + return nil +} + +func (x *GetConnectedPeerInfoResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type GetConnectedPeerInfoMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + // How long did the last ping/pong exchange take + LastPingDuration int64 `protobuf:"varint,3,opt,name=lastPingDuration,proto3" json:"lastPingDuration,omitempty"` + // Whether this kaspad initiated the connection + IsOutbound bool `protobuf:"varint,6,opt,name=isOutbound,proto3" json:"isOutbound,omitempty"` + TimeOffset int64 `protobuf:"varint,7,opt,name=timeOffset,proto3" json:"timeOffset,omitempty"` + UserAgent string `protobuf:"bytes,8,opt,name=userAgent,proto3" json:"userAgent,omitempty"` + // The protocol version that this peer claims to support + AdvertisedProtocolVersion uint32 `protobuf:"varint,9,opt,name=advertisedProtocolVersion,proto3" json:"advertisedProtocolVersion,omitempty"` + // The timestamp of when this peer connected to this kaspad + TimeConnected int64 `protobuf:"varint,10,opt,name=timeConnected,proto3" json:"timeConnected,omitempty"` + // Whether this peer is the IBD peer (if IBD is running) + IsIbdPeer bool `protobuf:"varint,11,opt,name=isIbdPeer,proto3" json:"isIbdPeer,omitempty"` +} + +func (x *GetConnectedPeerInfoMessage) Reset() { + *x = GetConnectedPeerInfoMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetConnectedPeerInfoMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConnectedPeerInfoMessage) ProtoMessage() {} + +func (x *GetConnectedPeerInfoMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConnectedPeerInfoMessage.ProtoReflect.Descriptor instead. +func (*GetConnectedPeerInfoMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{22} +} + +func (x *GetConnectedPeerInfoMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *GetConnectedPeerInfoMessage) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *GetConnectedPeerInfoMessage) GetLastPingDuration() int64 { + if x != nil { + return x.LastPingDuration + } + return 0 +} + +func (x *GetConnectedPeerInfoMessage) GetIsOutbound() bool { + if x != nil { + return x.IsOutbound + } + return false +} + +func (x *GetConnectedPeerInfoMessage) GetTimeOffset() int64 { + if x != nil { + return x.TimeOffset + } + return 0 +} + +func (x *GetConnectedPeerInfoMessage) GetUserAgent() string { + if x != nil { + return x.UserAgent + } + return "" +} + +func (x *GetConnectedPeerInfoMessage) GetAdvertisedProtocolVersion() uint32 { + if x != nil { + return x.AdvertisedProtocolVersion + } + return 0 +} + +func (x *GetConnectedPeerInfoMessage) GetTimeConnected() int64 { + if x != nil { + return x.TimeConnected + } + return 0 +} + +func (x *GetConnectedPeerInfoMessage) GetIsIbdPeer() bool { + if x != nil { + return x.IsIbdPeer + } + return false +} + +// AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. +// This will, in most cases, result in kaspad connecting to said peer. +type AddPeerRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // Whether to keep attempting to connect to this peer after disconnection + IsPermanent bool `protobuf:"varint,2,opt,name=isPermanent,proto3" json:"isPermanent,omitempty"` +} + +func (x *AddPeerRequestMessage) Reset() { + *x = AddPeerRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddPeerRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddPeerRequestMessage) ProtoMessage() {} + +func (x *AddPeerRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddPeerRequestMessage.ProtoReflect.Descriptor instead. +func (*AddPeerRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{23} +} + +func (x *AddPeerRequestMessage) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *AddPeerRequestMessage) GetIsPermanent() bool { + if x != nil { + return x.IsPermanent + } + return false +} + +type AddPeerResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *AddPeerResponseMessage) Reset() { + *x = AddPeerResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddPeerResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddPeerResponseMessage) ProtoMessage() {} + +func (x *AddPeerResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddPeerResponseMessage.ProtoReflect.Descriptor instead. +func (*AddPeerResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{24} +} + +func (x *AddPeerResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// SubmitTransactionRequestMessage submits a transaction to the mempool +type SubmitTransactionRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Transaction *RpcTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` +} + +func (x *SubmitTransactionRequestMessage) Reset() { + *x = SubmitTransactionRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitTransactionRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitTransactionRequestMessage) ProtoMessage() {} + +func (x *SubmitTransactionRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitTransactionRequestMessage.ProtoReflect.Descriptor instead. +func (*SubmitTransactionRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{25} +} + +func (x *SubmitTransactionRequestMessage) GetTransaction() *RpcTransaction { + if x != nil { + return x.Transaction + } + return nil +} + +type SubmitTransactionResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The transaction ID of the submitted transaction + TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *SubmitTransactionResponseMessage) Reset() { + *x = SubmitTransactionResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitTransactionResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitTransactionResponseMessage) ProtoMessage() {} + +func (x *SubmitTransactionResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitTransactionResponseMessage.ProtoReflect.Descriptor instead. +func (*SubmitTransactionResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{26} +} + +func (x *SubmitTransactionResponseMessage) GetTransactionId() string { + if x != nil { + return x.TransactionId + } + return "" +} + +func (x *SubmitTransactionResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged notifications. +// +// See: VirtualSelectedParentChainChangedNotificationMessage +type NotifyVirtualSelectedParentChainChangedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) Reset() { + *x = NotifyVirtualSelectedParentChainChangedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoMessage() {} + +func (x *NotifyVirtualSelectedParentChainChangedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyVirtualSelectedParentChainChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentChainChangedRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{27} +} + +type NotifyVirtualSelectedParentChainChangedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) Reset() { + *x = NotifyVirtualSelectedParentChainChangedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoMessage() {} + +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyVirtualSelectedParentChainChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentChainChangedResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{28} +} + +func (x *NotifyVirtualSelectedParentChainChangedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent +// chain had changed. +// +// See: NotifyVirtualSelectedParentChainChangedRequestMessage +type VirtualSelectedParentChainChangedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The chain blocks that were removed, in high-to-low order + RemovedChainBlockHashes []string `protobuf:"bytes,1,rep,name=removedChainBlockHashes,proto3" json:"removedChainBlockHashes,omitempty"` + // The chain blocks that were added, in low-to-high order + AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` +} + +func (x *VirtualSelectedParentChainChangedNotificationMessage) Reset() { + *x = VirtualSelectedParentChainChangedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VirtualSelectedParentChainChangedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VirtualSelectedParentChainChangedNotificationMessage) ProtoMessage() {} + +func (x *VirtualSelectedParentChainChangedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VirtualSelectedParentChainChangedNotificationMessage.ProtoReflect.Descriptor instead. +func (*VirtualSelectedParentChainChangedNotificationMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{29} +} + +func (x *VirtualSelectedParentChainChangedNotificationMessage) GetRemovedChainBlockHashes() []string { + if x != nil { + return x.RemovedChainBlockHashes + } + return nil +} + +func (x *VirtualSelectedParentChainChangedNotificationMessage) GetAddedChainBlocks() []*ChainBlock { + if x != nil { + return x.AddedChainBlocks + } + return nil +} + +type ChainBlock struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + AcceptedBlocks []*AcceptedBlock `protobuf:"bytes,2,rep,name=acceptedBlocks,proto3" json:"acceptedBlocks,omitempty"` +} + +func (x *ChainBlock) Reset() { + *x = ChainBlock{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChainBlock) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChainBlock) ProtoMessage() {} + +func (x *ChainBlock) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChainBlock.ProtoReflect.Descriptor instead. +func (*ChainBlock) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{30} +} + +func (x *ChainBlock) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *ChainBlock) GetAcceptedBlocks() []*AcceptedBlock { + if x != nil { + return x.AcceptedBlocks + } + return nil +} + +type AcceptedBlock struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + 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() { + *x = AcceptedBlock{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AcceptedBlock) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AcceptedBlock) ProtoMessage() {} + +func (x *AcceptedBlock) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AcceptedBlock.ProtoReflect.Descriptor instead. +func (*AcceptedBlock) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{31} +} + +func (x *AcceptedBlock) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *AcceptedBlock) GetAcceptedTransactionIds() []string { + if x != nil { + return x.AcceptedTransactionIds + } + return nil +} + +// GetBlockRequestMessage requests information about a specific block +type GetBlockRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The hash of the requested block + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + SubnetworkId string `protobuf:"bytes,2,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + // Whether to include transaction data in the response + IncludeTransactionVerboseData bool `protobuf:"varint,3,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` +} + +func (x *GetBlockRequestMessage) Reset() { + *x = GetBlockRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockRequestMessage) ProtoMessage() {} + +func (x *GetBlockRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockRequestMessage.ProtoReflect.Descriptor instead. +func (*GetBlockRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{32} +} + +func (x *GetBlockRequestMessage) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *GetBlockRequestMessage) GetSubnetworkId() string { + if x != nil { + return x.SubnetworkId + } + return "" +} + +func (x *GetBlockRequestMessage) GetIncludeTransactionVerboseData() bool { + if x != nil { + return x.IncludeTransactionVerboseData + } + return false +} + +type GetBlockResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockHash string `protobuf:"bytes,1,opt,name=blockHash,proto3" json:"blockHash,omitempty"` + BlockVerboseData *BlockVerboseData `protobuf:"bytes,2,opt,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetBlockResponseMessage) Reset() { + *x = GetBlockResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockResponseMessage) ProtoMessage() {} + +func (x *GetBlockResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockResponseMessage.ProtoReflect.Descriptor instead. +func (*GetBlockResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{33} +} + +func (x *GetBlockResponseMessage) GetBlockHash() string { + if x != nil { + return x.BlockHash + } + return "" +} + +func (x *GetBlockResponseMessage) GetBlockVerboseData() *BlockVerboseData { + if x != nil { + return x.BlockVerboseData + } + return nil +} + +func (x *GetBlockResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type BlockVerboseData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + VersionHex string `protobuf:"bytes,3,opt,name=versionHex,proto3" json:"versionHex,omitempty"` + HashMerkleRoot string `protobuf:"bytes,4,opt,name=hashMerkleRoot,proto3" json:"hashMerkleRoot,omitempty"` + AcceptedIDMerkleRoot string `protobuf:"bytes,5,opt,name=acceptedIDMerkleRoot,proto3" json:"acceptedIDMerkleRoot,omitempty"` + UtxoCommitment string `protobuf:"bytes,6,opt,name=utxoCommitment,proto3" json:"utxoCommitment,omitempty"` + TransactionVerboseData []*TransactionVerboseData `protobuf:"bytes,7,rep,name=transactionVerboseData,proto3" json:"transactionVerboseData,omitempty"` + Time int64 `protobuf:"varint,8,opt,name=time,proto3" json:"time,omitempty"` + Nonce uint64 `protobuf:"varint,9,opt,name=nonce,proto3" json:"nonce,omitempty"` + Bits string `protobuf:"bytes,10,opt,name=bits,proto3" json:"bits,omitempty"` + Difficulty float64 `protobuf:"fixed64,11,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + ParentHashes []string `protobuf:"bytes,12,rep,name=parentHashes,proto3" json:"parentHashes,omitempty"` + SelectedParentHash string `protobuf:"bytes,13,opt,name=selectedParentHash,proto3" json:"selectedParentHash,omitempty"` + TransactionIDs []string `protobuf:"bytes,14,rep,name=transactionIDs,proto3" json:"transactionIDs,omitempty"` + IsHeaderOnly bool `protobuf:"varint,15,opt,name=isHeaderOnly,proto3" json:"isHeaderOnly,omitempty"` + BlueScore uint64 `protobuf:"varint,16,opt,name=blueScore,proto3" json:"blueScore,omitempty"` +} + +func (x *BlockVerboseData) Reset() { + *x = BlockVerboseData{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlockVerboseData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlockVerboseData) ProtoMessage() {} + +func (x *BlockVerboseData) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlockVerboseData.ProtoReflect.Descriptor instead. +func (*BlockVerboseData) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{34} +} + +func (x *BlockVerboseData) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *BlockVerboseData) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *BlockVerboseData) GetVersionHex() string { + if x != nil { + return x.VersionHex + } + return "" +} + +func (x *BlockVerboseData) GetHashMerkleRoot() string { + if x != nil { + return x.HashMerkleRoot + } + return "" +} + +func (x *BlockVerboseData) GetAcceptedIDMerkleRoot() string { + if x != nil { + return x.AcceptedIDMerkleRoot + } + return "" +} + +func (x *BlockVerboseData) GetUtxoCommitment() string { + if x != nil { + return x.UtxoCommitment + } + return "" +} + +func (x *BlockVerboseData) GetTransactionVerboseData() []*TransactionVerboseData { + if x != nil { + return x.TransactionVerboseData + } + return nil +} + +func (x *BlockVerboseData) GetTime() int64 { + if x != nil { + return x.Time + } + return 0 +} + +func (x *BlockVerboseData) GetNonce() uint64 { + if x != nil { + return x.Nonce + } + return 0 +} + +func (x *BlockVerboseData) GetBits() string { + if x != nil { + return x.Bits + } + return "" +} + +func (x *BlockVerboseData) GetDifficulty() float64 { + if x != nil { + return x.Difficulty + } + return 0 +} + +func (x *BlockVerboseData) GetParentHashes() []string { + if x != nil { + return x.ParentHashes + } + return nil +} + +func (x *BlockVerboseData) GetSelectedParentHash() string { + if x != nil { + return x.SelectedParentHash + } + return "" +} + +func (x *BlockVerboseData) GetTransactionIDs() []string { + if x != nil { + return x.TransactionIDs + } + return nil +} + +func (x *BlockVerboseData) GetIsHeaderOnly() bool { + if x != nil { + return x.IsHeaderOnly + } + return false +} + +func (x *BlockVerboseData) GetBlueScore() uint64 { + if x != nil { + return x.BlueScore + } + return 0 +} + +type TransactionVerboseData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` + Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` + Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + Version uint32 `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"` + LockTime uint64 `protobuf:"varint,5,opt,name=lockTime,proto3" json:"lockTime,omitempty"` + SubnetworkId string `protobuf:"bytes,6,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + Gas uint64 `protobuf:"varint,7,opt,name=gas,proto3" json:"gas,omitempty"` + PayloadHash string `protobuf:"bytes,8,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` + Payload string `protobuf:"bytes,9,opt,name=payload,proto3" json:"payload,omitempty"` + TransactionVerboseInputs []*TransactionVerboseInput `protobuf:"bytes,10,rep,name=transactionVerboseInputs,proto3" json:"transactionVerboseInputs,omitempty"` + TransactionVerboseOutputs []*TransactionVerboseOutput `protobuf:"bytes,11,rep,name=transactionVerboseOutputs,proto3" json:"transactionVerboseOutputs,omitempty"` + BlockHash string `protobuf:"bytes,12,opt,name=blockHash,proto3" json:"blockHash,omitempty"` + Time uint64 `protobuf:"varint,13,opt,name=time,proto3" json:"time,omitempty"` + BlockTime uint64 `protobuf:"varint,14,opt,name=blockTime,proto3" json:"blockTime,omitempty"` +} + +func (x *TransactionVerboseData) Reset() { + *x = TransactionVerboseData{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionVerboseData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionVerboseData) ProtoMessage() {} + +func (x *TransactionVerboseData) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionVerboseData.ProtoReflect.Descriptor instead. +func (*TransactionVerboseData) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{35} +} + +func (x *TransactionVerboseData) GetTxId() string { + if x != nil { + return x.TxId + } + return "" +} + +func (x *TransactionVerboseData) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *TransactionVerboseData) GetSize() uint64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *TransactionVerboseData) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *TransactionVerboseData) GetLockTime() uint64 { + if x != nil { + return x.LockTime + } + return 0 +} + +func (x *TransactionVerboseData) GetSubnetworkId() string { + if x != nil { + return x.SubnetworkId + } + return "" +} + +func (x *TransactionVerboseData) GetGas() uint64 { + if x != nil { + return x.Gas + } + return 0 +} + +func (x *TransactionVerboseData) GetPayloadHash() string { + if x != nil { + return x.PayloadHash + } + return "" +} + +func (x *TransactionVerboseData) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +func (x *TransactionVerboseData) GetTransactionVerboseInputs() []*TransactionVerboseInput { + if x != nil { + return x.TransactionVerboseInputs + } + return nil +} + +func (x *TransactionVerboseData) GetTransactionVerboseOutputs() []*TransactionVerboseOutput { + if x != nil { + return x.TransactionVerboseOutputs + } + return nil +} + +func (x *TransactionVerboseData) GetBlockHash() string { + if x != nil { + return x.BlockHash + } + return "" +} + +func (x *TransactionVerboseData) GetTime() uint64 { + if x != nil { + return x.Time + } + return 0 +} + +func (x *TransactionVerboseData) GetBlockTime() uint64 { + if x != nil { + return x.BlockTime + } + return 0 +} + +type TransactionVerboseInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TxId string `protobuf:"bytes,1,opt,name=txId,proto3" json:"txId,omitempty"` + OutputIndex uint32 `protobuf:"varint,2,opt,name=outputIndex,proto3" json:"outputIndex,omitempty"` + ScriptSig *ScriptSig `protobuf:"bytes,3,opt,name=scriptSig,proto3" json:"scriptSig,omitempty"` + Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (x *TransactionVerboseInput) Reset() { + *x = TransactionVerboseInput{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionVerboseInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionVerboseInput) ProtoMessage() {} + +func (x *TransactionVerboseInput) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionVerboseInput.ProtoReflect.Descriptor instead. +func (*TransactionVerboseInput) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{36} +} + +func (x *TransactionVerboseInput) GetTxId() string { + if x != nil { + return x.TxId + } + return "" +} + +func (x *TransactionVerboseInput) GetOutputIndex() uint32 { + if x != nil { + return x.OutputIndex + } + return 0 +} + +func (x *TransactionVerboseInput) GetScriptSig() *ScriptSig { + if x != nil { + return x.ScriptSig + } + return nil +} + +func (x *TransactionVerboseInput) GetSequence() uint64 { + if x != nil { + return x.Sequence + } + return 0 +} + +type ScriptSig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Asm string `protobuf:"bytes,1,opt,name=asm,proto3" json:"asm,omitempty"` + Hex string `protobuf:"bytes,2,opt,name=hex,proto3" json:"hex,omitempty"` +} + +func (x *ScriptSig) Reset() { + *x = ScriptSig{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScriptSig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScriptSig) ProtoMessage() {} + +func (x *ScriptSig) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScriptSig.ProtoReflect.Descriptor instead. +func (*ScriptSig) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{37} +} + +func (x *ScriptSig) GetAsm() string { + if x != nil { + return x.Asm + } + return "" +} + +func (x *ScriptSig) GetHex() string { + if x != nil { + return x.Hex + } + return "" +} + +type TransactionVerboseOutput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + ScriptPublicKey *ScriptPublicKeyResult `protobuf:"bytes,3,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` +} + +func (x *TransactionVerboseOutput) Reset() { + *x = TransactionVerboseOutput{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionVerboseOutput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionVerboseOutput) ProtoMessage() {} + +func (x *TransactionVerboseOutput) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionVerboseOutput.ProtoReflect.Descriptor instead. +func (*TransactionVerboseOutput) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{38} +} + +func (x *TransactionVerboseOutput) GetValue() uint64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *TransactionVerboseOutput) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *TransactionVerboseOutput) GetScriptPublicKey() *ScriptPublicKeyResult { + if x != nil { + return x.ScriptPublicKey + } + return nil +} + +type ScriptPublicKeyResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Asm string `protobuf:"bytes,1,opt,name=asm,proto3" json:"asm,omitempty"` + Hex string `protobuf:"bytes,2,opt,name=hex,proto3" json:"hex,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` +} + +func (x *ScriptPublicKeyResult) Reset() { + *x = ScriptPublicKeyResult{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScriptPublicKeyResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScriptPublicKeyResult) ProtoMessage() {} + +func (x *ScriptPublicKeyResult) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScriptPublicKeyResult.ProtoReflect.Descriptor instead. +func (*ScriptPublicKeyResult) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{39} +} + +func (x *ScriptPublicKeyResult) GetAsm() string { + if x != nil { + return x.Asm + } + return "" +} + +func (x *ScriptPublicKeyResult) GetHex() string { + if x != nil { + return x.Hex + } + return "" +} + +func (x *ScriptPublicKeyResult) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ScriptPublicKeyResult) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +// GetSubnetworkRequestMessage requests information about a specific subnetwork +// +// Currently unimplemented +type GetSubnetworkRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SubnetworkId string `protobuf:"bytes,1,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` +} + +func (x *GetSubnetworkRequestMessage) Reset() { + *x = GetSubnetworkRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSubnetworkRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSubnetworkRequestMessage) ProtoMessage() {} + +func (x *GetSubnetworkRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSubnetworkRequestMessage.ProtoReflect.Descriptor instead. +func (*GetSubnetworkRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{40} +} + +func (x *GetSubnetworkRequestMessage) GetSubnetworkId() string { + if x != nil { + return x.SubnetworkId + } + return "" +} + +type GetSubnetworkResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GasLimit uint64 `protobuf:"varint,1,opt,name=gasLimit,proto3" json:"gasLimit,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetSubnetworkResponseMessage) Reset() { + *x = GetSubnetworkResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSubnetworkResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSubnetworkResponseMessage) ProtoMessage() {} + +func (x *GetSubnetworkResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetSubnetworkResponseMessage.ProtoReflect.Descriptor instead. +func (*GetSubnetworkResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{41} +} + +func (x *GetSubnetworkResponseMessage) GetGasLimit() uint64 { + if x != nil { + return x.GasLimit + } + return 0 +} + +func (x *GetSubnetworkResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected +// parent chain from some startHash to this kaspad's current virtual +type GetVirtualSelectedParentChainFromBlockRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StartHash string `protobuf:"bytes,1,opt,name=startHash,proto3" json:"startHash,omitempty"` +} + +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) Reset() { + *x = GetVirtualSelectedParentChainFromBlockRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoMessage() {} + +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVirtualSelectedParentChainFromBlockRequestMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentChainFromBlockRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{42} +} + +func (x *GetVirtualSelectedParentChainFromBlockRequestMessage) GetStartHash() string { + if x != nil { + return x.StartHash + } + return "" +} + +type GetVirtualSelectedParentChainFromBlockResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The chain blocks that were removed, in high-to-low order + RemovedChainBlockHashes []string `protobuf:"bytes,1,rep,name=removedChainBlockHashes,proto3" json:"removedChainBlockHashes,omitempty"` + // The chain blocks that were added, in low-to-high order + AddedChainBlocks []*ChainBlock `protobuf:"bytes,2,rep,name=addedChainBlocks,proto3" json:"addedChainBlocks,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) Reset() { + *x = GetVirtualSelectedParentChainFromBlockResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoMessage() {} + +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVirtualSelectedParentChainFromBlockResponseMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentChainFromBlockResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{43} +} + +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetRemovedChainBlockHashes() []string { + if x != nil { + return x.RemovedChainBlockHashes + } + return nil +} + +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetAddedChainBlocks() []*ChainBlock { + if x != nil { + return x.AddedChainBlocks + } + return nil +} + +func (x *GetVirtualSelectedParentChainFromBlockResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetBlocksRequestMessage requests blocks between a certain block lowHash up to this +// kaspad's current virtual. +type GetBlocksRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LowHash string `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` + IncludeBlockHexes bool `protobuf:"varint,2,opt,name=includeBlockHexes,proto3" json:"includeBlockHexes,omitempty"` + IncludeBlockVerboseData bool `protobuf:"varint,3,opt,name=includeBlockVerboseData,proto3" json:"includeBlockVerboseData,omitempty"` + IncludeTransactionVerboseData bool `protobuf:"varint,4,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` +} + +func (x *GetBlocksRequestMessage) Reset() { + *x = GetBlocksRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlocksRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlocksRequestMessage) ProtoMessage() {} + +func (x *GetBlocksRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlocksRequestMessage.ProtoReflect.Descriptor instead. +func (*GetBlocksRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{44} +} + +func (x *GetBlocksRequestMessage) GetLowHash() string { + if x != nil { + return x.LowHash + } + return "" +} + +func (x *GetBlocksRequestMessage) GetIncludeBlockHexes() bool { + if x != nil { + return x.IncludeBlockHexes + } + return false +} + +func (x *GetBlocksRequestMessage) GetIncludeBlockVerboseData() bool { + if x != nil { + return x.IncludeBlockVerboseData + } + return false +} + +func (x *GetBlocksRequestMessage) GetIncludeTransactionVerboseData() bool { + if x != nil { + return x.IncludeTransactionVerboseData + } + return false +} + +type GetBlocksResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockHashes []string `protobuf:"bytes,1,rep,name=blockHashes,proto3" json:"blockHashes,omitempty"` + BlockHexes []string `protobuf:"bytes,2,rep,name=blockHexes,proto3" json:"blockHexes,omitempty"` + BlockVerboseData []*BlockVerboseData `protobuf:"bytes,3,rep,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetBlocksResponseMessage) Reset() { + *x = GetBlocksResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlocksResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlocksResponseMessage) ProtoMessage() {} + +func (x *GetBlocksResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlocksResponseMessage.ProtoReflect.Descriptor instead. +func (*GetBlocksResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{45} +} + +func (x *GetBlocksResponseMessage) GetBlockHashes() []string { + if x != nil { + return x.BlockHashes + } + return nil +} + +func (x *GetBlocksResponseMessage) GetBlockHexes() []string { + if x != nil { + return x.BlockHexes + } + return nil +} + +func (x *GetBlocksResponseMessage) GetBlockVerboseData() []*BlockVerboseData { + if x != nil { + return x.BlockVerboseData + } + return nil +} + +func (x *GetBlocksResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetBlockCountRequestMessage requests the current number of blocks in this kaspad. +// Note that this number may decrease as pruning occurs. +type GetBlockCountRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetBlockCountRequestMessage) Reset() { + *x = GetBlockCountRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockCountRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockCountRequestMessage) ProtoMessage() {} + +func (x *GetBlockCountRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockCountRequestMessage.ProtoReflect.Descriptor instead. +func (*GetBlockCountRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{46} +} + +type GetBlockCountResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockCount uint64 `protobuf:"varint,1,opt,name=blockCount,proto3" json:"blockCount,omitempty"` + HeaderCount uint64 `protobuf:"varint,2,opt,name=headerCount,proto3" json:"headerCount,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetBlockCountResponseMessage) Reset() { + *x = GetBlockCountResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockCountResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockCountResponseMessage) ProtoMessage() {} + +func (x *GetBlockCountResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockCountResponseMessage.ProtoReflect.Descriptor instead. +func (*GetBlockCountResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{47} +} + +func (x *GetBlockCountResponseMessage) GetBlockCount() uint64 { + if x != nil { + return x.BlockCount + } + return 0 +} + +func (x *GetBlockCountResponseMessage) GetHeaderCount() uint64 { + if x != nil { + return x.HeaderCount + } + return 0 +} + +func (x *GetBlockCountResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetBlockDagInfoRequestMessage requests general information about the current state +// of this kaspad's DAG. +type GetBlockDagInfoRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetBlockDagInfoRequestMessage) Reset() { + *x = GetBlockDagInfoRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockDagInfoRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockDagInfoRequestMessage) ProtoMessage() {} + +func (x *GetBlockDagInfoRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockDagInfoRequestMessage.ProtoReflect.Descriptor instead. +func (*GetBlockDagInfoRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{48} +} + +type GetBlockDagInfoResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NetworkName string `protobuf:"bytes,1,opt,name=networkName,proto3" json:"networkName,omitempty"` + BlockCount uint64 `protobuf:"varint,2,opt,name=blockCount,proto3" json:"blockCount,omitempty"` + HeaderCount uint64 `protobuf:"varint,3,opt,name=headerCount,proto3" json:"headerCount,omitempty"` + TipHashes []string `protobuf:"bytes,4,rep,name=tipHashes,proto3" json:"tipHashes,omitempty"` + Difficulty float64 `protobuf:"fixed64,5,opt,name=difficulty,proto3" json:"difficulty,omitempty"` + PastMedianTime int64 `protobuf:"varint,6,opt,name=pastMedianTime,proto3" json:"pastMedianTime,omitempty"` + VirtualParentHashes []string `protobuf:"bytes,7,rep,name=virtualParentHashes,proto3" json:"virtualParentHashes,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetBlockDagInfoResponseMessage) Reset() { + *x = GetBlockDagInfoResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlockDagInfoResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlockDagInfoResponseMessage) ProtoMessage() {} + +func (x *GetBlockDagInfoResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlockDagInfoResponseMessage.ProtoReflect.Descriptor instead. +func (*GetBlockDagInfoResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{49} +} + +func (x *GetBlockDagInfoResponseMessage) GetNetworkName() string { + if x != nil { + return x.NetworkName + } + return "" +} + +func (x *GetBlockDagInfoResponseMessage) GetBlockCount() uint64 { + if x != nil { + return x.BlockCount + } + return 0 +} + +func (x *GetBlockDagInfoResponseMessage) GetHeaderCount() uint64 { + if x != nil { + return x.HeaderCount + } + return 0 +} + +func (x *GetBlockDagInfoResponseMessage) GetTipHashes() []string { + if x != nil { + return x.TipHashes + } + return nil +} + +func (x *GetBlockDagInfoResponseMessage) GetDifficulty() float64 { + if x != nil { + return x.Difficulty + } + return 0 +} + +func (x *GetBlockDagInfoResponseMessage) GetPastMedianTime() int64 { + if x != nil { + return x.PastMedianTime + } + return 0 +} + +func (x *GetBlockDagInfoResponseMessage) GetVirtualParentHashes() []string { + if x != nil { + return x.VirtualParentHashes + } + return nil +} + +func (x *GetBlockDagInfoResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type ResolveFinalityConflictRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FinalityBlockHash string `protobuf:"bytes,1,opt,name=finalityBlockHash,proto3" json:"finalityBlockHash,omitempty"` +} + +func (x *ResolveFinalityConflictRequestMessage) Reset() { + *x = ResolveFinalityConflictRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResolveFinalityConflictRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResolveFinalityConflictRequestMessage) ProtoMessage() {} + +func (x *ResolveFinalityConflictRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[50] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResolveFinalityConflictRequestMessage.ProtoReflect.Descriptor instead. +func (*ResolveFinalityConflictRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{50} +} + +func (x *ResolveFinalityConflictRequestMessage) GetFinalityBlockHash() string { + if x != nil { + return x.FinalityBlockHash + } + return "" +} + +type ResolveFinalityConflictResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *ResolveFinalityConflictResponseMessage) Reset() { + *x = ResolveFinalityConflictResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResolveFinalityConflictResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResolveFinalityConflictResponseMessage) ProtoMessage() {} + +func (x *ResolveFinalityConflictResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[51] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResolveFinalityConflictResponseMessage.ProtoReflect.Descriptor instead. +func (*ResolveFinalityConflictResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{51} +} + +func (x *ResolveFinalityConflictResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type NotifyFinalityConflictsRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NotifyFinalityConflictsRequestMessage) Reset() { + *x = NotifyFinalityConflictsRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyFinalityConflictsRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyFinalityConflictsRequestMessage) ProtoMessage() {} + +func (x *NotifyFinalityConflictsRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[52] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyFinalityConflictsRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyFinalityConflictsRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{52} +} + +type NotifyFinalityConflictsResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyFinalityConflictsResponseMessage) Reset() { + *x = NotifyFinalityConflictsResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyFinalityConflictsResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyFinalityConflictsResponseMessage) ProtoMessage() {} + +func (x *NotifyFinalityConflictsResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[53] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyFinalityConflictsResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyFinalityConflictsResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{53} +} + +func (x *NotifyFinalityConflictsResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +type FinalityConflictNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ViolatingBlockHash string `protobuf:"bytes,1,opt,name=violatingBlockHash,proto3" json:"violatingBlockHash,omitempty"` +} + +func (x *FinalityConflictNotificationMessage) Reset() { + *x = FinalityConflictNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FinalityConflictNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FinalityConflictNotificationMessage) ProtoMessage() {} + +func (x *FinalityConflictNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[54] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FinalityConflictNotificationMessage.ProtoReflect.Descriptor instead. +func (*FinalityConflictNotificationMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{54} +} + +func (x *FinalityConflictNotificationMessage) GetViolatingBlockHash() string { + if x != nil { + return x.ViolatingBlockHash + } + return "" +} + +type FinalityConflictResolvedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FinalityBlockHash string `protobuf:"bytes,1,opt,name=finalityBlockHash,proto3" json:"finalityBlockHash,omitempty"` +} + +func (x *FinalityConflictResolvedNotificationMessage) Reset() { + *x = FinalityConflictResolvedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FinalityConflictResolvedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FinalityConflictResolvedNotificationMessage) ProtoMessage() {} + +func (x *FinalityConflictResolvedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[55] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FinalityConflictResolvedNotificationMessage.ProtoReflect.Descriptor instead. +func (*FinalityConflictResolvedNotificationMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{55} +} + +func (x *FinalityConflictResolvedNotificationMessage) GetFinalityBlockHash() string { + if x != nil { + return x.FinalityBlockHash + } + return "" +} + +// ShutDownRequestMessage shuts down this kaspad. +type ShutDownRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ShutDownRequestMessage) Reset() { + *x = ShutDownRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShutDownRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShutDownRequestMessage) ProtoMessage() {} + +func (x *ShutDownRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[56] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShutDownRequestMessage.ProtoReflect.Descriptor instead. +func (*ShutDownRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{56} +} + +type ShutDownResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *ShutDownResponseMessage) Reset() { + *x = ShutDownResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShutDownResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShutDownResponseMessage) ProtoMessage() {} + +func (x *ShutDownResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[57] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShutDownResponseMessage.ProtoReflect.Descriptor instead. +func (*ShutDownResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{57} +} + +func (x *ShutDownResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetHeadersRequestMessage requests headers between the given startHash and the +// current virtual, up to the given limit. +type GetHeadersRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StartHash string `protobuf:"bytes,1,opt,name=startHash,proto3" json:"startHash,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + IsAscending bool `protobuf:"varint,3,opt,name=isAscending,proto3" json:"isAscending,omitempty"` +} + +func (x *GetHeadersRequestMessage) Reset() { + *x = GetHeadersRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetHeadersRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHeadersRequestMessage) ProtoMessage() {} + +func (x *GetHeadersRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[58] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHeadersRequestMessage.ProtoReflect.Descriptor instead. +func (*GetHeadersRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{58} +} + +func (x *GetHeadersRequestMessage) GetStartHash() string { + if x != nil { + return x.StartHash + } + return "" +} + +func (x *GetHeadersRequestMessage) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *GetHeadersRequestMessage) GetIsAscending() bool { + if x != nil { + return x.IsAscending + } + return false +} + +type GetHeadersResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Headers []string `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetHeadersResponseMessage) Reset() { + *x = GetHeadersResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetHeadersResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHeadersResponseMessage) ProtoMessage() {} + +func (x *GetHeadersResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[59] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHeadersResponseMessage.ProtoReflect.Descriptor instead. +func (*GetHeadersResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{59} +} + +func (x *GetHeadersResponseMessage) GetHeaders() []string { + if x != nil { + return x.Headers + } + return nil +} + +func (x *GetHeadersResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications +// for the given addresses. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: UtxosChangedNotificationMessage +type NotifyUtxosChangedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (x *NotifyUtxosChangedRequestMessage) Reset() { + *x = NotifyUtxosChangedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyUtxosChangedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyUtxosChangedRequestMessage) ProtoMessage() {} + +func (x *NotifyUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[60] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{60} +} + +func (x *NotifyUtxosChangedRequestMessage) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +type NotifyUtxosChangedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyUtxosChangedResponseMessage) Reset() { + *x = NotifyUtxosChangedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyUtxosChangedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyUtxosChangedResponseMessage) ProtoMessage() {} + +func (x *NotifyUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[61] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{61} +} + +func (x *NotifyUtxosChangedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated. +// +// See: NotifyUtxosChangedRequestMessage +type UtxosChangedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Added []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=added,proto3" json:"added,omitempty"` + Removed []*UtxosByAddressesEntry `protobuf:"bytes,2,rep,name=removed,proto3" json:"removed,omitempty"` +} + +func (x *UtxosChangedNotificationMessage) Reset() { + *x = UtxosChangedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UtxosChangedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UtxosChangedNotificationMessage) ProtoMessage() {} + +func (x *UtxosChangedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[62] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UtxosChangedNotificationMessage.ProtoReflect.Descriptor instead. +func (*UtxosChangedNotificationMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{62} +} + +func (x *UtxosChangedNotificationMessage) GetAdded() []*UtxosByAddressesEntry { + if x != nil { + return x.Added + } + return nil +} + +func (x *UtxosChangedNotificationMessage) GetRemoved() []*UtxosByAddressesEntry { + if x != nil { + return x.Removed + } + return nil +} + +type UtxosByAddressesEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Outpoint *RpcOutpoint `protobuf:"bytes,2,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + UtxoEntry *RpcUtxoEntry `protobuf:"bytes,3,opt,name=utxoEntry,proto3" json:"utxoEntry,omitempty"` +} + +func (x *UtxosByAddressesEntry) Reset() { + *x = UtxosByAddressesEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UtxosByAddressesEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UtxosByAddressesEntry) ProtoMessage() {} + +func (x *UtxosByAddressesEntry) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[63] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UtxosByAddressesEntry.ProtoReflect.Descriptor instead. +func (*UtxosByAddressesEntry) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{63} +} + +func (x *UtxosByAddressesEntry) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *UtxosByAddressesEntry) GetOutpoint() *RpcOutpoint { + if x != nil { + return x.Outpoint + } + return nil +} + +func (x *UtxosByAddressesEntry) GetUtxoEntry() *RpcUtxoEntry { + if x != nil { + return x.UtxoEntry + } + return nil +} + +type RpcTransaction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Inputs []*RpcTransactionInput `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*RpcTransactionOutput `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` + LockTime uint64 `protobuf:"varint,4,opt,name=lockTime,proto3" json:"lockTime,omitempty"` + SubnetworkId string `protobuf:"bytes,5,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + Gas uint64 `protobuf:"varint,6,opt,name=gas,proto3" json:"gas,omitempty"` + PayloadHash string `protobuf:"bytes,7,opt,name=payloadHash,proto3" json:"payloadHash,omitempty"` + Payload string `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *RpcTransaction) Reset() { + *x = RpcTransaction{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcTransaction) ProtoMessage() {} + +func (x *RpcTransaction) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[64] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. +func (*RpcTransaction) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{64} +} + +func (x *RpcTransaction) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *RpcTransaction) GetInputs() []*RpcTransactionInput { + if x != nil { + return x.Inputs + } + return nil +} + +func (x *RpcTransaction) GetOutputs() []*RpcTransactionOutput { + if x != nil { + return x.Outputs + } + return nil +} + +func (x *RpcTransaction) GetLockTime() uint64 { + if x != nil { + return x.LockTime + } + return 0 +} + +func (x *RpcTransaction) GetSubnetworkId() string { + if x != nil { + return x.SubnetworkId + } + return "" +} + +func (x *RpcTransaction) GetGas() uint64 { + if x != nil { + return x.Gas + } + return 0 +} + +func (x *RpcTransaction) GetPayloadHash() string { + if x != nil { + return x.PayloadHash + } + return "" +} + +func (x *RpcTransaction) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +type RpcTransactionInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PreviousOutpoint *RpcOutpoint `protobuf:"bytes,1,opt,name=previousOutpoint,proto3" json:"previousOutpoint,omitempty"` + SignatureScript string `protobuf:"bytes,2,opt,name=signatureScript,proto3" json:"signatureScript,omitempty"` + Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (x *RpcTransactionInput) Reset() { + *x = RpcTransactionInput{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcTransactionInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcTransactionInput) ProtoMessage() {} + +func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[65] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. +func (*RpcTransactionInput) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{65} +} + +func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { + if x != nil { + return x.PreviousOutpoint + } + return nil +} + +func (x *RpcTransactionInput) GetSignatureScript() string { + if x != nil { + return x.SignatureScript + } + return "" +} + +func (x *RpcTransactionInput) GetSequence() uint64 { + if x != nil { + return x.Sequence + } + return 0 +} + +type RpcScriptPublicKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + ScriptPublicKey string `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` +} + +func (x *RpcScriptPublicKey) Reset() { + *x = RpcScriptPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcScriptPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcScriptPublicKey) ProtoMessage() {} + +func (x *RpcScriptPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[66] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcScriptPublicKey.ProtoReflect.Descriptor instead. +func (*RpcScriptPublicKey) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{66} +} + +func (x *RpcScriptPublicKey) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *RpcScriptPublicKey) GetScriptPublicKey() string { + if x != nil { + return x.ScriptPublicKey + } + return "" +} + +type RpcTransactionOutput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *RpcScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` +} + +func (x *RpcTransactionOutput) Reset() { + *x = RpcTransactionOutput{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[67] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcTransactionOutput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcTransactionOutput) ProtoMessage() {} + +func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[67] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. +func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{67} +} + +func (x *RpcTransactionOutput) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *RpcTransactionOutput) GetScriptPublicKey() *RpcScriptPublicKey { + if x != nil { + return x.ScriptPublicKey + } + return nil +} + +type RpcOutpoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TransactionId string `protobuf:"bytes,1,opt,name=transactionId,proto3" json:"transactionId,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` +} + +func (x *RpcOutpoint) Reset() { + *x = RpcOutpoint{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcOutpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcOutpoint) ProtoMessage() {} + +func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[68] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. +func (*RpcOutpoint) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{68} +} + +func (x *RpcOutpoint) GetTransactionId() string { + if x != nil { + return x.TransactionId + } + return "" +} + +func (x *RpcOutpoint) GetIndex() uint32 { + if x != nil { + return x.Index + } + return 0 +} + +type RpcUtxoEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *RpcScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` + BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` + IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` +} + +func (x *RpcUtxoEntry) Reset() { + *x = RpcUtxoEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcUtxoEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcUtxoEntry) ProtoMessage() {} + +func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[69] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. +func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{69} +} + +func (x *RpcUtxoEntry) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *RpcUtxoEntry) GetScriptPublicKey() *RpcScriptPublicKey { + if x != nil { + return x.ScriptPublicKey + } + return nil +} + +func (x *RpcUtxoEntry) GetBlockBlueScore() uint64 { + if x != nil { + return x.BlockBlueScore + } + return 0 +} + +func (x *RpcUtxoEntry) GetIsCoinbase() bool { + if x != nil { + return x.IsCoinbase + } + return false +} + +// GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses +// +// This call is only available when this kaspad was started with `--utxoindex` +type GetUtxosByAddressesRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (x *GetUtxosByAddressesRequestMessage) Reset() { + *x = GetUtxosByAddressesRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUtxosByAddressesRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} + +func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[70] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. +func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{70} +} + +func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +type GetUtxosByAddressesResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entries []*UtxosByAddressesEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetUtxosByAddressesResponseMessage) Reset() { + *x = GetUtxosByAddressesResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUtxosByAddressesResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} + +func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[71] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. +func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{71} +} + +func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { + if x != nil { + return x.Entries + } + return nil +} + +func (x *GetUtxosByAddressesResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent +// of the virtual block. +type GetVirtualSelectedParentBlueScoreRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { + *x = GetVirtualSelectedParentBlueScoreRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} + +func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[72] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{72} +} + +type GetVirtualSelectedParentBlueScoreResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlueScore uint64 `protobuf:"varint,1,opt,name=blueScore,proto3" json:"blueScore,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { + *x = GetVirtualSelectedParentBlueScoreResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[73] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. +func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{73} +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { + if x != nil { + return x.BlueScore + } + return 0 +} + +func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// NotifyVirtualSelectedParentBlueScoreChangedRequestMessage registers this connection for +// virtualSelectedParentBlueScoreChanged notifications. +// +// See: VirtualSelectedParentBlueScoreChangedNotificationMessage +type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { + *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[74] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{74} +} + +type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { + *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[75] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{75} +} + +func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score +// of the virtual's selected parent changes. +// +// See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage +type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + VirtualSelectedParentBlueScore uint64 `protobuf:"varint,1,opt,name=virtualSelectedParentBlueScore,proto3" json:"virtualSelectedParentBlueScore,omitempty"` +} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { + *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[76] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. +func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{76} +} + +func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { + if x != nil { + return x.VirtualSelectedParentBlueScore + } + return 0 +} + +var File_rpc_proto protoreflect.FileDescriptor + +var file_rpc_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x76, 0x0a, 0x20, 0x47, 0x65, + 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x26, + 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 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, 0x4a, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, + 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, + 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, + 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, + 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, + 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 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, 0x39, + 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, + 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, + 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, + 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x69, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, + 0x66, 0x65, 0x65, 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, 0x02, 0x20, + 0x01, 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, 0x22, 0x24, + 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, + 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xd3, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, + 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, + 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, 0x22, 0x53, 0x0a, 0x15, + 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, + 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 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, 0x37, 0x0a, + 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 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, 0xb3, 0x01, 0x0a, + 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, + 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, + 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 0x0d, 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, 0x92, + 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 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, 0x22, + 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 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, 0x95, 0x01, + 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, + 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, + 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, + 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, + 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, + 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, + 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, + 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 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, 0x31, + 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 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, + 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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 ( + file_rpc_proto_rawDescOnce sync.Once + file_rpc_proto_rawDescData = file_rpc_proto_rawDesc +) + +func file_rpc_proto_rawDescGZIP() []byte { + file_rpc_proto_rawDescOnce.Do(func() { + file_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_proto_rawDescData) + }) + return file_rpc_proto_rawDescData +} + +var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 77) +var file_rpc_proto_goTypes = []interface{}{ + (*RPCError)(nil), // 0: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 1: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 2: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 3: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 4: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 5: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 6: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 7: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 8: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 9: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 10: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 11: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 12: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 13: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 14: protowire.GetSelectedTipHashResponseMessage + (*GetMempoolEntryRequestMessage)(nil), // 15: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 16: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 17: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 18: protowire.GetMempoolEntriesResponseMessage + (*MempoolEntry)(nil), // 19: protowire.MempoolEntry + (*GetConnectedPeerInfoRequestMessage)(nil), // 20: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 21: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 22: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 23: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 24: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 25: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 26: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 27: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 28: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 29: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*ChainBlock)(nil), // 30: protowire.ChainBlock + (*AcceptedBlock)(nil), // 31: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 32: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 33: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 34: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 35: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 36: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 37: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 38: protowire.TransactionVerboseOutput + (*ScriptPublicKeyResult)(nil), // 39: protowire.ScriptPublicKeyResult + (*GetSubnetworkRequestMessage)(nil), // 40: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 41: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 42: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 43: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 44: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 45: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 46: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 47: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 48: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 49: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 50: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 51: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 52: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 53: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 54: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 55: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 56: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 57: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 58: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 59: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 60: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 61: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 62: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 63: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 64: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 65: protowire.RpcTransactionInput + (*RpcScriptPublicKey)(nil), // 66: protowire.RpcScriptPublicKey + (*RpcTransactionOutput)(nil), // 67: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 68: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 69: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 70: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 71: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 72: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 73: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 74: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 75: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 76: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*BlockMessage)(nil), // 77: protowire.BlockMessage +} +var file_rpc_proto_depIdxs = []int32{ + 0, // 0: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 77, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 0, // 2: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 77, // 3: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 0, // 4: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 0, // 5: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 77, // 6: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 12, // 7: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 12, // 8: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 0, // 9: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 0, // 10: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 19, // 11: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 0, // 12: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 19, // 13: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 0, // 14: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 35, // 15: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 22, // 16: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 0, // 17: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 0, // 18: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 64, // 19: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 0, // 20: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 0, // 21: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 30, // 22: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 31, // 23: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 34, // 24: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 0, // 25: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 35, // 26: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 36, // 27: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 38, // 28: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 37, // 29: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 39, // 30: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult + 0, // 31: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 30, // 32: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 0, // 33: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 34, // 34: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 0, // 35: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 0, // 36: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 0, // 37: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 0, // 38: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 0, // 39: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 0, // 40: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 0, // 41: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 0, // 42: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 63, // 43: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 63, // 44: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 68, // 45: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 69, // 46: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 65, // 47: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 67, // 48: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 68, // 49: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 66, // 50: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 66, // 51: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 63, // 52: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 0, // 53: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 0, // 54: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 0, // 55: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 56, // [56:56] is the sub-list for method output_type + 56, // [56:56] is the sub-list for method input_type + 56, // [56:56] is the sub-list for extension type_name + 56, // [56:56] is the sub-list for extension extendee + 0, // [0:56] is the sub-list for field type_name +} + +func init() { file_rpc_proto_init() } +func file_rpc_proto_init() { + if File_rpc_proto != nil { + return + } + file_p2p_proto_init() + if !protoimpl.UnsafeEnabled { + file_rpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RPCError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetCurrentNetworkRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetCurrentNetworkResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitBlockRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitBlockResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockTemplateRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockTemplateResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyBlockAddedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyBlockAddedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockAddedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPeerAddressesRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPeerAddressesResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPeerAddressesKnownAddressMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSelectedTipHashRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSelectedTipHashResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMempoolEntryRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMempoolEntryResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMempoolEntriesRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMempoolEntriesResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MempoolEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetConnectedPeerInfoRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetConnectedPeerInfoResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetConnectedPeerInfoMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddPeerRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddPeerResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitTransactionRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitTransactionResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentChainChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentChainChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VirtualSelectedParentChainChangedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChainBlock); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AcceptedBlock); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlockVerboseData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionVerboseData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionVerboseInput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScriptSig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionVerboseOutput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScriptPublicKeyResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSubnetworkRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSubnetworkResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetVirtualSelectedParentChainFromBlockRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetVirtualSelectedParentChainFromBlockResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlocksRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlocksResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockCountRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockCountResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockDagInfoRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlockDagInfoResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResolveFinalityConflictRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResolveFinalityConflictResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyFinalityConflictsRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyFinalityConflictsResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FinalityConflictNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FinalityConflictResolvedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShutDownRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShutDownResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetHeadersRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetHeadersResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyUtxosChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyUtxosChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UtxosChangedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UtxosByAddressesEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcTransaction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcTransactionInput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcScriptPublicKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcTransactionOutput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcOutpoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcUtxoEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_rpc_proto_rawDesc, + NumEnums: 0, + NumMessages: 77, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_rpc_proto_goTypes, + DependencyIndexes: file_rpc_proto_depIdxs, + MessageInfos: file_rpc_proto_msgTypes, + }.Build() + File_rpc_proto = out.File + file_rpc_proto_rawDesc = nil + file_rpc_proto_goTypes = nil + file_rpc_proto_depIdxs = nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto new file mode 100644 index 000000000..9f8176ad3 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -0,0 +1,529 @@ +// RPC-related types. Request messages, response messages, and dependant types. +// +// Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto) +// +// Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a +// ResponseMessage (likewise wrapped in a KaspadMessage) respective to the original RequestMessage. +// +// **IMPORTANT:** This API is a work in progress and is subject to break between versions. +// +syntax = "proto3"; +package protowire; + +option go_package = "github.com/kaspanet/kaspad/protowire"; + +import "p2p.proto"; + +// RPCError represents a generic non-internal error. +// +// Receivers of any ResponseMessage are expected to check whether its error field is not null. +message RPCError{ + string message = 1; +} + +// GetCurrentNetworkRequestMessage requests the network kaspad is currently running against. +// +// Possible networks are: Mainnet, Testnet, Simnet, Devnet +message GetCurrentNetworkRequestMessage{ +} + +message GetCurrentNetworkResponseMessage{ + string currentNetwork = 1; + RPCError error = 1000; +} + +// SubmitBlockRequestMessage requests to submit a block into the DAG. +// Blocks are generally expected to have been generated using the getBlockTemplate call. +// +// See: GetBlockTemplateRequestMessage +message SubmitBlockRequestMessage{ + BlockMessage block = 1; +} + +message SubmitBlockResponseMessage{ + RPCError error = 1000; +} + +// GetBlockTemplateRequestMessage requests a current block template. +// Callers are expected to solve the block template and submit it using the submitBlock call +// +// See: SubmitBlockRequestMessage +message GetBlockTemplateRequestMessage{ + // Which kaspa address should the coinbase block reward transaction pay into + string payAddress = 1; +} + +message GetBlockTemplateResponseMessage{ + BlockMessage blockMessage = 1; + + // Whether kaspad thinks that it's synced. + // Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. + // That is because when kaspad isn't in sync with the rest of the network there's a high + // chance the block will never be accepted, thus the solving effort would have been wasted. + bool isSynced = 2; + + RPCError error = 1000; +} + +// NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications. +// +// See: BlockAddedNotificationMessage +message NotifyBlockAddedRequestMessage{ +} + +message NotifyBlockAddedResponseMessage{ + RPCError error = 1000; +} + +// BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted) +// into the DAG. +// +// See: NotifyBlockAddedRequestMessage +message BlockAddedNotificationMessage{ + BlockMessage block = 1; +} + +// GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the +// current network. (mainnet, testnet, etc.) +message GetPeerAddressesRequestMessage{ +} + +message GetPeerAddressesResponseMessage{ + repeated GetPeerAddressesKnownAddressMessage addresses = 1; + repeated GetPeerAddressesKnownAddressMessage bannedAddresses = 2; + RPCError error = 1000; +} + +message GetPeerAddressesKnownAddressMessage { + string Addr = 1; +} + +// GetSelectedTipHashRequestMessage requests the hash of the current virtual's +// selected parent. +message GetSelectedTipHashRequestMessage{ +} + +message GetSelectedTipHashResponseMessage{ + string selectedTipHash = 1; + RPCError error = 1000; +} + +// GetMempoolEntryRequestMessage requests information about a specific transaction +// in the mempool. +message GetMempoolEntryRequestMessage{ + // The transaction's TransactionID. + string txId = 1; +} + +message GetMempoolEntryResponseMessage{ + MempoolEntry entry = 1; + + RPCError error = 1000; +} + +// GetMempoolEntriesRequestMessage requests information about all the transactions +// currently in the mempool. +message GetMempoolEntriesRequestMessage{ +} + +message GetMempoolEntriesResponseMessage{ + repeated MempoolEntry entries = 1; + + RPCError error = 1000; +} + +message MempoolEntry{ + uint64 fee = 1; + TransactionVerboseData transactionVerboseData = 2; +} + +// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers +// currently connected to this kaspad. +message GetConnectedPeerInfoRequestMessage{ +} + +message GetConnectedPeerInfoResponseMessage{ + repeated GetConnectedPeerInfoMessage infos = 1; + RPCError error = 1000; +} + +message GetConnectedPeerInfoMessage{ + string id = 1; + string address = 2; + + // How long did the last ping/pong exchange take + int64 lastPingDuration = 3; + + // Whether this kaspad initiated the connection + bool isOutbound = 6; + int64 timeOffset = 7; + string userAgent = 8; + + // The protocol version that this peer claims to support + uint32 advertisedProtocolVersion = 9; + + // The timestamp of when this peer connected to this kaspad + int64 timeConnected = 10; + + // Whether this peer is the IBD peer (if IBD is running) + bool isIbdPeer = 11; +} + +// AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. +// This will, in most cases, result in kaspad connecting to said peer. +message AddPeerRequestMessage{ + string address = 1; + + // Whether to keep attempting to connect to this peer after disconnection + bool isPermanent = 2; +} + +message AddPeerResponseMessage{ + RPCError error = 1000; +} + +// SubmitTransactionRequestMessage submits a transaction to the mempool +message SubmitTransactionRequestMessage{ + RpcTransaction transaction = 1; +} + +message SubmitTransactionResponseMessage{ + // The transaction ID of the submitted transaction + string transactionId = 1; + + RPCError error = 1000; +} + +// NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged notifications. +// +// See: VirtualSelectedParentChainChangedNotificationMessage +message NotifyVirtualSelectedParentChainChangedRequestMessage{ +} + +message NotifyVirtualSelectedParentChainChangedResponseMessage{ + RPCError error = 1000; +} + +// VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent +// chain had changed. +// +// See: NotifyVirtualSelectedParentChainChangedRequestMessage +message VirtualSelectedParentChainChangedNotificationMessage{ + // The chain blocks that were removed, in high-to-low order + repeated string removedChainBlockHashes = 1; + + // The chain blocks that were added, in low-to-high order + repeated ChainBlock addedChainBlocks = 2; +} + +message ChainBlock{ + string hash = 1; + repeated AcceptedBlock acceptedBlocks = 2; +} + +message AcceptedBlock{ + string hash = 1; + repeated string acceptedTransactionIds = 2; +} + +// GetBlockRequestMessage requests information about a specific block +message GetBlockRequestMessage{ + // The hash of the requested block + string hash = 1; + string subnetworkId = 2; + + // Whether to include transaction data in the response + bool includeTransactionVerboseData = 3; +} + +message GetBlockResponseMessage{ + string blockHash = 1; + BlockVerboseData blockVerboseData = 2; + RPCError error = 1000; +} + +message BlockVerboseData{ + string hash = 1; + uint32 version = 2; + string versionHex = 3; + string hashMerkleRoot = 4; + string acceptedIDMerkleRoot = 5; + string utxoCommitment = 6; + repeated TransactionVerboseData transactionVerboseData = 7; + int64 time = 8; + uint64 nonce = 9; + string bits = 10; + double difficulty = 11; + repeated string parentHashes = 12; + string selectedParentHash = 13; + repeated string transactionIDs = 14; + bool isHeaderOnly = 15; + uint64 blueScore = 16; +} + +message TransactionVerboseData{ + string txId = 1; + string hash = 2; + uint64 size = 3; + uint32 version = 4; + uint64 lockTime = 5; + string subnetworkId = 6; + uint64 gas = 7; + string payloadHash = 8; + string payload = 9; + repeated TransactionVerboseInput transactionVerboseInputs = 10; + repeated TransactionVerboseOutput transactionVerboseOutputs = 11; + string blockHash = 12; + uint64 time = 13; + uint64 blockTime = 14; +} + +message TransactionVerboseInput{ + string txId = 1; + uint32 outputIndex = 2; + ScriptSig scriptSig = 3; + uint64 sequence = 4; +} + +message ScriptSig{ + string asm = 1; + string hex = 2; +} + +message TransactionVerboseOutput{ + uint64 value = 1; + uint32 index = 2; + ScriptPublicKeyResult scriptPublicKey = 3; +} + +message ScriptPublicKeyResult{ + string asm = 1; + string hex = 2; + string type = 3; + string address = 4; +} + +// GetSubnetworkRequestMessage requests information about a specific subnetwork +// +// Currently unimplemented +message GetSubnetworkRequestMessage{ + string subnetworkId = 1; +} + +message GetSubnetworkResponseMessage{ + uint64 gasLimit = 1; + RPCError error = 1000; +} + +// GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected +// parent chain from some startHash to this kaspad's current virtual +message GetVirtualSelectedParentChainFromBlockRequestMessage{ + string startHash = 1; +} + +message GetVirtualSelectedParentChainFromBlockResponseMessage{ + // The chain blocks that were removed, in high-to-low order + repeated string removedChainBlockHashes = 1; + + // The chain blocks that were added, in low-to-high order + repeated ChainBlock addedChainBlocks = 2; + + RPCError error = 1000; +} + +// GetBlocksRequestMessage requests blocks between a certain block lowHash up to this +// kaspad's current virtual. +message GetBlocksRequestMessage{ + string lowHash = 1; + bool includeBlockHexes = 2; + bool includeBlockVerboseData = 3; + bool includeTransactionVerboseData = 4; +} + +message GetBlocksResponseMessage{ + repeated string blockHashes = 1; + repeated string blockHexes = 2; + repeated BlockVerboseData blockVerboseData = 3; + RPCError error = 1000; +} + +// GetBlockCountRequestMessage requests the current number of blocks in this kaspad. +// Note that this number may decrease as pruning occurs. +message GetBlockCountRequestMessage{ +} + +message GetBlockCountResponseMessage{ + uint64 blockCount = 1; + uint64 headerCount = 2; + RPCError error = 1000; +} + +// GetBlockDagInfoRequestMessage requests general information about the current state +// of this kaspad's DAG. +message GetBlockDagInfoRequestMessage{ +} + +message GetBlockDagInfoResponseMessage{ + string networkName = 1; + uint64 blockCount = 2; + uint64 headerCount = 3; + repeated string tipHashes = 4; + double difficulty = 5; + int64 pastMedianTime = 6; + repeated string virtualParentHashes = 7; + RPCError error = 1000; +} + +message ResolveFinalityConflictRequestMessage{ + string finalityBlockHash = 1; +} + +message ResolveFinalityConflictResponseMessage{ + RPCError error = 1000; +} + +message NotifyFinalityConflictsRequestMessage{ +} + +message NotifyFinalityConflictsResponseMessage{ + RPCError error = 1000; +} + +message FinalityConflictNotificationMessage{ + string violatingBlockHash = 1; +} + +message FinalityConflictResolvedNotificationMessage{ + string finalityBlockHash = 1; +} + +// ShutDownRequestMessage shuts down this kaspad. +message ShutDownRequestMessage{ +} + +message ShutDownResponseMessage{ + RPCError error = 1000; +} + +// GetHeadersRequestMessage requests headers between the given startHash and the +// current virtual, up to the given limit. +message GetHeadersRequestMessage{ + string startHash = 1; + uint64 limit = 2; + bool isAscending = 3; +} + +message GetHeadersResponseMessage{ + repeated string headers = 1; + RPCError error = 1000; +} + +// NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications +// for the given addresses. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: UtxosChangedNotificationMessage +message NotifyUtxosChangedRequestMessage { + repeated string addresses = 1; +} + +message NotifyUtxosChangedResponseMessage { + RPCError error = 1000; +} + +// UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated. +// +// See: NotifyUtxosChangedRequestMessage +message UtxosChangedNotificationMessage { + repeated UtxosByAddressesEntry added = 1; + repeated UtxosByAddressesEntry removed = 2; +} + +message UtxosByAddressesEntry { + string address = 1; + RpcOutpoint outpoint = 2; + RpcUtxoEntry utxoEntry = 3; +} + +message RpcTransaction { + uint32 version = 1; + repeated RpcTransactionInput inputs = 2; + repeated RpcTransactionOutput outputs = 3; + uint64 lockTime = 4; + string subnetworkId = 5; + uint64 gas = 6; + string payloadHash = 7; + string payload = 8; +} + +message RpcTransactionInput { + RpcOutpoint previousOutpoint = 1; + string signatureScript = 2; + uint64 sequence = 3; +} + +message RpcScriptPublicKey { + uint32 version = 1; + string scriptPublicKey = 2; +} + +message RpcTransactionOutput { + uint64 amount = 1; + RpcScriptPublicKey scriptPublicKey = 2; +} + +message RpcOutpoint { + string transactionId = 1; + uint32 index = 2; +} + +message RpcUtxoEntry { + uint64 amount = 1; + RpcScriptPublicKey scriptPublicKey = 2; + uint64 blockBlueScore = 3; + bool isCoinbase = 4; +} + +// GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses +// +// This call is only available when this kaspad was started with `--utxoindex` +message GetUtxosByAddressesRequestMessage { + repeated string addresses = 1; +} + +message GetUtxosByAddressesResponseMessage { + repeated UtxosByAddressesEntry entries = 1; + + RPCError error = 1000; +} + +// GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent +// of the virtual block. +message GetVirtualSelectedParentBlueScoreRequestMessage { +} + +message GetVirtualSelectedParentBlueScoreResponseMessage { + uint64 blueScore = 1; + + RPCError error = 1000; +} + +// NotifyVirtualSelectedParentBlueScoreChangedRequestMessage registers this connection for +// virtualSelectedParentBlueScoreChanged notifications. +// +// See: VirtualSelectedParentBlueScoreChangedNotificationMessage +message NotifyVirtualSelectedParentBlueScoreChangedRequestMessage { +} + +message NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { + RPCError error = 1000; +} + +// VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score +// of the virtual's selected parent changes. +// +// See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage +message VirtualSelectedParentBlueScoreChangedNotificationMessage { + uint64 virtualSelectedParentBlueScore = 1; +} From 285ae5cd405ad31027dfed644c6aafea9fc83717 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 10 Jan 2021 09:13:00 +0200 Subject: [PATCH 226/351] Update READMEs and add CONTRIBUTING.md (#1381) * Update READMEs and add CONTRIBUTING.md * Update go version * Update READMEs and CONTRIBUTING.md * Update README.md * Update README.md * Update README.md --- CONTRIBUTING.md | 19 ++++++++++++++ README.md | 25 ++++++++----------- cmd/kaspactl/README.md | 53 ++++++++++++++++++++++++++++++++++++++++ cmd/kaspaminer/README.md | 45 ++++++++++++++++++++++++++++++++++ cmd/wallet/README.md | 29 ++++++++++++++++++++++ 5 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 cmd/kaspactl/README.md create mode 100644 cmd/kaspaminer/README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..33107f6e9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,19 @@ +# Contributing to Kaspad + +Any contribution to Kaspad is very welcome. + +## Getting started + +If you want to start contributing to Kaspad and don't know where to start, you can pick an issue from +the [list](https://github.com/kaspanet/kaspad/issues). + +If you want to make a big change it's better to discuss it first by opening an issue or talk about it in +[Discord](https://discord.gg/WmGhhzk) to avoid duplicate work. + +## Pull Request process + +Any pull request should be opened against the development branch of the target version. The development branch format is +as follows: `vx.y.z-dev`, for example: `v0.8.5-dev`. + +All pull requests should pass the checks written in `build_and_test.sh`, so it's recommended to run this script before +submitting your PR. \ No newline at end of file diff --git a/README.md b/README.md index 2e50a2b13..542ec885a 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,16 @@ Warning: This is pre-alpha software. There's no guarantee anything works. Kaspad is the reference full node Kaspa implementation written in Go (golang). -This project is currently under active development and is in a pre-Alpha state. +This project is currently under active development and is in a pre-Alpha state. Some things still don't work and APIs are far from finalized. The code is provided for reference only. +## What is kaspa + +Kaspa is an attempt at a proof-of-work cryptocurrency with instant confirmations and sub-second block times. It is based on [the PHANTOM protocol](https://eprint.iacr.org/2018/104.pdf), a generalization of Nakamoto consensus. + ## Requirements -Latest version of [Go](http://golang.org) (currently 1.13). +Go 1.14 or later. ## Installation @@ -27,23 +31,17 @@ Latest version of [Go](http://golang.org) (currently 1.13). ```bash $ go version -$ go env GOROOT GOPATH ``` -NOTE: The `GOROOT` and `GOPATH` above must not be the same path. It is -recommended that `GOPATH` is set to a directory in your home directory such as -`~/dev/go` to avoid write permission issues. It is also recommended to add -`$GOPATH/bin` to your `PATH` at this point. - - Run the following commands to obtain and install kaspad including all dependencies: ```bash -$ git clone https://github.com/kaspanet/kaspad $GOPATH/src/github.com/kaspanet/kaspad -$ cd $GOPATH/src/github.com/kaspanet/kaspad +$ git clone https://github.com/kaspanet/kaspad +$ cd kaspad $ go install . ./cmd/... ``` -- Kaspad (and utilities) should now be installed in `$GOPATH/bin`. If you did +- Kaspad (and utilities) should now be installed in `$(go env GOPATH)/bin`. If you did not already add the bin directory to your system path during Go installation, you are encouraged to do so now. @@ -53,10 +51,8 @@ $ go install . ./cmd/... Kaspad has several configuration options available to tweak how it runs, but all of the basic operations work with zero configuration. -#### Linux/BSD/POSIX/Source - ```bash -$ ./kaspad +$ kaspad ``` ## Discord @@ -74,4 +70,3 @@ The documentation is a work-in-progress. It is located in the [docs](https://git ## License Kaspad is licensed under the copyfree [ISC License](https://choosealicense.com/licenses/isc/). - diff --git a/cmd/kaspactl/README.md b/cmd/kaspactl/README.md new file mode 100644 index 000000000..e747c30c7 --- /dev/null +++ b/cmd/kaspactl/README.md @@ -0,0 +1,53 @@ +# kaspactl + +kaspactl is an RPC client for kaspad + +## Requirements + +Go 1.14 or later. + +## Installation + +#### Build from Source + +- Install Go according to the installation instructions here: + http://golang.org/doc/install + +- Ensure Go was installed properly and is a supported version: + +```bash +$ go version +``` + +- Run the following commands to obtain and install kaspad including all dependencies: + +```bash +$ git clone https://github.com/kaspanet/kaspad +$ cd kaspad/cmd/kaspactl +$ go install . +``` + +- Kaspactl should now be installed in `$(go env GOPATH)/bin`. If you did not already add the bin directory to your + system path during Go installation, you are encouraged to do so now. + +## Usage + +The full kaspctl configuration options can be seen with: + +```bash +$ kaspctl --help +``` + +But the minimum configuration needed to run it is: + +```bash +$ kaspactl +``` + +For example: + +``` +$ kaspactl '{"getBlockDagInfoRequest":{}}' +``` + +For a list of all available requests check out the [RPC documentation](infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md) \ No newline at end of file diff --git a/cmd/kaspaminer/README.md b/cmd/kaspaminer/README.md new file mode 100644 index 000000000..53e2041d4 --- /dev/null +++ b/cmd/kaspaminer/README.md @@ -0,0 +1,45 @@ +# kaspaminer + +Kaspaminer is a CPU-based miner for kaspad + +## Requirements + +Go 1.14 or later. + +## Installation + +#### Build from Source + +- Install Go according to the installation instructions here: + http://golang.org/doc/install + +- Ensure Go was installed properly and is a supported version: + +```bash +$ go version +``` + +- Run the following commands to obtain and install kaspad including all dependencies: + +```bash +$ git clone https://github.com/kaspanet/kaspad +$ cd kaspad/cmd/kaspaminer +$ go install . +``` + +- Kapaminer should now be installed in `$(go env GOPATH)/bin`. If you did + not already add the bin directory to your system path during Go installation, + you are encouraged to do so now. + +## Usage + +The full kaspaminer configuration options can be seen with: + +```bash +$ kaspaminer --help +``` + +But the minimum configuration needed to run it is: +```bash +$ kaspaminer --miningaddr= +``` \ No newline at end of file diff --git a/cmd/wallet/README.md b/cmd/wallet/README.md index 46fb1d98e..c71fe930c 100644 --- a/cmd/wallet/README.md +++ b/cmd/wallet/README.md @@ -8,6 +8,35 @@ WALLET `wallet` is a simple, no-frills wallet software operated via the command line.\ It is capable of generating wallet key-pairs, printing a wallet's current balance, and sending simple transactions. +## Requirements + +Go 1.14 or later. + +## Installation + +#### Build from Source + +- Install Go according to the installation instructions here: + http://golang.org/doc/install + +- Ensure Go was installed properly and is a supported version: + +```bash +$ go version +``` + +- Run the following commands to obtain and install kaspad including all dependencies: + +```bash +$ git clone https://github.com/kaspanet/kaspad +$ cd kaspad/cmd/wallet +$ go install . +``` + +- Wallet should now be installed in `$(go env GOPATH)/bin`. If you did + not already add the bin directory to your system path during Go installation, + you are encouraged to do so now. + Usage ----- From 49e0a2a2e7d39181bf6a4bd15492b9758a429207 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 10 Jan 2021 10:25:15 +0200 Subject: [PATCH 227/351] Add basic support for archival node (#1370) * Add archival cli flag * If --archival was activated - don't delete anything * Fix tests * Still change block status to StatusHeaderOnly even in archival nodes --- app/component_manager.go | 5 +++-- domain/consensus/consensus_test.go | 2 +- domain/consensus/factory.go | 20 +++++++++++-------- domain/consensus/factory_test.go | 7 ++++--- domain/consensus/finality_test.go | 6 +++--- .../validateandinsertblock_test.go | 5 +++-- .../block_body_in_isolation_test.go | 7 ++++--- .../block_header_in_context_test.go | 7 ++++--- .../calculate_past_utxo_test.go | 4 ++-- ...find_selected_parent_chain_changes_test.go | 5 +++-- .../resolve_block_status_test.go | 9 +++++---- .../virtual_parents_test.go | 7 ++++--- .../dagtopologymanager_external_test.go | 2 +- .../dagtraversalmanager/window_test.go | 2 +- .../difficultymanager_test.go | 2 +- .../pastmediantimemanager_test.go | 2 +- .../processes/pruningmanager/pruning_test.go | 2 +- .../pruningmanager/pruningmanager.go | 9 ++++++++- .../reachability_external_test.go | 9 +++++---- .../transaction_in_isolation_test.go | 5 +++-- domain/domain.go | 4 ++-- infrastructure/config/config.go | 1 + 22 files changed, 72 insertions(+), 50 deletions(-) diff --git a/app/component_manager.go b/app/component_manager.go index f3efe34e9..e2f20beae 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -2,9 +2,10 @@ package app import ( "fmt" - "github.com/kaspanet/kaspad/domain/utxoindex" "sync/atomic" + "github.com/kaspanet/kaspad/domain/utxoindex" + infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/kaspanet/kaspad/domain" @@ -79,7 +80,7 @@ func (a *ComponentManager) Stop() { func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, interrupt chan<- struct{}) ( *ComponentManager, error) { - domain, err := domain.New(cfg.ActiveNetParams, db) + domain, err := domain.New(cfg.ActiveNetParams, db, cfg.IsArchivalNode) if err != nil { return nil, err } diff --git a/domain/consensus/consensus_test.go b/domain/consensus/consensus_test.go index cc38ca06e..9b423c455 100644 --- a/domain/consensus/consensus_test.go +++ b/domain/consensus/consensus_test.go @@ -14,7 +14,7 @@ import ( func TestConsensus_GetBlockInfo(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, "TestConsensus_GetBlockInfo") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestConsensus_GetBlockInfo") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 807455522..cf9da3f95 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -46,10 +46,11 @@ import ( // Factory instantiates new Consensuses type Factory interface { - NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) - NewTestConsensus(dagParams *dagconfig.Params, testName string) ( + NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) ( + externalapi.Consensus, error) + NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode bool, testName string) ( tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) - NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) ( + NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string, isArchivalNode bool) ( tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) } @@ -61,7 +62,9 @@ func NewFactory() Factory { } // NewConsensus instantiates a new Consensus -func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) { +func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) ( + externalapi.Consensus, error) { + dbManager := consensusdatabase.New(db) pruningWindowSizeForCaches := int(dagParams.PruningDepth()) @@ -236,6 +239,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockStore, blockHeaderStore, utxoDiffStore, + isArchivalNode, genesisHash, dagParams.FinalityDepth(), dagParams.PruningDepth()) @@ -348,7 +352,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat return c, nil } -func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) ( +func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode bool, testName string) ( tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) { dataDir, err := ioutil.TempDir("", testName) @@ -356,17 +360,17 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) return nil, nil, err } - return f.NewTestConsensusWithDataDir(dagParams, dataDir) + return f.NewTestConsensusWithDataDir(dagParams, dataDir, isArchivalNode) } -func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) ( +func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string, isArchivalNode bool) ( tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) { db, err := ldb.NewLevelDB(dataDir) if err != nil { return nil, nil, err } - consensusAsInterface, err := f.NewConsensus(dagParams, db) + consensusAsInterface, err := f.NewConsensus(dagParams, db, isArchivalNode) if err != nil { return nil, nil, err } diff --git a/domain/consensus/factory_test.go b/domain/consensus/factory_test.go index 9db43b9a9..e352e15ee 100644 --- a/domain/consensus/factory_test.go +++ b/domain/consensus/factory_test.go @@ -1,10 +1,11 @@ package consensus import ( - "github.com/kaspanet/kaspad/domain/dagconfig" - "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" "io/ioutil" "testing" + + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" ) func TestNewConsensus(t *testing.T) { @@ -22,7 +23,7 @@ func TestNewConsensus(t *testing.T) { t.Fatalf("error in NewLevelDB: %s", err) } - _, err = f.NewConsensus(dagParams, db) + _, err = f.NewConsensus(dagParams, db, false) if err != nil { t.Fatalf("error in NewConsensus: %+v", err) } diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index e267c5380..ff1547e59 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -20,7 +20,7 @@ func TestFinality(t *testing.T) { params.FinalityDuration = 50 * params.TargetTimePerBlock factory := NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, "TestFinality") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestFinality") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -232,12 +232,12 @@ func TestBoundedMergeDepth(t *testing.T) { } factory := NewFactory() - consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, "BoundedMergeTestBuild") + consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, false, "BoundedMergeTestBuild") if err != nil { t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) } - consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, "BoundedMergeTestReal") + consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, false, "BoundedMergeTestReal") if err != nil { t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go index 8f59baffe..6cfc26ea4 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go @@ -1,6 +1,8 @@ package blockprocessor_test import ( + "testing" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -9,13 +11,12 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" - "testing" ) func TestBlockStatus(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestBlockStatus") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestBlockStatus") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 53f47191f..5906b8f30 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -1,10 +1,11 @@ package blockvalidator_test import ( - "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "math" "testing" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -21,7 +22,7 @@ func TestChainedTransactions(t *testing.T) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestChainedTransactions") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestChainedTransactions") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -83,7 +84,7 @@ func TestChainedTransactions(t *testing.T) { func TestCheckBlockSanity(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, "TestCheckBlockSanity") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockSanity") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index 4791e7e11..5e2f77c46 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -2,9 +2,10 @@ package blockvalidator_test import ( "errors" - "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "testing" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -17,7 +18,7 @@ import ( func TestValidateMedianTime(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestValidateMedianTime") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateMedianTime") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -86,7 +87,7 @@ func TestValidateMedianTime(t *testing.T) { func TestCheckParentsIncest(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestCheckParentsIncest") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentsIncest") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index db0b64817..ad94de971 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -19,7 +19,7 @@ func TestUTXOCommitment(t *testing.T) { params.BlockCoinbaseMaturity = 0 factory := consensus.NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestUTXOCommitment") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -115,7 +115,7 @@ func TestPastUTXOMultiset(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestUTXOCommitment") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go index c90ef0680..cbeb6ea87 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go @@ -1,18 +1,19 @@ package consensusstatemanager_test import ( + "testing" + "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") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestCalculateSelectedParentChainChanges") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go index 119b931bf..f1b289f24 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status_test.go @@ -2,10 +2,11 @@ package consensusstatemanager_test import ( "errors" + "testing" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" - "testing" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -24,7 +25,7 @@ func TestDoubleSpends(t *testing.T) { factory := consensus.NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, "TestUTXOCommitment") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestUTXOCommitment") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -161,7 +162,7 @@ func TestTransactionAcceptance(t *testing.T) { params.BlockCoinbaseMaturity = 0 factory := consensus.NewFactory() - testConsensus, teardown, err := factory.NewTestConsensus(params, "TestTransactionAcceptance") + testConsensus, teardown, err := factory.NewTestConsensus(params, false, "TestTransactionAcceptance") if err != nil { t.Fatalf("Error setting up testConsensus: %+v", err) } @@ -381,7 +382,7 @@ func TestTransactionAcceptance(t *testing.T) { func TestResolveBlockStatusSanity(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - consensus, teardown, err := consensus.NewFactory().NewTestConsensus(params, "TestResolveBlockStatusSanity") + consensus, teardown, err := consensus.NewFactory().NewTestConsensus(params, false, "TestResolveBlockStatusSanity") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go index 56a95b2ca..dfaa9c990 100644 --- a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go +++ b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go @@ -1,6 +1,9 @@ package consensusstatemanager_test import ( + "sort" + "testing" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -8,13 +11,11 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" - "sort" - "testing" ) func TestConsensusStateManager_pickVirtualParents(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { - tc, teardown, err := consensus.NewFactory().NewTestConsensus(params, "TestConsensusStateManager_pickVirtualParents") + tc, teardown, err := consensus.NewFactory().NewTestConsensus(params, false, "TestConsensusStateManager_pickVirtualParents") if err != nil { t.Fatalf("Error setting up tc: %+v", err) } diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go index ab0e713d4..d2bab7172 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager_external_test.go @@ -12,7 +12,7 @@ import ( func TestIsAncestorOf(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestIsAncestorOf") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestIsAncestorOf") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index cabcfde43..0d0016aee 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -311,7 +311,7 @@ func TestBlueBlockWindow(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { params.K = 1 factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestBlueBlockWindow") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestBlueBlockWindow") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index 46e9b8cfd..77a3be908 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -33,7 +33,7 @@ func TestDifficulty(t *testing.T) { params.DifficultyAdjustmentWindowSize = 264 factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestDifficulty") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestDifficulty") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go index c7769750f..7227e2270 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager_test.go @@ -13,7 +13,7 @@ import ( func TestPastMedianTime(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index fd25d69c0..99770c47a 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -67,7 +67,7 @@ func TestPruning(t *testing.T) { params.MergeSetSizeLimit = test.MergeSetSizeLimit factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestPruning") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestPruning") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 7fb43d826..1149bcfa3 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -28,6 +28,7 @@ type pruningManager struct { blockHeaderStore model.BlockHeaderStore utxoDiffStore model.UTXODiffStore + isArchivalNode bool genesisHash *externalapi.DomainHash finalityInterval uint64 pruningDepth uint64 @@ -52,6 +53,7 @@ func New( blockHeaderStore model.BlockHeaderStore, utxoDiffStore model.UTXODiffStore, + isArchivalNode bool, genesisHash *externalapi.DomainHash, finalityInterval uint64, pruningDepth uint64, @@ -72,6 +74,7 @@ func New( blockHeaderStore: blockHeaderStore, utxoDiffStore: utxoDiffStore, headerSelectedTipStore: headerSelectedTipStore, + isArchivalNode: isArchivalNode, genesisHash: genesisHash, pruningDepth: pruningDepth, finalityInterval: finalityInterval, @@ -328,12 +331,16 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread return true, nil } + pm.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) + if pm.isArchivalNode { + return false, nil + } + pm.multiSetStore.Delete(blockHash) pm.acceptanceDataStore.Delete(blockHash) pm.blocksStore.Delete(blockHash) pm.utxoDiffStore.Delete(blockHash) - pm.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly) return false, nil } diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index f35b85a15..ad8519179 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -13,7 +13,8 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot") + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot") if err != nil { t.Fatalf("NewTestConsensus: %+v", err) } @@ -68,7 +69,7 @@ func TestUpdateReindexRoot(t *testing.T) { reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } @@ -158,7 +159,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot") if err != nil { t.Fatalf("NewTestConsensus: %+v", err) } @@ -292,7 +293,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) { reachabilityReindexWindow := uint64(10) testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } diff --git a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go index f0fcb2afb..946f2ae6c 100644 --- a/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go +++ b/domain/consensus/processes/transactionvalidator/transaction_in_isolation_test.go @@ -1,9 +1,10 @@ package transactionvalidator_test import ( - "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "testing" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -25,7 +26,7 @@ type txSubnetworkData struct { func TestValidateTransactionInIsolation(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, "TestValidateTransactionInIsolation") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateTransactionInIsolation") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/domain.go b/domain/domain.go index 844a96fee..84a50b98c 100644 --- a/domain/domain.go +++ b/domain/domain.go @@ -28,9 +28,9 @@ func (d domain) MiningManager() miningmanager.MiningManager { } // New instantiates a new instance of a Domain object -func New(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (Domain, error) { +func New(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) (Domain, error) { consensusFactory := consensus.NewFactory() - consensusInstance, err := consensusFactory.NewConsensus(dagParams, db) + consensusInstance, err := consensusFactory.NewConsensus(dagParams, db, isArchivalNode) if err != nil { return nil, err } diff --git a/infrastructure/config/config.go b/infrastructure/config/config.go index fe2dae758..243c76ae2 100644 --- a/infrastructure/config/config.go +++ b/infrastructure/config/config.go @@ -121,6 +121,7 @@ type Flags struct { ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."` MaxUTXOCacheSize uint64 `long:"maxutxocachesize" description:"Max size of loaded UTXO into ram from the disk in bytes"` UTXOIndex bool `long:"utxoindex" description:"Enable the UTXO index"` + IsArchivalNode bool `long:"archival" description:"Run as an archival node: don't delete old block data when moving the pruning point (Warning: heavy disk usage)'"` NetworkFlags ServiceOptions *ServiceOptions } From c6d20c1f6f7c1bd38260ead1177b332ebc1a6caa Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 10 Jan 2021 11:06:06 +0200 Subject: [PATCH 228/351] Start IBDBlockLocator from PruningPoint instead of Genesis (#1383) --- app/protocol/flows/blockrelay/ibd.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 5cf96cefc..d83877d9e 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -120,7 +120,10 @@ func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) e } func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - lowHash := flow.Config().ActiveNetParams.GenesisHash + lowHash, err := flow.Domain().Consensus().PruningPoint() + if err != nil { + return nil, err + } highHash, err := flow.Domain().Consensus().GetHeadersSelectedTip() if err != nil { return nil, err From 09e1a73340563a8ddfbec79e1a53a059810d3e52 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 10 Jan 2021 12:05:34 +0200 Subject: [PATCH 229/351] Added some logs to block-relay and IBD flows (#1384) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/protocol/flows/blockrelay/handle_ibd_block_requests.go | 4 +++- .../flows/blockrelay/handle_ibd_root_hash_requests.go | 2 ++ .../flows/blockrelay/handle_relay_block_requests.go | 2 ++ .../flows/blockrelay/handle_request_block_locator.go | 2 ++ app/protocol/flows/blockrelay/handle_request_headers.go | 3 ++- .../handle_request_ibd_root_utxo_set_and_block.go | 6 ++++++ 6 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_ibd_block_requests.go b/app/protocol/flows/blockrelay/handle_ibd_block_requests.go index e70e49eee..e6593dc7c 100644 --- a/app/protocol/flows/blockrelay/handle_ibd_block_requests.go +++ b/app/protocol/flows/blockrelay/handle_ibd_block_requests.go @@ -25,7 +25,8 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute return err } msgRequestIBDBlocks := message.(*appmessage.MsgRequestIBDBlocks) - for _, hash := range msgRequestIBDBlocks.Hashes { + log.Debugf("Got request for %d ibd blocks", len(msgRequestIBDBlocks.Hashes)) + for i, hash := range msgRequestIBDBlocks.Hashes { // Fetch the block from the database. blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash) if err != nil { @@ -47,6 +48,7 @@ func HandleIBDBlockRequests(context HandleIBDBlockRequestsContext, incomingRoute if err != nil { return err } + log.Debugf("sent %d out of %d", i, len(msgRequestIBDBlocks.Hashes)) } } } diff --git a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go index 3d8948233..1250560f7 100644 --- a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go +++ b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go @@ -35,6 +35,7 @@ func (flow *handleIBDRootHashRequestsFlow) start() error { if err != nil { return err } + log.Debugf("Got request for IBD root hash") pruningPoint, err := flow.Domain().Consensus().PruningPoint() if err != nil { @@ -45,5 +46,6 @@ func (flow *handleIBDRootHashRequestsFlow) start() error { if err != nil { return err } + log.Debugf("Sent IBD root hash %s", pruningPoint) } } diff --git a/app/protocol/flows/blockrelay/handle_relay_block_requests.go b/app/protocol/flows/blockrelay/handle_relay_block_requests.go index d64cf47cc..db4e54558 100644 --- a/app/protocol/flows/blockrelay/handle_relay_block_requests.go +++ b/app/protocol/flows/blockrelay/handle_relay_block_requests.go @@ -26,6 +26,7 @@ func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute * return err } getRelayBlocksMessage := message.(*appmessage.MsgRequestRelayBlocks) + log.Debugf("Got request for relay blocks with hashes %s", getRelayBlocksMessage.Hashes) for _, hash := range getRelayBlocksMessage.Hashes { // Fetch the block from the database. blockInfo, err := context.Domain().Consensus().GetBlockInfo(hash) @@ -46,6 +47,7 @@ func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute * if err != nil { return err } + log.Debugf("Relayed block with hash %s", hash) } } } diff --git a/app/protocol/flows/blockrelay/handle_request_block_locator.go b/app/protocol/flows/blockrelay/handle_request_block_locator.go index 9fe8970aa..a465bf9cb 100644 --- a/app/protocol/flows/blockrelay/handle_request_block_locator.go +++ b/app/protocol/flows/blockrelay/handle_request_block_locator.go @@ -36,6 +36,8 @@ func (flow *handleRequestBlockLocatorFlow) start() error { if err != nil { return err } + log.Debugf("Received getBlockLocator with lowHash: %s, highHash: %s, limit: %d", + lowHash, highHash, limit) locator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash, limit) if err != nil || len(locator) == 0 { diff --git a/app/protocol/flows/blockrelay/handle_request_headers.go b/app/protocol/flows/blockrelay/handle_request_headers.go index 5d8615b29..312f75af4 100644 --- a/app/protocol/flows/blockrelay/handle_request_headers.go +++ b/app/protocol/flows/blockrelay/handle_request_headers.go @@ -42,9 +42,10 @@ func (flow *handleRequestBlocksFlow) start() error { if err != nil { return err } + log.Debugf("Recieved requestHeaders with lowHash: %s, highHash: %s", lowHash, highHash) for !lowHash.Equal(highHash) { - log.Debugf("Getting block hashes between %s and %s to %s", lowHash, highHash, flow.peer) + log.Debugf("Getting block headers between %s and %s to %s", lowHash, highHash, flow.peer) // GetHashesBetween is a relatively heavy operation so we limit it // in order to avoid locking the consensus for too long diff --git a/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go index 659272e85..c031a96df 100644 --- a/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go +++ b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go @@ -2,6 +2,7 @@ package blockrelay import ( "errors" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -39,6 +40,8 @@ func (flow *handleRequestIBDRootUTXOSetAndBlockFlow) start() error { } msgRequestIBDRootUTXOSetAndBlock := message.(*appmessage.MsgRequestIBDRootUTXOSetAndBlock) + log.Debugf("Got request for IBDRoot UTXOSet and Block") + utxoSet, err := flow.Domain().Consensus().GetPruningPointUTXOSet(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) if err != nil { if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) { @@ -50,12 +53,15 @@ func (flow *handleRequestIBDRootUTXOSetAndBlockFlow) start() error { continue } } + log.Debugf("Got utxo set for pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) block, err := flow.Domain().Consensus().GetBlock(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) if err != nil { return err } + log.Debugf("Got pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootUTXOSetAndBlock(utxoSet, appmessage.DomainBlockToMsgBlock(block))) if err != nil { From 0f2d0d45b51ec2b61978641d775b4f2863670873 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 10 Jan 2021 12:44:24 +0200 Subject: [PATCH 230/351] Add TargetBlocksPerSecond for kaspaminer (#1385) Co-authored-by: Svarog --- cmd/kaspaminer/config.go | 13 +++++++------ cmd/kaspaminer/main.go | 2 +- cmd/kaspaminer/mineloop.go | 27 ++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/cmd/kaspaminer/config.go b/cmd/kaspaminer/config.go index 243dbf22e..68423b5ac 100644 --- a/cmd/kaspaminer/config.go +++ b/cmd/kaspaminer/config.go @@ -30,12 +30,13 @@ var ( ) type configFlags struct { - ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` - RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` - MiningAddr string `long:"miningaddr" description:"Address to mine to"` - NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."` - MineWhenNotSynced bool `long:"mine-when-not-synced" description:"Mine even if the node is not synced with the rest of the network."` - Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` + ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` + RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` + MiningAddr string `long:"miningaddr" description:"Address to mine to"` + NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."` + MineWhenNotSynced bool `long:"mine-when-not-synced" description:"Mine even if the node is not synced with the rest of the network."` + Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` + TargetBlocksPerSecond float64 `long:"target-blocks-per-second" description:"Sets a maximum block rate. This flag is for debugging purposes."` config.NetworkFlags } diff --git a/cmd/kaspaminer/main.go b/cmd/kaspaminer/main.go index a4a85fa7a..27729b511 100644 --- a/cmd/kaspaminer/main.go +++ b/cmd/kaspaminer/main.go @@ -48,7 +48,7 @@ func main() { doneChan := make(chan struct{}) spawn("mineLoop", func() { - err = mineLoop(client, cfg.NumberOfBlocks, cfg.MineWhenNotSynced, miningAddr) + err = mineLoop(client, cfg.NumberOfBlocks, cfg.TargetBlocksPerSecond, cfg.MineWhenNotSynced, miningAddr) if err != nil { panic(errors.Wrap(err, "error in mine loop")) } diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 2538769e5..97c0cf0d0 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -24,7 +24,7 @@ var hashesTried uint64 const logHashRateInterval = 10 * time.Second -func mineLoop(client *minerClient, numberOfBlocks uint64, mineWhenNotSynced bool, +func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond float64, mineWhenNotSynced bool, miningAddr util.Address) error { errChan := make(chan error) @@ -33,7 +33,18 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, mineWhenNotSynced bool doneChan := make(chan struct{}) spawn("mineLoop-internalLoop", func() { + const windowSize = 10 + var expectedDurationForWindow time.Duration + var windowExpectedEndTime time.Time + hasBlockRateTarget := targetBlocksPerSecond != 0 + if hasBlockRateTarget { + expectedDurationForWindow = time.Duration(float64(windowSize)/targetBlocksPerSecond) * time.Second + windowExpectedEndTime = time.Now().Add(expectedDurationForWindow) + } + blockInWindowIndex := 0 + for i := uint64(0); numberOfBlocks == 0 || i < numberOfBlocks; i++ { + foundBlock := make(chan *externalapi.DomainBlock) mineNextBlock(client, miningAddr, foundBlock, mineWhenNotSynced, templateStopChan, errChan) block := <-foundBlock @@ -42,6 +53,20 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, mineWhenNotSynced bool if err != nil { errChan <- err } + + if hasBlockRateTarget { + blockInWindowIndex++ + if blockInWindowIndex == windowSize-1 { + deviation := windowExpectedEndTime.Sub(time.Now()) + if deviation > 0 { + log.Infof("Finished to mine %d blocks %s earlier than expected. Sleeping %s to compensate", + windowSize, deviation, deviation) + time.Sleep(deviation) + } + blockInWindowIndex = 0 + } + } + } doneChan <- struct{}{} }) From 2cc0bf16392c866d496c71c5ffd746f882f2ac13 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 10 Jan 2021 13:36:02 +0200 Subject: [PATCH 231/351] Optimize block locator using finality store (#1386) * Make sure block locator doesn't include a hash lower than the lowHash in the block locator * Use finalityStore to optimize LowestChainBlockAboveOrEqualToBlueScore --- domain/consensus/factory.go | 4 +++- .../dagtraversalmanager.go | 24 +++++++++++++++++-- .../processes/syncmanager/blocklocator.go | 5 ++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index cf9da3f95..f831a9a90 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -111,7 +111,9 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTopologyManager, ghostdagDataStore, reachabilityDataStore, - ghostdagManager) + ghostdagManager, + finalityStore, + dagParams.FinalityDepth()) pastMedianTimeManager := pastmediantimemanager.New( dagParams.TimestampDeviationTolerance, dbManager, diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index ca1ece855..f054f0beb 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -13,9 +13,11 @@ type dagTraversalManager struct { databaseContext model.DBReader dagTopologyManager model.DAGTopologyManager + ghostdagManager model.GHOSTDAGManager ghostdagDataStore model.GHOSTDAGDataStore reachabilityDataStore model.ReachabilityDataStore - ghostdagManager model.GHOSTDAGManager + finalityStore model.FinalityStore + finalityDepth uint64 } // selectedParentIterator implements the `model.BlockIterator` API @@ -47,13 +49,17 @@ func New( dagTopologyManager model.DAGTopologyManager, ghostdagDataStore model.GHOSTDAGDataStore, reachabilityDataStore model.ReachabilityDataStore, - ghostdagManager model.GHOSTDAGManager) model.DAGTraversalManager { + ghostdagManager model.GHOSTDAGManager, + finalityStore model.FinalityStore, + finalityDepth uint64) model.DAGTraversalManager { return &dagTraversalManager{ databaseContext: databaseContext, dagTopologyManager: dagTopologyManager, ghostdagDataStore: ghostdagDataStore, reachabilityDataStore: reachabilityDataStore, ghostdagManager: ghostdagManager, + finalityStore: finalityStore, + finalityDepth: finalityDepth, } } @@ -110,6 +116,20 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash currentHash := highHash currentBlockGHOSTDAGData := highBlockGHOSTDAGData + + // Use the finality Store to jump `finalityDepth` blue scores down the selected chain. + // this should be much faster than stepping through the whole chain. + for currentBlockGHOSTDAGData.BlueScore()-blueScore >= dtm.finalityDepth { + currentHash, err = dtm.finalityStore.FinalityPoint(dtm.databaseContext, currentHash) + if err != nil { + return nil, err + } + currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) + if err != nil { + return nil, err + } + } + for currentBlockGHOSTDAGData.SelectedParent() != nil { selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent()) if err != nil { diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index 7bcc80e5a..137eaa171 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -25,7 +25,8 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH currentHash := highHash step := uint64(1) locator := make(externalapi.BlockLocator, 0) - for currentHash != nil { + // The loop will break if we reached the limit or if we got to lowHash. + for { locator = append(locator, currentHash) // Stop if we've reached the limit (if it's set) @@ -55,7 +56,7 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH // Calculate blueScore of previous node to include ensuring the // final node is lowNode. nextBlueScore := currentBlockBlueScore - step - if currentBlockBlueScore < step { + if currentBlockBlueScore < step || nextBlueScore < lowBlockGHOSTDAGData.BlueScore() { nextBlueScore = lowBlockGHOSTDAGData.BlueScore() } From 434cf4511296e88b05c46cf03355a278fc1ec64b Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Mon, 11 Jan 2021 13:15:26 +0200 Subject: [PATCH 232/351] Adds a new test to validate POW, and Fix Main-net and Test-net genesis block data. (#1389) * commit for do fetch&merge * Adds a new test to validate POW, and Fix Main-net and Testnet genesis block data. * Fix window's test for testnet and change the expected pruning point for mainnet and testnet. * Delete function "solveBlock" on proof_of_work_test.go and call the function mining.SolvaBlock instead. Also, remove using of random in "solveBlockWithWrongPOW" function. * Replace 0xFFFFFFFFFFFFFFFF to math.MaxUint64 in "solveBlockWithWrongPOW" function and change the function's comment of "TestPOW" * Replace 0xFFFFFFFFFFFFFFFF to math.MaxUint64 in "solveBlockWithWrongPOW" function and change the function's comment of "TestPOW" * Change from <= to < in the for statement in "solveBlockWithWrongPOW" function * Adds one arg to the function call "NewTestConsensus" (the function sig has changed). Co-authored-by: tal Co-authored-by: Ori Newman --- .../blockvalidator/proof_of_work_test.go | 70 +++++++++++++++++++ .../dagtraversalmanager/window_test.go | 14 ++-- .../processes/pruningmanager/pruning_test.go | 4 +- domain/dagconfig/genesis.go | 24 +++---- 4 files changed, 91 insertions(+), 21 deletions(-) create mode 100644 domain/consensus/processes/blockvalidator/proof_of_work_test.go diff --git a/domain/consensus/processes/blockvalidator/proof_of_work_test.go b/domain/consensus/processes/blockvalidator/proof_of_work_test.go new file mode 100644 index 000000000..451e5e06b --- /dev/null +++ b/domain/consensus/processes/blockvalidator/proof_of_work_test.go @@ -0,0 +1,70 @@ +package blockvalidator_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/mining" + "github.com/kaspanet/kaspad/util" + "math" + "math/rand" + + "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" + "github.com/pkg/errors" +) + +// TestPOW tests the validation of the block's POW. +func TestPOW(t *testing.T) { + // We set the flag "skip pow" to be false (second argument in the function) for not skipping the check of POW and validate its correctness. + testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestPOW") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + // Builds and checks block with invalid POW. + invalidBlockWrongPOW, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + invalidBlockWrongPOW = solveBlockWithWrongPOW(invalidBlockWrongPOW) + _, err = tc.ValidateAndInsertBlock(invalidBlockWrongPOW) + if !errors.Is(err, ruleerrors.ErrInvalidPoW) { + t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrInvalidPoW, err) + } + + // test on a valid block. + validBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + random := rand.New(rand.NewSource(0)) + mining.SolveBlock(validBlock, random) + _, err = tc.ValidateAndInsertBlock(validBlock) + if err != nil { + t.Fatal(err) + } + }) +} + +// solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!). +func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock { + targetDifficulty := util.CompactToBig(block.Header.Bits()) + headerForMining := block.Header.ToMutable() + initialNonce := uint64(0) + for i := initialNonce; i < math.MaxUint64; i++ { + headerForMining.SetNonce(i) + if !pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { + block.Header = headerForMining.ToImmutable() + return block + } + } + + panic("Failed to solve block! cannot find a invalid POW for the test") +} diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 0d0016aee..e62c52e61 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -130,37 +130,37 @@ func TestBlueBlockWindow(t *testing.T) { { parents: []string{"H", "F"}, id: "I", - expectedWindowWithGenesisPadding: []string{"F", "C", "H", "D", "G", "B", "A", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"F", "H", "C", "D", "B", "G", "A", "A", "A", "A"}, }, { parents: []string{"I"}, id: "J", - expectedWindowWithGenesisPadding: []string{"I", "F", "C", "H", "D", "G", "B", "A", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"I", "F", "H", "C", "D", "B", "G", "A", "A", "A"}, }, { parents: []string{"J"}, id: "K", - expectedWindowWithGenesisPadding: []string{"J", "I", "F", "C", "H", "D", "G", "B", "A", "A"}, + expectedWindowWithGenesisPadding: []string{"J", "I", "F", "H", "C", "D", "B", "G", "A", "A"}, }, { parents: []string{"K"}, id: "L", - expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "C", "H", "D", "G", "B", "A"}, + expectedWindowWithGenesisPadding: []string{"K", "J", "I", "F", "H", "C", "D", "B", "G", "A"}, }, { parents: []string{"L"}, id: "M", - expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "C", "H", "D", "G", "B"}, + expectedWindowWithGenesisPadding: []string{"L", "K", "J", "I", "F", "H", "C", "D", "B", "G"}, }, { parents: []string{"M"}, id: "N", - expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "C", "H", "D", "G"}, + expectedWindowWithGenesisPadding: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "B"}, }, { parents: []string{"N"}, id: "O", - expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "H", "D"}, + expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"}, }, }, "kaspa-devnet": { diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index 99770c47a..94071618a 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -33,10 +33,10 @@ func TestPruning(t *testing.T) { "kaspa-testnet": "1582", }, "dag-for-test-pruning.json": { - "kaspa-mainnet": "502", + "kaspa-mainnet": "503", "kaspa-simnet": "502", "kaspa-devnet": "503", - "kaspa-testnet": "502", + "kaspa-testnet": "503", }, } diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index b27189c00..d91ad274c 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -30,10 +30,10 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externa // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xbf, 0x07, 0x16, 0x75, 0x1e, 0x62, 0x3b, 0xbe, - 0x18, 0xab, 0x1e, 0x79, 0x09, 0xe6, 0x48, 0x5c, - 0x1b, 0xaf, 0x03, 0x08, 0x25, 0x3c, 0xb9, 0xf5, - 0x22, 0xd2, 0x9d, 0xa6, 0x4d, 0xd1, 0x01, 0xc0, + 0x92, 0x29, 0x3c, 0xbd, 0x65, 0xa8, 0x6d, 0x9c, + 0xc1, 0xb2, 0x8f, 0x63, 0xc9, 0x2a, 0x50, 0x90, + 0x28, 0xe7, 0x45, 0x57, 0x1d, 0xdc, 0xc2, 0xcd, + 0xdd, 0x9b, 0x99, 0x4c, 0x22, 0xc6, 0x21, 0x89, }) // genesisMerkleRoot is the hash of the first transaction in the genesis block @@ -54,9 +54,9 @@ var genesisBlock = externalapi.DomainBlock{ genesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x176c86a5bac, + 0x176eb9ddaf4, 0x207fffff, - 0x3, + 0x0, ), Transactions: []*externalapi.DomainTransaction{genesisCoinbaseTx}, } @@ -182,10 +182,10 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0x5a, 0x22, 0xf5, 0x2e, 0x87, 0x5b, 0xc2, 0xf2, - 0x9d, 0xbb, 0xa7, 0xc1, 0xf6, 0x0a, 0x81, 0xde, - 0xfa, 0x1e, 0xbc, 0x87, 0x8a, 0x37, 0x20, 0xac, - 0xc6, 0x6d, 0x1f, 0x49, 0x9b, 0x0b, 0xe7, 0xe0, + 0x5d, 0xb7, 0x49, 0xc1, 0x6e, 0xfb, 0x4e, 0x7a, + 0x0c, 0x9f, 0xd1, 0x80, 0x74, 0x91, 0x60, 0xd0, + 0x1b, 0x84, 0xc7, 0x92, 0xa8, 0x5f, 0xcf, 0x9b, + 0x1d, 0x8c, 0x8c, 0x34, 0xa9, 0x41, 0x5f, 0xa5, }) // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -206,9 +206,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{ testnetGenesisMerkleRoot, &externalapi.DomainHash{}, &externalapi.DomainHash{}, - 0x176c86a5c26, + 0x176eb9ddb6d, 0x1e7fffff, - 0x18cbd, + 0x5dba6, ), Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } From c7deda41c671cad45bb1312efe4341710ef0b002 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 11 Jan 2021 15:23:27 +0200 Subject: [PATCH 233/351] Fix deserialization of script version in UTXOSet deserialization (#1395) * Initalize protoUTXOSetIterator with index = -1 * Handle error when failed to deserialize Script version * Add support for (de)serialization of (u)int16 * Log the error when converting it into ErrMalformedUTXO --- .../update_pruning_utxo_set.go | 4 ++-- .../consensus/utils/serialization/common.go | 21 +++++++++++++++++++ domain/consensus/utils/utxo/serialization.go | 5 ++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go index 5ecdb16d3..9b66aad91 100644 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go @@ -161,7 +161,7 @@ func (p *protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxo entry, outpoint, err := utxo.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair) if err != nil { if serialization.IsMalformedError(err) { - return nil, nil, errors.Wrap(ruleerrors.ErrMalformedUTXO, "malformed utxo") + return nil, nil, errors.Wrapf(ruleerrors.ErrMalformedUTXO, "malformed utxo: %s", err) } return nil, nil, err } @@ -170,5 +170,5 @@ func (p *protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxo } func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator { - return &protoUTXOSetIterator{utxoSet: protoUTXOSet} + return &protoUTXOSetIterator{utxoSet: protoUTXOSet, index: -1} } diff --git a/domain/consensus/utils/serialization/common.go b/domain/consensus/utils/serialization/common.go index 91038a0f2..e5116cdb2 100644 --- a/domain/consensus/utils/serialization/common.go +++ b/domain/consensus/utils/serialization/common.go @@ -18,6 +18,12 @@ func WriteElement(w io.Writer, element interface{}) error { // Attempt to write the element based on the concrete type via fast // type assertions first. switch e := element.(type) { + case int16: + err := binaryserializer.PutUint16(w, uint16(e)) + if err != nil { + return err + } + return nil case uint16: err := binaryserializer.PutUint16(w, e) if err != nil { @@ -121,6 +127,21 @@ func ReadElement(r io.Reader, element interface{}) error { // Attempt to read the element based on the concrete type via fast // type assertions first. switch e := element.(type) { + case *int16: + rv, err := binaryserializer.Uint16(r) + if err != nil { + return err + } + *e = int16(rv) + return nil + + case *uint16: + rv, err := binaryserializer.Uint16(r) + if err != nil { + return err + } + *e = rv + return nil case *int32: rv, err := binaryserializer.Uint32(r) if err != nil { diff --git a/domain/consensus/utils/utxo/serialization.go b/domain/consensus/utils/utxo/serialization.go index 0fae67734..ed3fd5935 100644 --- a/domain/consensus/utils/utxo/serialization.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -114,7 +114,10 @@ func deserializeUTXOEntry(r io.Reader) (externalapi.UTXOEntry, error) { } var version uint16 - err = serialization.ReadElement(r, version) + err = serialization.ReadElement(r, &version) + if err != nil { + return nil, err + } var scriptPubKeyLen uint64 err = serialization.ReadElement(r, &scriptPubKeyLen) if err != nil { From b8ca33d91dd9ca4d2b91ab09ae56e750d97a6c74 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 11 Jan 2021 15:51:45 +0200 Subject: [PATCH 234/351] Add selected chain store and optimize block locator with it (#1394) * Add selected chain store and optimize block locator with it * Fix build error * Fix comments * Fix IsStaged * Rename CalculateSelectedParentChainChanges to CalculateChainPath and SelectedParentChainChanges->SelectedChainPath * Use binary.LittleEndian directly to allow compiler optimizations * Remove boolean from HeadersSelectedChainStore interface * Prevent endless loop in block locator --- app/protocol/flows/blockrelay/ibd.go | 9 +- app/rpc/rpccontext/chain_changed.go | 2 +- domain/consensus/consensus.go | 37 +-- .../database/binaryserialization/hash.go | 13 + .../binaryserialization/selected_chain.go | 15 ++ .../headersselectedchainstore.go | 230 ++++++++++++++++++ domain/consensus/factory.go | 38 +-- .../consensus/model/externalapi/consensus.go | 3 +- .../model/externalapi/insertblockresult.go | 6 +- ...atastructures_headersselectedchainstore.go | 13 + ...terface_processes_consensusstatemanager.go | 4 +- ...interface_processes_dagtraversalmanager.go | 2 + .../model/interface_processes_syncmanager.go | 1 + .../consensus/model/testapi/test_consensus.go | 1 + .../blockprocessor/blockprocessor.go | 58 +++-- .../blockprocessor/validateandinsertblock.go | 2 +- .../processes/coinbasemanager/payload.go | 6 +- .../add_block_to_virtual.go | 2 +- .../find_selected_parent_chain_changes.go | 54 +--- ...find_selected_parent_chain_changes_test.go | 4 +- .../consensusstatemanager/update_virtual.go | 7 +- .../dagtraversalmanager.go | 50 ++++ .../headersselectedtipmanager.go | 79 ++++++ .../headersselectedtipmanager_test.go | 77 ++++++ .../headertipsmanager.go | 55 ----- .../processes/syncmanager/blocklocator.go | 43 ++++ .../processes/syncmanager/syncmanager.go | 32 ++- domain/consensus/test_consensus.go | 1 + domain/consensus/test_consensus_getters.go | 4 + .../lrucacheuint64tohash.go | 57 +++++ domain/utxoindex/utxoindex.go | 2 +- 31 files changed, 713 insertions(+), 194 deletions(-) create mode 100644 domain/consensus/database/binaryserialization/hash.go create mode 100644 domain/consensus/database/binaryserialization/selected_chain.go create mode 100644 domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go create mode 100644 domain/consensus/model/interface_datastructures_headersselectedchainstore.go create mode 100644 domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager.go create mode 100644 domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager_test.go delete mode 100644 domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go create mode 100644 domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index d83877d9e..2eac07659 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -131,7 +131,7 @@ func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *external for !lowHash.Equal(highHash) { log.Debugf("Sending a blockLocator to %s between %s and %s", flow.peer, lowHash, highHash) - blockLocator, err := flow.Domain().Consensus().CreateBlockLocator(lowHash, highHash, 0) + blockLocator, err := flow.Domain().Consensus().CreateHeadersSelectedChainBlockLocator(lowHash, highHash) if err != nil { return nil, err } @@ -169,6 +169,13 @@ func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *external log.Debugf("The index of the highest hash in the original "+ "blockLocator sent to %s is %d", flow.peer, highestHashIndex) + // If the block locator contains only two adjacent chain blocks, the + // syncer will always find the same highest chain block, so to avoid + // an endless loop, we explicitly stop the loop in such situation. + if len(blockLocator) == 2 && highestHashIndex == 1 { + return highestHash, nil + } + locatorHashAboveHighestHash := highestHash if highestHashIndex > 0 { locatorHashAboveHighestHash = blockLocator[highestHashIndex-1] diff --git a/app/rpc/rpccontext/chain_changed.go b/app/rpc/rpccontext/chain_changed.go index 2375e3ce8..cd8d6c18a 100644 --- a/app/rpc/rpccontext/chain_changed.go +++ b/app/rpc/rpccontext/chain_changed.go @@ -9,7 +9,7 @@ import ( // ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage converts // VirtualSelectedParentChainChanges to VirtualSelectedParentChainChangedNotificationMessage func (ctx *Context) ConvertVirtualSelectedParentChainChangesToChainChangedNotificationMessage( - selectedParentChainChanges *externalapi.SelectedParentChainChanges) (*appmessage.VirtualSelectedParentChainChangedNotificationMessage, error) { + selectedParentChainChanges *externalapi.SelectedChainPath) (*appmessage.VirtualSelectedParentChainChangedNotificationMessage, error) { removedChainBlockHashes := make([]string, len(selectedParentChainChanges.Removed)) for i, removed := range selectedParentChainChanges.Removed { diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 614d19b97..08a14e10c 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -32,19 +32,20 @@ type consensus struct { 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 - headersSelectedTipStore model.HeaderSelectedTipStore - 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 + headersSelectedChainStore model.HeadersSelectedChainStore } // BuildBlock builds a block over the current state, with the transactions @@ -297,6 +298,14 @@ func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash return s.syncManager.CreateBlockLocator(lowHash, highHash, limit) } +func (s *consensus) CreateHeadersSelectedChainBlockLocator(lowHash, + highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + s.lock.Lock() + defer s.lock.Unlock() + + return s.syncManager.CreateHeadersSelectedChainBlockLocator(lowHash, highHash) +} + func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { s.lock.Lock() defer s.lock.Unlock() @@ -327,7 +336,7 @@ func (s *consensus) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool return s.pruningManager.IsValidPruningPoint(blockHash) } -func (s *consensus) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { +func (s *consensus) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { s.lock.Lock() defer s.lock.Unlock() diff --git a/domain/consensus/database/binaryserialization/hash.go b/domain/consensus/database/binaryserialization/hash.go new file mode 100644 index 000000000..a405eaa4f --- /dev/null +++ b/domain/consensus/database/binaryserialization/hash.go @@ -0,0 +1,13 @@ +package binaryserialization + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// SerializeHash serializes hash to a slice of bytes +func SerializeHash(hash *externalapi.DomainHash) []byte { + return hash.ByteSlice() +} + +// DeserializeHash a slice of bytes to a hash +func DeserializeHash(hashBytes []byte) (*externalapi.DomainHash, error) { + return externalapi.NewDomainHashFromByteSlice(hashBytes) +} diff --git a/domain/consensus/database/binaryserialization/selected_chain.go b/domain/consensus/database/binaryserialization/selected_chain.go new file mode 100644 index 000000000..dbce0f9b3 --- /dev/null +++ b/domain/consensus/database/binaryserialization/selected_chain.go @@ -0,0 +1,15 @@ +package binaryserialization + +import "encoding/binary" + +// SerializeChainBlockIndex serializes chain block index +func SerializeChainBlockIndex(index uint64) []byte { + var keyBytes [8]byte + binary.LittleEndian.PutUint64(keyBytes[:], index) + return keyBytes[:] +} + +// DeserializeChainBlockIndex deserializes chain block index to uint64 +func DeserializeChainBlockIndex(indexBytes []byte) uint64 { + return binary.LittleEndian.Uint64(indexBytes) +} diff --git a/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go b/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go new file mode 100644 index 000000000..34406ec91 --- /dev/null +++ b/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go @@ -0,0 +1,230 @@ +package headersselectedchainstore + +import ( + "encoding/binary" + "github.com/kaspanet/kaspad/domain/consensus/database/binaryserialization" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" + "github.com/kaspanet/kaspad/domain/consensus/utils/lrucacheuint64tohash" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/pkg/errors" +) + +var bucketChainBlockHashByIndex = dbkeys.MakeBucket([]byte("chain-block-hash-by-index")) +var bucketChainBlockIndexByHash = dbkeys.MakeBucket([]byte("chain-block-index-by-hash")) +var highestChainBlockIndexKey = dbkeys.MakeBucket().Key([]byte("highest-chain-block-index")) + +type headersSelectedChainStore struct { + stagingAddedByHash map[externalapi.DomainHash]uint64 + stagingRemovedByHash map[externalapi.DomainHash]struct{} + stagingAddedByIndex map[uint64]*externalapi.DomainHash + stagingRemovedByIndex map[uint64]struct{} + cacheByIndex *lrucacheuint64tohash.LRUCache + cacheByHash *lrucache.LRUCache + cacheHighestChainBlockIndex uint64 +} + +// New instantiates a new HeadersSelectedChainStore +func New(cacheSize int) model.HeadersSelectedChainStore { + return &headersSelectedChainStore{ + stagingAddedByHash: make(map[externalapi.DomainHash]uint64), + stagingRemovedByHash: make(map[externalapi.DomainHash]struct{}), + stagingAddedByIndex: make(map[uint64]*externalapi.DomainHash), + stagingRemovedByIndex: make(map[uint64]struct{}), + cacheByIndex: lrucacheuint64tohash.New(cacheSize), + cacheByHash: lrucache.New(cacheSize), + } +} + +// Stage stages the given chain changes +func (hscs *headersSelectedChainStore) Stage(dbContext model.DBReader, + chainChanges *externalapi.SelectedChainPath) error { + + if hscs.IsStaged() { + return errors.Errorf("can't stage when there's already staged data") + } + + for _, blockHash := range chainChanges.Removed { + index, err := hscs.GetIndexByHash(dbContext, blockHash) + if err != nil { + return err + } + + hscs.stagingRemovedByIndex[index] = struct{}{} + hscs.stagingRemovedByHash[*blockHash] = struct{}{} + } + + currentIndex := uint64(0) + highestChainBlockIndex, exists, err := hscs.highestChainBlockIndex(dbContext) + if err != nil { + return err + } + + if exists { + currentIndex = highestChainBlockIndex - uint64(len(chainChanges.Removed)) + 1 + } + + for _, blockHash := range chainChanges.Added { + hscs.stagingAddedByIndex[currentIndex] = blockHash + hscs.stagingAddedByHash[*blockHash] = currentIndex + currentIndex++ + } + + return nil +} + +func (hscs *headersSelectedChainStore) IsStaged() bool { + return len(hscs.stagingAddedByHash) != 0 || + len(hscs.stagingRemovedByHash) != 0 || + len(hscs.stagingAddedByIndex) != 0 || + len(hscs.stagingAddedByIndex) != 0 +} + +func (hscs *headersSelectedChainStore) Discard() { + hscs.stagingAddedByHash = make(map[externalapi.DomainHash]uint64) + hscs.stagingRemovedByHash = make(map[externalapi.DomainHash]struct{}) + hscs.stagingAddedByIndex = make(map[uint64]*externalapi.DomainHash) + hscs.stagingRemovedByIndex = make(map[uint64]struct{}) +} + +func (hscs *headersSelectedChainStore) Commit(dbTx model.DBTransaction) error { + if !hscs.IsStaged() { + return nil + } + + for hash := range hscs.stagingRemovedByHash { + hashCopy := hash + err := dbTx.Delete(hscs.hashAsKey(&hashCopy)) + if err != nil { + return err + } + hscs.cacheByHash.Remove(&hashCopy) + } + + for index := range hscs.stagingRemovedByIndex { + err := dbTx.Delete(hscs.indexAsKey(index)) + if err != nil { + return err + } + hscs.cacheByIndex.Remove(index) + } + + highestIndex := uint64(0) + for hash, index := range hscs.stagingAddedByHash { + hashCopy := hash + err := dbTx.Put(hscs.hashAsKey(&hashCopy), hscs.serializeIndex(index)) + if err != nil { + return err + } + + err = dbTx.Put(hscs.indexAsKey(index), binaryserialization.SerializeHash(&hashCopy)) + if err != nil { + return err + } + + hscs.cacheByHash.Add(&hashCopy, index) + hscs.cacheByIndex.Add(index, &hashCopy) + + if index > highestIndex { + highestIndex = index + } + } + + err := dbTx.Put(highestChainBlockIndexKey, hscs.serializeIndex(highestIndex)) + if err != nil { + return err + } + + hscs.cacheHighestChainBlockIndex = highestIndex + + hscs.Discard() + return nil +} + +// Get gets the chain block index for the given blockHash +func (hscs *headersSelectedChainStore) GetIndexByHash(dbContext model.DBReader, blockHash *externalapi.DomainHash) (uint64, error) { + if index, ok := hscs.stagingAddedByHash[*blockHash]; ok { + return index, nil + } + + if _, ok := hscs.stagingRemovedByHash[*blockHash]; ok { + return 0, errors.Wrapf(database.ErrNotFound, "couldn't find block %s", blockHash) + } + + if index, ok := hscs.cacheByHash.Get(blockHash); ok { + return index.(uint64), nil + } + + indexBytes, err := dbContext.Get(hscs.hashAsKey(blockHash)) + if err != nil { + return 0, err + } + + index := hscs.deserializeIndex(indexBytes) + hscs.cacheByHash.Add(blockHash, index) + return index, nil +} + +func (hscs *headersSelectedChainStore) GetHashByIndex(dbContext model.DBReader, index uint64) (*externalapi.DomainHash, error) { + if blockHash, ok := hscs.stagingAddedByIndex[index]; ok { + return blockHash, nil + } + + if _, ok := hscs.stagingRemovedByIndex[index]; ok { + return nil, errors.Wrapf(database.ErrNotFound, "couldn't find chain block with index %d", index) + } + + if blockHash, ok := hscs.cacheByIndex.Get(index); ok { + return blockHash, nil + } + + hashBytes, err := dbContext.Get(hscs.indexAsKey(index)) + if err != nil { + return nil, err + } + + blockHash, err := binaryserialization.DeserializeHash(hashBytes) + if err != nil { + return nil, err + } + hscs.cacheByIndex.Add(index, blockHash) + return blockHash, nil +} + +func (hscs *headersSelectedChainStore) serializeIndex(index uint64) []byte { + return binaryserialization.SerializeChainBlockIndex(index) +} + +func (hscs *headersSelectedChainStore) deserializeIndex(indexBytes []byte) uint64 { + return binaryserialization.DeserializeChainBlockIndex(indexBytes) +} + +func (hscs *headersSelectedChainStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { + return bucketChainBlockIndexByHash.Key(hash.ByteSlice()) +} + +func (hscs *headersSelectedChainStore) indexAsKey(index uint64) model.DBKey { + var keyBytes [8]byte + binary.BigEndian.PutUint64(keyBytes[:], index) + return bucketChainBlockHashByIndex.Key(keyBytes[:]) +} + +func (hscs *headersSelectedChainStore) highestChainBlockIndex(dbContext model.DBReader) (uint64, bool, error) { + if hscs.cacheHighestChainBlockIndex != 0 { + return hscs.cacheHighestChainBlockIndex, true, nil + } + + indexBytes, err := dbContext.Get(highestChainBlockIndexKey) + if err != nil { + if errors.Is(err, database.ErrNotFound) { + return 0, false, nil + } + return 0, false, err + } + + index := hscs.deserializeIndex(indexBytes) + hscs.cacheHighestChainBlockIndex = index + return index, true, nil +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index f831a9a90..20608919f 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,6 +1,7 @@ package consensus import ( + "github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedchainstore" "io/ioutil" "os" "sync" @@ -89,6 +90,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat ghostdagDataStore := ghostdagdatastore.New(pruningWindowSizeForCaches) headersSelectedTipStore := headersselectedtipstore.New() finalityStore := finalitystore.New(200) + headersSelectedChainStore := headersselectedchainstore.New(pruningWindowSizeForCaches) // Processes reachabilityManager := reachabilitymanager.New( @@ -148,7 +150,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagParams.CoinbasePayloadScriptPublicKeyMaxLength, ghostdagDataStore, acceptanceDataStore) - headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, ghostdagManager, headersSelectedTipStore) + headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, dagTraversalManager, + ghostdagManager, headersSelectedTipStore, headersSelectedChainStore) genesisHash := dagParams.GenesisHash finalityManager := finalitymanager.New( dbManager, @@ -258,7 +261,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockStatusStore, blockHeaderStore, blockStore, - pruningStore) + pruningStore, + headersSelectedChainStore) blockBuilder := blockbuilder.New( dbManager, @@ -300,7 +304,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat utxoDiffStore, blockHeaderStore, headersSelectedTipStore, - finalityStore) + finalityStore, + headersSelectedChainStore) c := &consensus{ lock: &sync.Mutex{}, @@ -324,19 +329,20 @@ 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, - headersSelectedTipStore: headersSelectedTipStore, - 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, + headersSelectedChainStore: headersSelectedChainStore, } genesisInfo, err := c.GetBlockInfo(genesisHash) diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 8921d9a28..535d99664 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -18,12 +18,13 @@ type Consensus interface { ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error GetVirtualSelectedParent() (*DomainHash, error) CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) + CreateHeadersSelectedChainBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error) GetSyncInfo() (*SyncInfo, error) Tips() ([]*DomainHash, error) GetVirtualInfo() (*VirtualInfo, error) IsValidPruningPoint(blockHash *DomainHash) (bool, error) - GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedParentChainChanges, error) + GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedChainPath, error) IsInSelectedParentChainOf(blockHashA *DomainHash, blockHashB *DomainHash) (bool, error) GetHeadersSelectedTip() (*DomainHash, error) } diff --git a/domain/consensus/model/externalapi/insertblockresult.go b/domain/consensus/model/externalapi/insertblockresult.go index 48379a32d..f90960aad 100644 --- a/domain/consensus/model/externalapi/insertblockresult.go +++ b/domain/consensus/model/externalapi/insertblockresult.go @@ -2,11 +2,11 @@ package externalapi // BlockInsertionResult is auxiliary data returned from ValidateAndInsertBlock type BlockInsertionResult struct { - VirtualSelectedParentChainChanges *SelectedParentChainChanges + VirtualSelectedParentChainChanges *SelectedChainPath } -// SelectedParentChainChanges is the set of changes made to the selected parent chain -type SelectedParentChainChanges struct { +// SelectedChainPath is a path the of the selected chains between two blocks. +type SelectedChainPath struct { Added []*DomainHash Removed []*DomainHash } diff --git a/domain/consensus/model/interface_datastructures_headersselectedchainstore.go b/domain/consensus/model/interface_datastructures_headersselectedchainstore.go new file mode 100644 index 000000000..60c916c84 --- /dev/null +++ b/domain/consensus/model/interface_datastructures_headersselectedchainstore.go @@ -0,0 +1,13 @@ +package model + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// HeadersSelectedChainStore represents a store of the headers selected chain +type HeadersSelectedChainStore interface { + Store + Stage(dbContext DBReader, + chainChanges *externalapi.SelectedChainPath) error + IsStaged() bool + GetIndexByHash(dbContext DBReader, blockHash *externalapi.DomainHash) (uint64, error) + GetHashByIndex(dbContext DBReader, index uint64) (*externalapi.DomainHash, error) +} diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index be966c26d..d9a74b1ee 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -4,10 +4,10 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // ConsensusStateManager manages the node's consensus state type ConsensusStateManager interface { - AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) + AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, externalapi.AcceptanceData, Multiset, error) - GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) + GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) } diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index f020760af..9121ba263 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -13,4 +13,6 @@ type DAGTraversalManager interface { BlueWindow(highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) NewDownHeap() BlockHeap NewUpHeap() BlockHeap + CalculateChainPath( + fromBlockHash, toBlockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) } diff --git a/domain/consensus/model/interface_processes_syncmanager.go b/domain/consensus/model/interface_processes_syncmanager.go index 925497066..5596f98e7 100644 --- a/domain/consensus/model/interface_processes_syncmanager.go +++ b/domain/consensus/model/interface_processes_syncmanager.go @@ -7,6 +7,7 @@ type SyncManager interface { GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) + CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) GetSyncInfo() (*externalapi.SyncInfo, error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index c36a69a36..b1ec12320 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -40,6 +40,7 @@ type TestConsensus interface { PruningStore() model.PruningStore ReachabilityDataStore() model.ReachabilityDataStore UTXODiffStore() model.UTXODiffStore + HeadersSelectedChainStore() model.HeadersSelectedChainStore BlockBuilder() TestBlockBuilder BlockProcessor() model.BlockProcessor diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index cb007a39a..c21817150 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -24,19 +24,20 @@ type blockProcessor struct { 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 - headersSelectedTipStore model.HeaderSelectedTipStore - 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 + headersSelectedChainStore model.HeadersSelectedChainStore stores []model.Store } @@ -70,6 +71,7 @@ func New( blockHeaderStore model.BlockHeaderStore, headersSelectedTipStore model.HeaderSelectedTipStore, finalityStore model.FinalityStore, + headersSelectedChainStore model.HeadersSelectedChainStore, ) model.BlockProcessor { return &blockProcessor{ @@ -86,20 +88,21 @@ 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, - headersSelectedTipStore: headersSelectedTipStore, - 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, + headersSelectedChainStore: headersSelectedChainStore, stores: []model.Store{ consensusStateStore, @@ -116,6 +119,7 @@ func New( blockHeaderStore, headersSelectedTipStore, finalityStore, + headersSelectedChainStore, }, } } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index b95cf82ef..778966bbf 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -81,7 +81,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, return nil, err } - var selectedParentChainChanges *externalapi.SelectedParentChainChanges + var selectedParentChainChanges *externalapi.SelectedChainPath isHeaderOnlyBlock := isHeaderOnlyBlock(block) if !isHeaderOnlyBlock { // There's no need to update the consensus state manager when diff --git a/domain/consensus/processes/coinbasemanager/payload.go b/domain/consensus/processes/coinbasemanager/payload.go index a5ad83c7d..ee98d371d 100644 --- a/domain/consensus/processes/coinbasemanager/payload.go +++ b/domain/consensus/processes/coinbasemanager/payload.go @@ -9,8 +9,6 @@ import ( "github.com/pkg/errors" ) -var byteOrder = binary.LittleEndian - const uint64Len = 8 const uint16Len = 2 const lengthOfscriptPubKeyLength = 1 @@ -25,7 +23,7 @@ func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseDat } payload := make([]byte, uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptLengthOfScriptPubKey+len(coinbaseData.ExtraData)) - byteOrder.PutUint64(payload[:uint64Len], blueScore) + binary.LittleEndian.PutUint64(payload[:uint64Len], blueScore) if len(coinbaseData.ScriptPublicKey.Script) > math.MaxUint8 { return nil, errors.Errorf("script public key is bigger than %d", math.MaxUint8) } @@ -47,7 +45,7 @@ func (c *coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalap "coinbase payload is less than the minimum length of %d", minLength) } - blueScore = byteOrder.Uint64(coinbaseTx.Payload[:uint64Len]) + blueScore = binary.LittleEndian.Uint64(coinbaseTx.Payload[:uint64Len]) scriptPubKeyVersion := uint16(coinbaseTx.Payload[uint64Len]) scriptPubKeyScriptLength := coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey] diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 4546c1c8f..104c3d101 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -9,7 +9,7 @@ import ( // AddBlock 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) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { +func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { logger.LogAndMeasureExecutionTime(log, "csm.AddBlock") log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash) diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go index d27b92e4c..caaa1abcb 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes.go @@ -6,7 +6,7 @@ import ( ) func (csm *consensusStateManager) GetVirtualSelectedParentChainFromBlock( - blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { + blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { // Calculate chain changes between the given blockHash and the // virtual's selected parent. Note that we explicitly don't @@ -18,55 +18,5 @@ func (csm *consensusStateManager) GetVirtualSelectedParentChainFromBlock( } virtualSelectedParent := virtualGHOSTDAGData.SelectedParent() - return csm.calculateSelectedParentChainChanges(blockHash, virtualSelectedParent) -} - -func (csm *consensusStateManager) calculateSelectedParentChainChanges( - fromBlockHash, toBlockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { - - // Walk down from fromBlockHash until we reach the common selected - // parent chain ancestor of fromBlockHash and toBlockHash. Note - // that this slice will be empty if fromBlockHash is the selected - // parent of toBlockHash - var removed []*externalapi.DomainHash - current := fromBlockHash - for { - isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent, err := csm.dagTopologyManager.IsInSelectedParentChainOf(current, toBlockHash) - 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 toBlockHash to the common ancestor - var added []*externalapi.DomainHash - current = toBlockHash - for !current.Equal(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 + return csm.dagTraversalManager.CalculateChainPath(blockHash, virtualSelectedParent) } diff --git a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go index cbeb6ea87..12313e634 100644 --- a/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go +++ b/domain/consensus/processes/consensusstatemanager/find_selected_parent_chain_changes_test.go @@ -10,10 +10,10 @@ import ( "github.com/kaspanet/kaspad/domain/dagconfig" ) -func TestCalculateSelectedParentChainChanges(t *testing.T) { +func TestCalculateChainPath(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, false, "TestCalculateSelectedParentChainChanges") + consensus, teardown, err := factory.NewTestConsensus(params, false, "TestCalculateChainPath") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index a2752bcfa..503f667c5 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -6,7 +6,7 @@ import ( ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, - tips []*externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) { + tips []*externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { log.Debugf("updateVirtual start for block %s", newBlockHash) defer log.Debugf("updateVirtual end for block %s", newBlockHash) @@ -64,14 +64,15 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain } log.Debugf("Calculating selected parent chain changes") - var selectedParentChainChanges *externalapi.SelectedParentChainChanges + var selectedParentChainChanges *externalapi.SelectedChainPath if !newBlockHash.Equal(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) + selectedParentChainChanges, err = csm.dagTraversalManager. + CalculateChainPath(oldVirtualSelectedParent, newVirtualSelectedParent) if err != nil { return nil, err } diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index f054f0beb..27aaa1145 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -145,3 +145,53 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash return currentHash, nil } + +func (dtm *dagTraversalManager) CalculateChainPath( + fromBlockHash, toBlockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { + + // Walk down from fromBlockHash until we reach the common selected + // parent chain ancestor of fromBlockHash and toBlockHash. Note + // that this slice will be empty if fromBlockHash is the selected + // parent of toBlockHash + var removed []*externalapi.DomainHash + current := fromBlockHash + for { + isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent, err := dtm.dagTopologyManager.IsInSelectedParentChainOf(current, toBlockHash) + if err != nil { + return nil, err + } + if isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent { + break + } + removed = append(removed, current) + + currentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, current) + if err != nil { + return nil, err + } + current = currentGHOSTDAGData.SelectedParent() + } + commonAncestor := current + + // Walk down from the toBlockHash to the common ancestor + var added []*externalapi.DomainHash + current = toBlockHash + for !current.Equal(commonAncestor) { + added = append(added, current) + currentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.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.SelectedChainPath{ + Added: added, + Removed: removed, + }, nil +} diff --git a/domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager.go b/domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager.go new file mode 100644 index 000000000..c62a1646b --- /dev/null +++ b/domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager.go @@ -0,0 +1,79 @@ +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 + dagTraversalManager model.DAGTraversalManager + ghostdagManager model.GHOSTDAGManager + headersSelectedTipStore model.HeaderSelectedTipStore + headersSelectedChainStore model.HeadersSelectedChainStore +} + +// New instantiates a new HeadersSelectedTipManager +func New(databaseContext model.DBReader, + dagTopologyManager model.DAGTopologyManager, + dagTraversalManager model.DAGTraversalManager, + ghostdagManager model.GHOSTDAGManager, + headersSelectedTipStore model.HeaderSelectedTipStore, + headersSelectedChainStore model.HeadersSelectedChainStore) model.HeadersSelectedTipManager { + + return &headerTipsManager{ + databaseContext: databaseContext, + dagTopologyManager: dagTopologyManager, + dagTraversalManager: dagTraversalManager, + ghostdagManager: ghostdagManager, + headersSelectedTipStore: headersSelectedTipStore, + headersSelectedChainStore: headersSelectedChainStore, + } +} + +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) + + err := h.headersSelectedChainStore.Stage(h.databaseContext, &externalapi.SelectedChainPath{ + Added: []*externalapi.DomainHash{hash}, + Removed: nil, + }) + if err != nil { + return err + } + } 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.Equal(headersSelectedTip) { + h.headersSelectedTipStore.Stage(newHeadersSelectedTip) + + chainChanges, err := h.dagTraversalManager.CalculateChainPath(headersSelectedTip, newHeadersSelectedTip) + if err != nil { + return err + } + + err = h.headersSelectedChainStore.Stage(h.databaseContext, chainChanges) + if err != nil { + return err + } + } + } + + return nil +} diff --git a/domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager_test.go b/domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager_test.go new file mode 100644 index 000000000..ce83241f4 --- /dev/null +++ b/domain/consensus/processes/headersselectedtipmanager/headersselectedtipmanager_test.go @@ -0,0 +1,77 @@ +package headersselectedtipmanager_test + +import ( + "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" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/pkg/errors" + "testing" +) + +func TestAddHeaderTip(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestAddHeaderTip") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown(false) + + checkExpectedSelectedChain := func(expectedSelectedChain []*externalapi.DomainHash) { + for i, blockHash := range expectedSelectedChain { + chainBlockHash, err := tc.HeadersSelectedChainStore().GetHashByIndex(tc.DatabaseContext(), uint64(i)) + if err != nil { + t.Fatalf("GetHashByIndex: %+v", err) + } + + if !blockHash.Equal(chainBlockHash) { + t.Fatalf("chain block %d is expected to be %s but got %s", i, blockHash, chainBlockHash) + } + + index, err := tc.HeadersSelectedChainStore().GetIndexByHash(tc.DatabaseContext(), blockHash) + if err != nil { + t.Fatalf("GetIndexByHash: %+v", err) + } + + if uint64(i) != index { + t.Fatalf("chain block %s is expected to be %d but got %d", blockHash, i, index) + } + } + + _, err := tc.HeadersSelectedChainStore().GetHashByIndex(tc.DatabaseContext(), + uint64(len(expectedSelectedChain)+1)) + if !errors.Is(err, database.ErrNotFound) { + t.Fatalf("index %d is not expected to exist, but instead got error: %+v", + uint64(len(expectedSelectedChain)+1), err) + } + } + + expectedSelectedChain := []*externalapi.DomainHash{params.GenesisHash} + tipHash := params.GenesisHash + for i := 0; i < 10; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + expectedSelectedChain = append(expectedSelectedChain, tipHash) + checkExpectedSelectedChain(expectedSelectedChain) + } + + expectedSelectedChain = []*externalapi.DomainHash{params.GenesisHash} + tipHash = params.GenesisHash + for i := 0; i < 11; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + expectedSelectedChain = append(expectedSelectedChain, tipHash) + } + checkExpectedSelectedChain(expectedSelectedChain) + }) +} diff --git a/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go b/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go deleted file mode 100644 index f4bb6f16b..000000000 --- a/domain/consensus/processes/headersselectedtipmanager/headertipsmanager.go +++ /dev/null @@ -1,55 +0,0 @@ -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.Equal(headersSelectedTip) { - h.headersSelectedTipStore.Stage(newHeadersSelectedTip) - } - } - - return nil -} diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index 137eaa171..62ec0427a 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -98,3 +98,46 @@ func (sm *syncManager) findNextBlockLocatorBoundaries(blockLocator externalapi.B } return highestKnownHash, lowestUnknownHash, nil } + +func (sm *syncManager) createHeadersSelectedChainBlockLocator(lowHash, + highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + + if highHash.Equal(sm.genesisBlockHash) && lowHash.Equal(sm.genesisBlockHash) { + return externalapi.BlockLocator{sm.genesisBlockHash}, nil + } + + lowHashIndex, err := sm.headersSelectedChainStore.GetIndexByHash(sm.databaseContext, lowHash) + if err != nil { + return nil, err + } + + highHashIndex, err := sm.headersSelectedChainStore.GetIndexByHash(sm.databaseContext, highHash) + if err != nil { + return nil, err + } + + if highHashIndex < lowHashIndex { + return nil, errors.Errorf("cannot build block locator while highHash is lower than lowHash") + } + + locator := externalapi.BlockLocator{} + currentIndex := highHashIndex + step := uint64(1) + for currentIndex > lowHashIndex { + blockHash, err := sm.headersSelectedChainStore.GetHashByIndex(sm.databaseContext, currentIndex) + if err != nil { + return nil, err + } + + locator = append(locator, blockHash) + if currentIndex < step { + break + } + + currentIndex -= step + step *= 2 + } + + locator = append(locator, lowHash) + return locator, nil +} diff --git a/domain/consensus/processes/syncmanager/syncmanager.go b/domain/consensus/processes/syncmanager/syncmanager.go index a81faa58b..48ea10d65 100644 --- a/domain/consensus/processes/syncmanager/syncmanager.go +++ b/domain/consensus/processes/syncmanager/syncmanager.go @@ -15,11 +15,12 @@ type syncManager struct { ghostdagManager model.GHOSTDAGManager pruningManager model.PruningManager - ghostdagDataStore model.GHOSTDAGDataStore - blockStatusStore model.BlockStatusStore - blockHeaderStore model.BlockHeaderStore - blockStore model.BlockStore - pruningStore model.PruningStore + ghostdagDataStore model.GHOSTDAGDataStore + blockStatusStore model.BlockStatusStore + blockHeaderStore model.BlockHeaderStore + blockStore model.BlockStore + pruningStore model.PruningStore + headersSelectedChainStore model.HeadersSelectedChainStore } // New instantiates a new SyncManager @@ -35,16 +36,18 @@ func New( blockStatusStore model.BlockStatusStore, blockHeaderStore model.BlockHeaderStore, blockStore model.BlockStore, - pruningStore model.PruningStore) model.SyncManager { + pruningStore model.PruningStore, + headersSelectedChainStore model.HeadersSelectedChainStore) model.SyncManager { return &syncManager{ databaseContext: databaseContext, genesisBlockHash: genesisBlockHash, - dagTraversalManager: dagTraversalManager, - dagTopologyManager: dagTopologyManager, - ghostdagManager: ghostdagManager, - pruningManager: pruningManager, + dagTraversalManager: dagTraversalManager, + dagTopologyManager: dagTopologyManager, + ghostdagManager: ghostdagManager, + pruningManager: pruningManager, + headersSelectedChainStore: headersSelectedChainStore, ghostdagDataStore: ghostdagDataStore, blockStatusStore: blockStatusStore, @@ -77,6 +80,15 @@ func (sm *syncManager) CreateBlockLocator(lowHash, highHash *externalapi.DomainH return sm.createBlockLocator(lowHash, highHash, limit) } +func (sm *syncManager) CreateHeadersSelectedChainBlockLocator(lowHash, + highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + + onEnd := logger.LogAndMeasureExecutionTime(log, "CreateHeadersSelectedChainBlockLocator") + defer onEnd() + + return sm.createHeadersSelectedChainBlockLocator(lowHash, highHash) +} + func (sm *syncManager) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { onEnd := logger.LogAndMeasureExecutionTime(log, "FindNextBlockLocatorBoundaries") defer onEnd() diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 31481a7d7..7c18b13e7 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -95,4 +95,5 @@ func (tc *testConsensus) DiscardAllStores() { tc.PruningStore().Discard() tc.ReachabilityDataStore().Discard() tc.UTXODiffStore().Discard() + tc.HeadersSelectedChainStore().Discard() } diff --git a/domain/consensus/test_consensus_getters.go b/domain/consensus/test_consensus_getters.go index 8cb6a5219..8811bbb5c 100644 --- a/domain/consensus/test_consensus_getters.go +++ b/domain/consensus/test_consensus_getters.go @@ -133,3 +133,7 @@ func (tc *testConsensus) FinalityManager() model.FinalityManager { func (tc *testConsensus) FinalityStore() model.FinalityStore { return tc.finalityStore } + +func (tc *testConsensus) HeadersSelectedChainStore() model.HeadersSelectedChainStore { + return tc.headersSelectedChainStore +} diff --git a/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go b/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go new file mode 100644 index 000000000..c2317d5f0 --- /dev/null +++ b/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go @@ -0,0 +1,57 @@ +package lrucacheuint64tohash + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// LRUCache is a least-recently-used cache from +// uint64 to DomainHash +type LRUCache struct { + cache map[uint64]*externalapi.DomainHash + capacity int +} + +// New creates a new LRUCache +func New(capacity int) *LRUCache { + return &LRUCache{ + cache: make(map[uint64]*externalapi.DomainHash, capacity+1), + capacity: capacity, + } +} + +// Add adds an entry to the LRUCache +func (c *LRUCache) Add(key uint64, value *externalapi.DomainHash) { + c.cache[key] = value + + if len(c.cache) > c.capacity { + c.evictRandom() + } +} + +// Get returns the entry for the given key, or (nil, false) otherwise +func (c *LRUCache) Get(key uint64) (*externalapi.DomainHash, bool) { + value, ok := c.cache[key] + if !ok { + return nil, false + } + return value, true +} + +// Has returns whether the LRUCache contains the given key +func (c *LRUCache) Has(key uint64) bool { + _, ok := c.cache[key] + return ok +} + +// Remove removes the entry for the the given key. Does nothing if +// the entry does not exist +func (c *LRUCache) Remove(key uint64) { + delete(c.cache, key) +} + +func (c *LRUCache) evictRandom() { + var keyToEvict uint64 + for key := range c.cache { + keyToEvict = key + break + } + c.Remove(keyToEvict) +} diff --git a/domain/utxoindex/utxoindex.go b/domain/utxoindex/utxoindex.go index 1d881f882..24b14352c 100644 --- a/domain/utxoindex/utxoindex.go +++ b/domain/utxoindex/utxoindex.go @@ -29,7 +29,7 @@ func New(consensus externalapi.Consensus, database database.Database) *UTXOIndex } // Update updates the UTXO index with the given DAG selected parent chain changes -func (ui *UTXOIndex) Update(chainChanges *externalapi.SelectedParentChainChanges) (*UTXOChanges, error) { +func (ui *UTXOIndex) Update(chainChanges *externalapi.SelectedChainPath) (*UTXOChanges, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "UTXOIndex.Update") defer onEnd() From d9b97afb929dc1be259415db391b29984bb3a5c2 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 11 Jan 2021 17:16:15 +0200 Subject: [PATCH 235/351] Don't swallow errors in HandleNewBlockTransactions. (#1390) Co-authored-by: Ori Newman --- app/protocol/flowcontext/blocks.go | 5 ++++- domain/miningmanager/mempool/mempool.go | 8 ++++---- domain/miningmanager/miningmanager.go | 4 ++-- domain/miningmanager/model/interface_mempool.go | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index d229a8748..59e502b1e 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -41,7 +41,10 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, blocklogger.LogBlock(block) log.Debugf("OnNewBlock: passing block %s transactions to mining manager", hash) - _ = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) + _, err = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) + if err != nil { + return err + } if f.onBlockAddedToDAGHandler != nil { log.Debugf("OnNewBlock: calling f.onBlockAddedToDAGHandler for block %s", hash) diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index fe06cd61a..92e5e0e38 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -876,7 +876,7 @@ func (mp *mempool) BlockCandidateTransactions() []*consensusexternalapi.DomainTr // from the mempool and the orphan pool, and it also removes // from the mempool transactions that double spend a // transaction that is already in the DAG -func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction { +func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error) { // Protect concurrent access. mp.mtx.Lock() defer mp.mtx.Unlock() @@ -890,13 +890,13 @@ func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.Domain // valid. err := mp.removeBlockTransactionsFromPool(txs) if err != nil { - log.Errorf("Failed removing txs from pool: '%s'", err) + return nil, errors.Wrapf(err, "Failed removing txs from pool") } acceptedTxs := make([]*consensusexternalapi.DomainTransaction, 0) for _, tx := range txs[transactionhelper.CoinbaseTransactionIndex+1:] { err := mp.removeDoubleSpends(tx) if err != nil { - log.Infof("Failed removing tx from mempool: %s, '%s'", consensushashing.TransactionID(tx), err) + return nil, errors.Wrapf(err, "Failed removing tx from mempool: %s", consensushashing.TransactionID(tx)) } mp.removeOrphan(tx, false) acceptedOrphans := mp.processOrphans(tx) @@ -905,7 +905,7 @@ func (mp *mempool) HandleNewBlockTransactions(txs []*consensusexternalapi.Domain } } - return acceptedTxs + return acceptedTxs, nil } func (mp *mempool) RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) { diff --git a/domain/miningmanager/miningmanager.go b/domain/miningmanager/miningmanager.go index 5c5ab59f7..bbbeb2b9b 100644 --- a/domain/miningmanager/miningmanager.go +++ b/domain/miningmanager/miningmanager.go @@ -11,7 +11,7 @@ type MiningManager interface { GetBlockTemplate(coinbaseData *consensusexternalapi.DomainCoinbaseData) (*consensusexternalapi.DomainBlock, error) GetTransaction(transactionID *consensusexternalapi.DomainTransactionID) (*consensusexternalapi.DomainTransaction, bool) AllTransactions() []*consensusexternalapi.DomainTransaction - HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction + HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error) ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error } @@ -26,7 +26,7 @@ func (mm *miningManager) GetBlockTemplate(coinbaseData *consensusexternalapi.Dom } // HandleNewBlock handles the transactions for a new block that was just added to the DAG -func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction { +func (mm *miningManager) HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error) { return mm.mempool.HandleNewBlockTransactions(txs) } diff --git a/domain/miningmanager/model/interface_mempool.go b/domain/miningmanager/model/interface_mempool.go index c49be4f96..0c824536a 100644 --- a/domain/miningmanager/model/interface_mempool.go +++ b/domain/miningmanager/model/interface_mempool.go @@ -7,7 +7,7 @@ import ( // Mempool maintains a set of known transactions that // are intended to be mined into new blocks type Mempool interface { - HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) []*consensusexternalapi.DomainTransaction + HandleNewBlockTransactions(txs []*consensusexternalapi.DomainTransaction) ([]*consensusexternalapi.DomainTransaction, error) BlockCandidateTransactions() []*consensusexternalapi.DomainTransaction ValidateAndInsertTransaction(transaction *consensusexternalapi.DomainTransaction, allowOrphan bool) error RemoveTransactions(txs []*consensusexternalapi.DomainTransaction) From 6101e6bdb6e177a814aefdc1e9fbb097cac82dc7 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 11 Jan 2021 17:45:17 +0200 Subject: [PATCH 236/351] Fix UTXO serialization, its test, and the static check that missed it (#1396) * Fix UTXO serialization, its test, and the static check that missed it * Remove duplicate case * Use one line for static check Co-authored-by: Elichai Turkel --- build_and_test.sh | 6 +----- domain/consensus/utils/utxo/serialization.go | 1 + domain/consensus/utils/utxo/serialization_test.go | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/build_and_test.sh b/build_and_test.sh index 6fd9ac9ba..2e6d5c856 100755 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -13,11 +13,7 @@ test -z "$(go fmt ./...)" golint -set_exit_status ./... -staticcheck -checks "\ - SA4006,SA4008,SA4009,SA4010,SA5003,SA1004,SA1014,SA1021,SA1023,SA1024,SA1025,SA1026,SA1027,SA1028,SA2000,SA2001, \ - SA2003,SA4000,SA4001,SA4003,SA4004,SA4011,SA4012,SA4013,SA4014,SA4015,SA4016,SA4017,SA4018,SA4019,SA4020,SA4021, \ - SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002, \ - SA9003,SA9004,SA9005,SA9006,ST1019" ./... +staticcheck -checks SA4006,SA4008,SA4009,SA4010,SA5003,SA1004,SA1014,SA1021,SA1023,SA1024,SA1025,SA1026,SA1027,SA1028,SA2000,SA2001,SA2003,SA4000,SA4001,SA4003,SA4004,SA4011,SA4012,SA4013,SA4014,SA4015,SA4016,SA4017,SA4018,SA4019,SA4020,SA4021,SA4022,SA4023,SA5000,SA5002,SA5004,SA5005,SA5007,SA5008,SA5009,SA5010,SA5011,SA5012,SA6001,SA6002,SA9001,SA9002,SA9003,SA9004,SA9005,SA9006,ST1019 ./... go vet -composites=false $FLAGS ./... diff --git a/domain/consensus/utils/utxo/serialization.go b/domain/consensus/utils/utxo/serialization.go index ed3fd5935..478447072 100644 --- a/domain/consensus/utils/utxo/serialization.go +++ b/domain/consensus/utils/utxo/serialization.go @@ -118,6 +118,7 @@ func deserializeUTXOEntry(r io.Reader) (externalapi.UTXOEntry, error) { if err != nil { return nil, err } + var scriptPubKeyLen uint64 err = serialization.ReadElement(r, &scriptPubKeyLen) if err != nil { diff --git a/domain/consensus/utils/utxo/serialization_test.go b/domain/consensus/utils/utxo/serialization_test.go index 19eab145a..000ead691 100644 --- a/domain/consensus/utils/utxo/serialization_test.go +++ b/domain/consensus/utils/utxo/serialization_test.go @@ -57,7 +57,7 @@ func Test_serializeUTXO(t *testing.T) { deserializedEntry, deserializedOutpoint, err := DeserializeUTXO(serialized) if err != nil { - return + t.Fatalf("DeserializeUTXO: %+v", err) } if !reflect.DeepEqual(deserializedEntry, entry) { From bcf230246011eed66407f51f6c2478bd5410a66e Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 12 Jan 2021 11:16:25 +0200 Subject: [PATCH 237/351] Add high hash to block locator, and add block locator tests (#1397) * Include high hash in the block locator * Add tests for block locator * Remove redundant function * Remove redundant assignments --- domain/consensus/consensus.go | 11 - .../consensus/model/externalapi/consensus.go | 1 - .../model/interface_processes_syncmanager.go | 1 - .../processes/syncmanager/blocklocator.go | 34 --- .../syncmanager/blocklocator_test.go | 231 ++++++++++++++++++ .../processes/syncmanager/syncmanager.go | 7 - 6 files changed, 231 insertions(+), 54 deletions(-) create mode 100644 domain/consensus/processes/syncmanager/blocklocator_test.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 08a14e10c..9d7bf67d6 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -306,17 +306,6 @@ func (s *consensus) CreateHeadersSelectedChainBlockLocator(lowHash, return s.syncManager.CreateHeadersSelectedChainBlockLocator(lowHash, highHash) } -func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { - s.lock.Lock() - defer s.lock.Unlock() - - if len(blockLocator) == 0 { - return nil, nil, errors.Errorf("empty block locator") - } - - return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator) -} - func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) { s.lock.Lock() defer s.lock.Unlock() diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 535d99664..cce6c9b5e 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -19,7 +19,6 @@ type Consensus interface { GetVirtualSelectedParent() (*DomainHash, error) CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) - FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error) GetSyncInfo() (*SyncInfo, error) Tips() ([]*DomainHash, error) GetVirtualInfo() (*VirtualInfo, error) diff --git a/domain/consensus/model/interface_processes_syncmanager.go b/domain/consensus/model/interface_processes_syncmanager.go index 5596f98e7..e67ccb884 100644 --- a/domain/consensus/model/interface_processes_syncmanager.go +++ b/domain/consensus/model/interface_processes_syncmanager.go @@ -8,6 +8,5 @@ type SyncManager interface { GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) - FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) GetSyncInfo() (*externalapi.SyncInfo, error) } diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index 62ec0427a..56ddc3b56 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -8,14 +8,6 @@ import ( // createBlockLocator creates a block locator for the passed high and low hashes. // See the BlockLocator type comments for more details. func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) { - // We use the selected parent of the high block, so that the - // block locator won't contain it. - highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash) - if err != nil { - return nil, err - } - highHash = highBlockGHOSTDAGData.SelectedParent() - lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) if err != nil { return nil, err @@ -73,32 +65,6 @@ func (sm *syncManager) createBlockLocator(lowHash, highHash *externalapi.DomainH return locator, nil } -// findNextBlockLocatorBoundaries finds the lowest unknown block locator -// hash and the highest known block locator hash. This is used to create the -// next block locator to find the highest shared known chain block with a -// remote kaspad. -func (sm *syncManager) findNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) ( - lowHash, highHash *externalapi.DomainHash, err error) { - - // Find the most recent locator block hash in the DAG. In case none of - // the hashes in the locator are in the DAG, fall back to the genesis block. - highestKnownHash := sm.genesisBlockHash - lowestUnknownHash := blockLocator[len(blockLocator)-1] - for _, hash := range blockLocator { - exists, err := sm.blockStatusStore.Exists(sm.databaseContext, hash) - if err != nil { - return nil, nil, err - } - if !exists { - lowestUnknownHash = hash - } else { - highestKnownHash = hash - break - } - } - return highestKnownHash, lowestUnknownHash, nil -} - func (sm *syncManager) createHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { diff --git a/domain/consensus/processes/syncmanager/blocklocator_test.go b/domain/consensus/processes/syncmanager/blocklocator_test.go new file mode 100644 index 000000000..6a6276626 --- /dev/null +++ b/domain/consensus/processes/syncmanager/blocklocator_test.go @@ -0,0 +1,231 @@ +package syncmanager_test + +import ( + "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" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/pkg/errors" + "strings" + "testing" +) + +func TestCreateBlockLocator(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestCreateBlockLocator") + if err != nil { + t.Fatalf("NewTestConsensus: %+v", err) + } + defer tearDown(false) + + chain := []*externalapi.DomainHash{params.GenesisHash} + tipHash := params.GenesisHash + for i := 0; i < 20; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + chain = append(chain, tipHash) + } + + sideChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + // Check a situation where low hash is not on the exact step blue score + locator, err := tc.CreateBlockLocator(params.GenesisHash, tipHash, 0) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[20], + chain[19], + chain[17], + chain[13], + chain[5], + chain[0], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check a situation where low hash is on the exact step blue score + locator, err = tc.CreateBlockLocator(chain[5], tipHash, 0) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[20], + chain[19], + chain[17], + chain[13], + chain[5], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check block locator with limit + locator, err = tc.CreateBlockLocator(params.GenesisHash, tipHash, 3) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[20], + chain[19], + chain[17], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check a block locator from genesis to genesis + locator, err = tc.CreateBlockLocator(params.GenesisHash, params.GenesisHash, 0) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + params.GenesisHash, + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check a block locator from one block to the same block + locator, err = tc.CreateBlockLocator(chain[7], chain[7], 0) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[7], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check block locator with incompatible blocks + _, err = tc.CreateBlockLocator(sideChainTipHash, tipHash, 0) + expectedErr := "highHash and lowHash are not in the same selected parent chain" + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Fatalf("expected error '%s' but got '%s'", expectedErr, err) + } + + // Check block locator with non exist blocks + _, err = tc.CreateBlockLocator(&externalapi.DomainHash{}, tipHash, 0) + expectedErr = "does not exist" + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Fatalf("expected error '%s' but got '%s'", expectedErr, err) + } + + _, err = tc.CreateBlockLocator(tipHash, &externalapi.DomainHash{}, 0) + expectedErr = "does not exist" + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Fatalf("expected error '%s' but got '%s'", expectedErr, err) + } + }) +} + +func TestCreateHeadersSelectedChainBlockLocator(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestCreateHeadersSelectedChainBlockLocator") + if err != nil { + t.Fatalf("NewTestConsensus: %+v", err) + } + defer tearDown(false) + + chain := []*externalapi.DomainHash{params.GenesisHash} + tipHash := params.GenesisHash + for i := 0; i < 20; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + chain = append(chain, tipHash) + } + + sideChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + // Check a situation where low hash is not on the exact step + locator, err := tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, tipHash) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[20], + chain[19], + chain[17], + chain[13], + chain[5], + chain[0], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check a situation where low hash is on the exact step + locator, err = tc.CreateHeadersSelectedChainBlockLocator(chain[5], tipHash) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[20], + chain[19], + chain[17], + chain[13], + chain[5], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check a block locator from genesis to genesis + locator, err = tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, params.GenesisHash) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + params.GenesisHash, + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check a block locator from one block to the same block + locator, err = tc.CreateHeadersSelectedChainBlockLocator(chain[7], chain[7]) + if err != nil { + t.Fatalf("CreateBlockLocator: %+v", err) + } + + if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{ + chain[7], + }) { + t.Fatalf("unexpected block locator %s", locator) + } + + // Check block locator with low hash higher than high hash + _, err = tc.CreateHeadersSelectedChainBlockLocator(chain[20], chain[19]) + expectedErr := "cannot build block locator while highHash is lower than lowHash" + if err == nil || !strings.Contains(err.Error(), expectedErr) { + t.Fatalf("expected error '%s' but got '%s'", expectedErr, err) + } + + // Check block locator with non chain blocks + _, err = tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, sideChainTipHash) + if !errors.Is(err, database.ErrNotFound) { + t.Fatalf("expected error '%s' but got '%s'", database.ErrNotFound, err) + } + }) +} diff --git a/domain/consensus/processes/syncmanager/syncmanager.go b/domain/consensus/processes/syncmanager/syncmanager.go index 48ea10d65..c4f5d7384 100644 --- a/domain/consensus/processes/syncmanager/syncmanager.go +++ b/domain/consensus/processes/syncmanager/syncmanager.go @@ -89,13 +89,6 @@ func (sm *syncManager) CreateHeadersSelectedChainBlockLocator(lowHash, return sm.createHeadersSelectedChainBlockLocator(lowHash, highHash) } -func (sm *syncManager) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) { - onEnd := logger.LogAndMeasureExecutionTime(log, "FindNextBlockLocatorBoundaries") - defer onEnd() - - return sm.findNextBlockLocatorBoundaries(blockLocator) -} - func (sm *syncManager) GetSyncInfo() (*externalapi.SyncInfo, error) { onEnd := logger.LogAndMeasureExecutionTime(log, "GetSyncInfo") defer onEnd() From 53744ceb45dbf8fdc27278a9028ddd37d8e093d8 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 12 Jan 2021 12:53:33 +0200 Subject: [PATCH 238/351] Compare transaction IDs with Equal (#1401) --- .../flows/transactionrelay/handle_relayed_transactions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/protocol/flows/transactionrelay/handle_relayed_transactions.go b/app/protocol/flows/transactionrelay/handle_relayed_transactions.go index 2bcd8afc9..e97919d81 100644 --- a/app/protocol/flows/transactionrelay/handle_relayed_transactions.go +++ b/app/protocol/flows/transactionrelay/handle_relayed_transactions.go @@ -159,7 +159,7 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact return err } if msgTxNotFound != nil { - if msgTxNotFound.ID != expectedID { + if !msgTxNotFound.ID.Equal(expectedID) { return protocolerrors.Errorf(true, "expected transaction %s, but got %s", expectedID, msgTxNotFound.ID) } From c1361e5b3e113becde3a055bcd210dc4747c8d78 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 12 Jan 2021 13:26:29 +0200 Subject: [PATCH 239/351] Change log sizes and add some new features to logger (#1400) * Increase default log sizes, and increase kaspad log sizes * Add an option to not print logs to stdout * Allow logs to be printed in the current working directory * Add more pruning related logs * Add comment and increase log rotations to save last 64 logs --- .../pruningmanager/pruningmanager.go | 4 +++ infrastructure/logger/logger.go | 4 +-- infrastructure/logger/logs.go | 26 ++++++++++++++----- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 1149bcfa3..5f5c4a308 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -171,6 +171,7 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { } if !newCandidate.Equal(currentCandidate) { + log.Debugf("Staged a new pruning candidate, old: %s, new: %s", currentCandidate, newCandidate) pm.pruningStore.StagePruningPointCandidate(newCandidate) } @@ -181,6 +182,7 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { } if !newPruningPoint.Equal(currentPruningPoint) { + log.Debugf("Moving pruning point from %s to %s", currentPruningPoint, newPruningPoint) err = pm.savePruningPoint(newPruningPoint) if err != nil { return err @@ -447,6 +449,8 @@ func (pm *pruningManager) validateUTXOSetFitsCommitment( pruningPointHash, utxoSetHash, expectedUTXOCommitment) } + log.Debugf("Validated the pruning point %s UTXO commitment: %s", pruningPointHash, utxoSetHash) + return nil } diff --git a/infrastructure/logger/logger.go b/infrastructure/logger/logger.go index 28a221cbd..fc5c4a8ed 100644 --- a/infrastructure/logger/logger.go +++ b/infrastructure/logger/logger.go @@ -159,8 +159,8 @@ var subsystemLoggers = map[string]*Logger{ // InitLog attaches log file and error log file to the backend log. func InitLog(logFile, errLogFile string) { - // 250 MB (MB=1000^2 bytes) - err := BackendLog.AddLogFileWithCustomRotator(logFile, LevelTrace, 1000*250, 32) + // 280 MB (MB=1000^2 bytes) + err := BackendLog.AddLogFileWithCustomRotator(logFile, LevelTrace, 1000*280, 64) if err != nil { fmt.Fprintf(os.Stderr, "Error adding log file %s as log rotator for level %s: %s", logFile, LevelTrace, err) os.Exit(1) diff --git a/infrastructure/logger/logs.go b/infrastructure/logger/logs.go index c7bf92706..a8bf4801d 100644 --- a/infrastructure/logger/logs.go +++ b/infrastructure/logger/logs.go @@ -129,7 +129,7 @@ func (l Level) String() string { // NewBackend creates a new logger backend. func NewBackend(opts ...BackendOption) *Backend { - b := &Backend{flag: defaultFlags} + b := &Backend{flag: defaultFlags, toStdout: true} for _, o := range opts { o(b) } @@ -148,6 +148,7 @@ type Backend struct { rotators []*backendLogRotator mu sync.Mutex // ensures atomic writes flag uint32 + toStdout bool } // BackendOption is a function used to modify the behavior of a Backend. @@ -266,8 +267,8 @@ func callsite(flag uint32) (string, int) { } const ( - defaultThresholdKB = 10 * 1024 - defaultMaxRolls = 3 + defaultThresholdKB = 100 * 1000 // 100 MB logs by default. + defaultMaxRolls = 8 // keep 8 last logs by default. ) // AddLogFile adds a file which the log will write into on a certain @@ -281,9 +282,12 @@ func (b *Backend) AddLogFile(logFile string, logLevel Level) error { // It'll create the file if it doesn't exist. func (b *Backend) AddLogFileWithCustomRotator(logFile string, logLevel Level, thresholdKB int64, maxRolls int) error { logDir, _ := filepath.Split(logFile) - err := os.MkdirAll(logDir, 0700) - if err != nil { - return errors.Errorf("failed to create log directory: %s", err) + // if the logDir is empty then `logFile` is in the cwd and there's no need to create any directory. + if logDir != "" { + err := os.MkdirAll(logDir, 0700) + if err != nil { + return errors.Errorf("failed to create log directory: %+v", err) + } } r, err := rotator.New(logFile, thresholdKB, false, maxRolls) if err != nil { @@ -348,7 +352,10 @@ func (b *Backend) printf(lvl Level, tag string, format string, args ...interface func (b *Backend) write(lvl Level, bytesToWrite []byte) { b.mu.Lock() defer b.mu.Unlock() - os.Stdout.Write(bytesToWrite) + if b.toStdout { + os.Stdout.Write(bytesToWrite) + } + for _, r := range b.rotators { if lvl >= r.logLevel { r.Write(bytesToWrite) @@ -363,6 +370,11 @@ func (b *Backend) Close() { } } +// WriteToStdout sets if the backend will print to stdout or not (default: true) +func (b *Backend) WriteToStdout(stdout bool) { + b.toStdout = stdout +} + // Logger returns a new logger for a particular subsystem that writes to the // Backend b. A tag describes the subsystem and is included in all log // messages. The logger uses the info verbosity level by default. From 23a2fbf401eea886bfe8965510e0ba39eeb463e6 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 12 Jan 2021 15:27:08 +0200 Subject: [PATCH 240/351] Remove erroneous finality optimization from LowestChainBlockAboveOrEqualToBlueScore (#1402) * Remove finality erroneous optimization from LowestChainBlockAboveOrEqualToBlueScore * Add TestLowestChainBlockAboveOrEqualToBlueScore * Remove unnecessary fields from dagTraversalManager --- domain/consensus/factory.go | 4 +- .../dagtraversalmanager.go | 21 +--- .../dagtraversalmanager_test.go | 113 ++++++++++++++++++ 3 files changed, 115 insertions(+), 23 deletions(-) create mode 100644 domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 20608919f..414724e94 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -113,9 +113,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTopologyManager, ghostdagDataStore, reachabilityDataStore, - ghostdagManager, - finalityStore, - dagParams.FinalityDepth()) + ghostdagManager) pastMedianTimeManager := pastmediantimemanager.New( dagParams.TimestampDeviationTolerance, dbManager, diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 27aaa1145..316a01ccb 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -16,8 +16,6 @@ type dagTraversalManager struct { ghostdagManager model.GHOSTDAGManager ghostdagDataStore model.GHOSTDAGDataStore reachabilityDataStore model.ReachabilityDataStore - finalityStore model.FinalityStore - finalityDepth uint64 } // selectedParentIterator implements the `model.BlockIterator` API @@ -49,17 +47,13 @@ func New( dagTopologyManager model.DAGTopologyManager, ghostdagDataStore model.GHOSTDAGDataStore, reachabilityDataStore model.ReachabilityDataStore, - ghostdagManager model.GHOSTDAGManager, - finalityStore model.FinalityStore, - finalityDepth uint64) model.DAGTraversalManager { + ghostdagManager model.GHOSTDAGManager) model.DAGTraversalManager { return &dagTraversalManager{ databaseContext: databaseContext, dagTopologyManager: dagTopologyManager, ghostdagDataStore: ghostdagDataStore, reachabilityDataStore: reachabilityDataStore, ghostdagManager: ghostdagManager, - finalityStore: finalityStore, - finalityDepth: finalityDepth, } } @@ -117,19 +111,6 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash currentHash := highHash currentBlockGHOSTDAGData := highBlockGHOSTDAGData - // Use the finality Store to jump `finalityDepth` blue scores down the selected chain. - // this should be much faster than stepping through the whole chain. - for currentBlockGHOSTDAGData.BlueScore()-blueScore >= dtm.finalityDepth { - currentHash, err = dtm.finalityStore.FinalityPoint(dtm.databaseContext, currentHash) - if err != nil { - return nil, err - } - currentBlockGHOSTDAGData, err = dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) - if err != nil { - return nil, err - } - } - for currentBlockGHOSTDAGData.SelectedParent() != nil { selectedParentBlockGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentBlockGHOSTDAGData.SelectedParent()) if err != nil { diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go new file mode 100644 index 000000000..cd4c9f2fe --- /dev/null +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go @@ -0,0 +1,113 @@ +package dagtraversalmanager_test + +import ( + "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 TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.FinalityDuration = 10 * params.TargetTimePerBlock + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestLowestChainBlockAboveOrEqualToBlueScore") + if err != nil { + t.Fatalf("NewTestConsensus: %s", err) + } + defer tearDown(false) + + checkExpectedBlock := func(highHash *externalapi.DomainHash, blueScore uint64, expected *externalapi.DomainHash) { + blockHash, err := tc.DAGTraversalManager().LowestChainBlockAboveOrEqualToBlueScore(highHash, blueScore) + if err != nil { + t.Fatalf("LowestChainBlockAboveOrEqualToBlueScore: %+v", err) + } + + if !blockHash.Equal(expected) { + t.Fatalf("Expected block %s but got %s", expected, blockHash) + } + } + + checkBlueScore := func(blockHash *externalapi.DomainHash, expectedBlueScoe uint64) { + ghostdagData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), blockHash) + if err != nil { + t.Fatalf("GHOSTDAGDataStore().Get: %+v", err) + } + + if ghostdagData.BlueScore() != expectedBlueScoe { + t.Fatalf("Expected blue score %d but got %d", expectedBlueScoe, ghostdagData.BlueScore()) + } + } + + chain := []*externalapi.DomainHash{params.GenesisHash} + tipHash := params.GenesisHash + for i := 0; i < 9; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + chain = append(chain, tipHash) + } + + sideChain1TipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{sideChain1TipHash, tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + chain = append(chain, tipHash) + blueScore11BlockHash := tipHash + checkBlueScore(blueScore11BlockHash, 11) + + for i := 0; i < 5; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + chain = append(chain, tipHash) + } + + sideChain2TipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{sideChain2TipHash, tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + chain = append(chain, tipHash) + + blueScore18BlockHash := tipHash + checkBlueScore(blueScore18BlockHash, 18) + + for i := 0; i < 3; i++ { + var err error + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + chain = append(chain, tipHash) + } + + // Check by exact blue score + checkExpectedBlock(tipHash, 0, params.GenesisHash) + checkExpectedBlock(tipHash, 5, chain[5]) + checkExpectedBlock(tipHash, 19, chain[len(chain)-3]) + + // Check by non exact blue score + checkExpectedBlock(tipHash, 17, blueScore18BlockHash) + checkExpectedBlock(tipHash, 10, blueScore11BlockHash) + }) +} From 8ad5725421a4d3f951c4ab627418180c9a985b88 Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Tue, 12 Jan 2021 15:55:02 +0200 Subject: [PATCH 241/351] Adding a test for the error cases on the function 'checkBlockStatus()' (#1398) * Adds test for error cases on the function checkBlockStatus. * Fix review's comments. * Move test to validateandinsertblock_test.go Co-authored-by: tal Co-authored-by: Ori Newman --- .../validateandinsertblock_test.go | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go index 6cfc26ea4..8552c5565 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go @@ -1,6 +1,7 @@ package blockprocessor_test import ( + "strings" "testing" "github.com/kaspanet/kaspad/domain/consensus" @@ -105,3 +106,105 @@ func TestBlockStatus(t *testing.T) { checkStatus(consensushashing.BlockHash(invalidBlock), externalapi.StatusInvalid) }) } + +// TestValidateAndInsertErrors tests the error cases on "validateBlock" function. +func TestValidateAndInsertErrors(t *testing.T) { + // All the tests below tests the error cases in "validateAndInsertBlock" function. + // Each test is covering the error cases in a sub-function in "validateAndInsertBlock" function. + // Currently, implemented only for some of the errors. + + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestBlockStatus") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + tipHash, emptyCoinbase, tx1 := initData(params) + + // Tests all the error case on the function: "checkBlockStatus"(sub-function in function validateBlock) + blockWithStatusInvalid, err := tc.BuildBlock(&emptyCoinbase, []*externalapi.DomainTransaction{tx1, tx1}) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + _, err = tc.ValidateAndInsertBlock(blockWithStatusInvalid) + if err == nil { + t.Fatalf("Test ValidateAndInsertBlock: Expected an error, because the block is invalid.") + } + _, err = tc.ValidateAndInsertBlock(blockWithStatusInvalid) + if err == nil || !errors.Is(err, ruleerrors.ErrKnownInvalid) { + t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrKnownInvalid, err) + } + if !strings.Contains(err.Error(), "is a known invalid block") { + t.Fatalf("Test ValidateAndInsertBlock: Expected an diff error, got: %+v.", err) + } + + block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + _, err = tc.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + // resend the same block. + _, err = tc.ValidateAndInsertBlock(block) + if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateBlock) { + t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrDuplicateBlock, err) + } + if !strings.Contains(err.Error(), " already exists") { + t.Fatalf("Test ValidateAndInsertBlock: Expected an diff error, got: %+v.", err) + } + + onlyHeader, err := tc.BuildBlock(&emptyCoinbase, []*externalapi.DomainTransaction{}) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + onlyHeader.Transactions = []*externalapi.DomainTransaction{} + _, err = tc.ValidateAndInsertBlock(onlyHeader) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + // resend the same header. + _, err = tc.ValidateAndInsertBlock(onlyHeader) + if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateBlock) { + t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrDuplicateBlock, err) + } + if !strings.Contains(err.Error(), "header already exists") { + t.Fatalf("Test ValidateAndInsertBlock: Expected an diff error, got: %+v.", err) + } + + }) +} + +func initData(params *dagconfig.Params) (*externalapi.DomainHash, externalapi.DomainCoinbaseData, *externalapi.DomainTransaction) { + return params.GenesisHash, + externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + }, + + &externalapi.DomainTransaction{ + Version: 0, + Inputs: []*externalapi.DomainTransactionInput{}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + LockTime: 1, + SubnetworkID: externalapi.DomainSubnetworkID{0x01}, + Gas: 1, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + Payload: []byte{0x01}, + Fee: 0, + Mass: 1, + ID: externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}), + } +} From ce348373c6c4769d3f89c78754e4e17af7268f62 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 12 Jan 2021 16:51:56 +0200 Subject: [PATCH 242/351] Delete existing UTXOSet when commiting VirtualUTXOSet. (#1403) --- domain/consensus/database/transaction.go | 16 ++++++++++++++++ .../datastructures/consensusstatestore/utxo.go | 17 +++++++++++++++++ domain/consensus/model/database.go | 1 + 3 files changed, 34 insertions(+) diff --git a/domain/consensus/database/transaction.go b/domain/consensus/database/transaction.go index 9f17bc544..1ecbfa802 100644 --- a/domain/consensus/database/transaction.go +++ b/domain/consensus/database/transaction.go @@ -9,6 +9,22 @@ type dbTransaction struct { transaction database.Transaction } +func (d *dbTransaction) Get(key model.DBKey) ([]byte, error) { + return d.transaction.Get(dbKeyToDatabaseKey(key)) +} + +func (d *dbTransaction) Has(key model.DBKey) (bool, error) { + return d.transaction.Has(dbKeyToDatabaseKey(key)) +} + +func (d *dbTransaction) Cursor(bucket model.DBBucket) (model.DBCursor, error) { + cursor, err := d.transaction.Cursor(dbBucketToDatabaseBucket(bucket)) + if err != nil { + return nil, err + } + return newDBCursor(cursor), nil +} + func (d *dbTransaction) Put(key model.DBKey, value []byte) error { return d.transaction.Put(dbKeyToDatabaseKey(key), value) } diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index 5959bfb1a..8c1dc2854 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -85,6 +85,23 @@ func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) e return nil } + // Clear the existing virtual utxo set in database before adding the new one + cursor, err := dbTx.Cursor(utxoSetBucket) + if err != nil { + return err + } + for cursor.Next() { + key, err := cursor.Key() + if err != nil { + return err + } + err = dbTx.Delete(key) + if err != nil { + return err + } + } + + // Now put the new virtualUTXOSet into the database css.virtualUTXOSetCache.Clear() iterator := css.virtualUTXOSetStaging.Iterator() for iterator.Next() { diff --git a/domain/consensus/model/database.go b/domain/consensus/model/database.go index f5b2f47aa..7133d99e2 100644 --- a/domain/consensus/model/database.go +++ b/domain/consensus/model/database.go @@ -58,6 +58,7 @@ type DBWriter interface { // access that requires an open database transaction type DBTransaction interface { DBWriter + DBReader // Rollback rolls back whatever changes were made to the // database within this transaction. From cc49b1826ab7c9ff4a4d5456cf566cf5c6109c56 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 12 Jan 2021 21:34:26 +0200 Subject: [PATCH 243/351] Reset windowExpectedEndTime after each window (#1407) --- cmd/kaspaminer/mineloop.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 97c0cf0d0..a2d82a5c2 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -64,6 +64,7 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond time.Sleep(deviation) } blockInWindowIndex = 0 + windowExpectedEndTime = time.Now().Add(expectedDurationForWindow) } } From 192dd2ba8f628470118fd5147ab606c00adbb5e9 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 13 Jan 2021 10:35:12 +0200 Subject: [PATCH 244/351] Add codecov to github (#1358) --- .github/workflows/go.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index b10b6f049..d23baf0e7 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -49,3 +49,22 @@ jobs: - name: Test shell: bash run: ./build_and_test.sh + + coverage: + runs-on: ubuntu-20.04 + name: Produce code coverage + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: 1.14 + + - name: Create coverage file + # Because of https://github.com/golang/go/issues/27333 this seem to "fail" even though nothing is wrong, so ignore the failure + run: go test -json -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./... || true + + - name: Upload coverage file + run: bash <(curl -s https://codecov.io/bash) \ No newline at end of file From 68bd8330acc80ad57e01884a3118714969b78035 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 13 Jan 2021 12:51:23 +0200 Subject: [PATCH 245/351] Log the networks hashrate (#1406) * Log the hashrate of each block * Add a test for GetHashrateString * Move difficulty related functions to its own package * Convert the validated log in validateAndInsertBlock to a log function * Add tests for max/min int --- app/rpc/rpccontext/verbosedata.go | 4 +- cmd/kaspaminer/mineloop.go | 3 +- domain/consensus/factory.go | 1 + domain/consensus/model/pow/pow.go | 8 +-- .../blockprocessor/blockprocessor.go | 8 ++- .../blockprocessor/validateandinsertblock.go | 8 ++- .../blockvalidator/blockvalidator.go | 4 +- .../processes/blockvalidator/proof_of_work.go | 4 +- .../blockvalidator/proof_of_work_test.go | 4 +- .../difficultymanager/blockwindow.go | 4 +- .../difficultymanager/difficultymanager.go | 6 +- .../difficultymanager_test.go | 6 +- .../processes/ghostdag2/ghostdagimpl.go | 4 +- .../processes/ghostdagmanager/ghostdag.go | 4 +- .../ghostdagmanager/ghostdag_test.go | 7 +- .../blocktemplatebuilder.go | 4 +- testing/integration/mining_test.go | 4 +- util/{math.go => difficulty/difficulty.go} | 65 +++++++++++++------ util/difficulty/difficulty_test.go | 24 +++++++ util/example_test.go | 5 +- util/math/min_test.go | 64 ++++++++++++++++++ util/math_test.go | 35 ---------- 22 files changed, 182 insertions(+), 94 deletions(-) rename util/{math.go => difficulty/difficulty.go} (76%) create mode 100644 util/difficulty/difficulty_test.go create mode 100644 util/math/min_test.go delete mode 100644 util/math_test.go diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 7f09bac8f..16b8556ce 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "fmt" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/util/difficulty" "math" "math/big" "strconv" @@ -19,7 +20,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/dagconfig" - "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/pointers" ) @@ -83,7 +83,7 @@ func (ctx *Context) GetDifficultyRatio(bits uint32, params *dagconfig.Params) fl // converted back to a number. Note this is not the same as the proof of // work limit directly because the block difficulty is encoded in a block // with the compact form which loses precision. - target := util.CompactToBig(bits) + target := difficulty.CompactToBig(bits) difficulty := new(big.Rat).SetFrac(params.PowMax, target) diff, _ := difficulty.Float64() diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index a2d82a5c2..bfa9f3e7d 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -2,6 +2,7 @@ package main import ( nativeerrors "errors" + "github.com/kaspanet/kaspad/util/difficulty" "math/rand" "sync/atomic" "time" @@ -122,7 +123,7 @@ func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error } func solveBlock(block *externalapi.DomainBlock, stopChan chan struct{}, foundBlock chan *externalapi.DomainBlock) { - targetDifficulty := util.CompactToBig(block.Header.Bits()) + targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) headerForMining := block.Header.ToMutable() initialNonce := random.Uint64() for i := initialNonce; i != initialNonce-1; i++ { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 414724e94..38ec3cc26 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -277,6 +277,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockProcessor := blockprocessor.New( genesisHash, + dagParams.TargetTimePerBlock, dbManager, consensusStateManager, pruningManager, diff --git a/domain/consensus/model/pow/pow.go b/domain/consensus/model/pow/pow.go index c584cc628..faea01951 100644 --- a/domain/consensus/model/pow/pow.go +++ b/domain/consensus/model/pow/pow.go @@ -1,14 +1,14 @@ package pow import ( - "math/big" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/domain/consensus/utils/serialization" - "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/util/difficulty" + "github.com/pkg/errors" + "math/big" ) // CheckProofOfWorkWithTarget check's if the block has a valid PoW according to the provided target @@ -24,7 +24,7 @@ func CheckProofOfWorkWithTarget(header externalapi.MutableBlockHeader, target *b // CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field // it does not check if the difficulty itself is valid or less than the maximum for the appropriate network func CheckProofOfWorkByBits(header externalapi.MutableBlockHeader) bool { - return CheckProofOfWorkWithTarget(header, util.CompactToBig(header.Bits())) + return CheckProofOfWorkWithTarget(header, difficulty.CompactToBig(header.Bits())) } func calcPowValue(header externalapi.MutableBlockHeader) *big.Int { diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index c21817150..4d6985c8b 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -4,13 +4,15 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/logger" + "time" ) // blockProcessor is responsible for processing incoming blocks // and creating blocks from the current state type blockProcessor struct { - genesisHash *externalapi.DomainHash - databaseContext model.DBManager + genesisHash *externalapi.DomainHash + targetTimePerBlock time.Duration + databaseContext model.DBManager consensusStateManager model.ConsensusStateManager pruningManager model.PruningManager @@ -45,6 +47,7 @@ type blockProcessor struct { // New instantiates a new BlockProcessor func New( genesisHash *externalapi.DomainHash, + targetTimePerBlock time.Duration, databaseContext model.DBManager, consensusStateManager model.ConsensusStateManager, pruningManager model.PruningManager, @@ -76,6 +79,7 @@ func New( return &blockProcessor{ genesisHash: genesisHash, + targetTimePerBlock: targetTimePerBlock, databaseContext: databaseContext, pruningManager: pruningManager, blockValidator: blockValidator, diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 778966bbf..6c49db0a5 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -2,6 +2,7 @@ package blockprocessor import ( "fmt" + "github.com/kaspanet/kaspad/util/difficulty" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -116,10 +117,13 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, return nil, err } - log.Debugf("Block %s validated and inserted", blockHash) + log.Debug(logger.NewLogClosure(func() string { + hashrate := difficulty.GetHashrateString(difficulty.CompactToBig(block.Header.Bits()), bp.targetTimePerBlock) + return fmt.Sprintf("Block %s validated and inserted, network hashrate: %s", blockHash, hashrate) + })) var logClosureErr error - log.Debugf("%s", logger.NewLogClosure(func() string { + log.Debug(logger.NewLogClosure(func() string { virtualGhostDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash) if err != nil { logClosureErr = err diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index bb5bf40af..e73209f29 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -1,12 +1,12 @@ package blockvalidator import ( + "github.com/kaspanet/kaspad/util/difficulty" "math/big" "time" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util" ) // blockValidator exposes a set of validation classes, after which @@ -79,7 +79,7 @@ func New(powMax *big.Int, skipPoW: skipPoW, genesisHash: genesisHash, enableNonNativeSubnetworks: enableNonNativeSubnetworks, - powMaxBits: util.BigToCompact(powMax), + powMaxBits: difficulty.BigToCompact(powMax), maxBlockSize: maxBlockSize, mergeSetSizeLimit: mergeSetSizeLimit, maxBlockParents: maxBlockParents, diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/proof_of_work.go index fa96c528e..cddf21b04 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work.go @@ -6,7 +6,7 @@ import ( "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/kaspanet/kaspad/util/difficulty" "github.com/pkg/errors" ) @@ -81,7 +81,7 @@ func (v *blockValidator) validateDifficulty(blockHash *externalapi.DomainHash) e // difficulty is not performed. func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error { // The target difficulty must be larger than zero. - target := util.CompactToBig(header.Bits()) + target := difficulty.CompactToBig(header.Bits()) if target.Sign() <= 0 { return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block target difficulty of %064x is too low", target) diff --git a/domain/consensus/processes/blockvalidator/proof_of_work_test.go b/domain/consensus/processes/blockvalidator/proof_of_work_test.go index 451e5e06b..ddc6b479e 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work_test.go +++ b/domain/consensus/processes/blockvalidator/proof_of_work_test.go @@ -4,7 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/pow" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/mining" - "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/util/difficulty" "math" "math/rand" @@ -55,7 +55,7 @@ func TestPOW(t *testing.T) { // solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!). func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock { - targetDifficulty := util.CompactToBig(block.Header.Bits()) + targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) headerForMining := block.Header.ToMutable() initialNonce := uint64(0) for i := initialNonce; i < math.MaxUint64; i++ { diff --git a/domain/consensus/processes/difficultymanager/blockwindow.go b/domain/consensus/processes/difficultymanager/blockwindow.go index 9f070f286..d6c685c93 100644 --- a/domain/consensus/processes/difficultymanager/blockwindow.go +++ b/domain/consensus/processes/difficultymanager/blockwindow.go @@ -2,7 +2,7 @@ package difficultymanager import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/util/difficulty" "github.com/pkg/errors" "math" "math/big" @@ -75,7 +75,7 @@ func (window blockWindow) averageTarget() *big.Int { averageTarget := new(big.Int) targetTmp := new(big.Int) for _, block := range window { - util.CompactToBigWithDestination(block.Bits, targetTmp) + difficulty.CompactToBigWithDestination(block.Bits, targetTmp) averageTarget.Add(averageTarget, targetTmp) } return averageTarget.Div(averageTarget, big.NewInt(int64(len(window)))) diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index c82a6716a..15a6c33ca 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -1,12 +1,12 @@ package difficultymanager import ( + "github.com/kaspanet/kaspad/util/difficulty" "math/big" "time" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util" ) // DifficultyManager provides a method to resolve the @@ -108,8 +108,8 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas Div(newTarget, div.SetInt64(dm.targetTimePerBlock.Milliseconds())). Div(newTarget, div.SetUint64(uint64(dm.difficultyAdjustmentWindowSize))) if newTarget.Cmp(dm.powMax) > 0 { - return util.BigToCompact(dm.powMax), nil + return difficulty.BigToCompact(dm.powMax), nil } - newTargetBits := util.BigToCompact(newTarget) + newTargetBits := difficulty.BigToCompact(newTarget) return newTargetBits, nil } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index 77a3be908..1b921f59c 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -1,6 +1,7 @@ package difficultymanager_test import ( + "github.com/kaspanet/kaspad/util/difficulty" "testing" "time" @@ -13,7 +14,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" - "github.com/kaspanet/kaspad/util" ) func TestDifficulty(t *testing.T) { @@ -213,7 +213,7 @@ func TestDifficulty(t *testing.T) { } func compareBits(a uint32, b uint32) int { - aTarget := util.CompactToBig(a) - bTarget := util.CompactToBig(b) + aTarget := difficulty.CompactToBig(a) + bTarget := difficulty.CompactToBig(b) return aTarget.Cmp(bTarget) } diff --git a/domain/consensus/processes/ghostdag2/ghostdagimpl.go b/domain/consensus/processes/ghostdag2/ghostdagimpl.go index 2afec5464..796523533 100644 --- a/domain/consensus/processes/ghostdag2/ghostdagimpl.go +++ b/domain/consensus/processes/ghostdag2/ghostdagimpl.go @@ -1,13 +1,13 @@ package ghostdag2 import ( + "github.com/kaspanet/kaspad/util/difficulty" "sort" "math/big" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util" ) type ghostdagHelper struct { @@ -111,7 +111,7 @@ func (gh *ghostdagHelper) GHOSTDAG(blockCandidate *externalapi.DomainHash) error if err != nil { return err } - myWork.Add(myWork, util.CalcWork(header.Bits())) + myWork.Add(myWork, difficulty.CalcWork(header.Bits())) } e := model.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil) diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index 488dbf088..b72d775dd 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -3,7 +3,7 @@ package ghostdagmanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util" + "github.com/kaspanet/kaspad/util/difficulty" "github.com/pkg/errors" "math/big" ) @@ -101,7 +101,7 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { if err != nil { return err } - newBlockData.blueWork.Add(newBlockData.blueWork, util.CalcWork(header.Bits())) + newBlockData.blueWork.Add(newBlockData.blueWork, difficulty.CalcWork(header.Bits())) } } else { // Genesis's blue score is defined to be 0. diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index 71f87120b..d004f11dd 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -4,18 +4,17 @@ import ( "encoding/json" "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/util/difficulty" "math/big" "os" "path/filepath" "reflect" "testing" - "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" - "github.com/kaspanet/kaspad/util" - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" + "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" @@ -72,7 +71,7 @@ func TestGHOSTDAG(t *testing.T) { blockGHOSTDAGDataGenesis := model.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil) genesisHeader := params.GenesisBlock.Header - genesisWork := util.CalcWork(genesisHeader.Bits()) + genesisWork := difficulty.CalcWork(genesisHeader.Bits()) var testsCounter int err := filepath.Walk("../../testdata/dags", func(path string, info os.FileInfo, err error) error { diff --git a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go index 18d74c12a..1039bb187 100644 --- a/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go +++ b/domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go @@ -1,6 +1,7 @@ package blocktemplatebuilder import ( + "github.com/kaspanet/kaspad/util/difficulty" "math" "sort" @@ -8,7 +9,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" miningmanagerapi "github.com/kaspanet/kaspad/domain/miningmanager/model" - "github.com/kaspanet/kaspad/util" "github.com/pkg/errors" ) @@ -148,7 +148,7 @@ func (btb *blockTemplateBuilder) GetBlockTemplate(coinbaseData *consensusexterna } log.Debugf("Created new block template (%d transactions, %d in fees, %d mass, target difficulty %064x)", - len(blk.Transactions), blockTxs.totalFees, blockTxs.totalMass, util.CompactToBig(blk.Header.Bits())) + len(blk.Transactions), blockTxs.totalFees, blockTxs.totalMass, difficulty.CompactToBig(blk.Header.Bits())) return blk, nil } diff --git a/testing/integration/mining_test.go b/testing/integration/mining_test.go index 0f9d77746..62849ee15 100644 --- a/testing/integration/mining_test.go +++ b/testing/integration/mining_test.go @@ -2,17 +2,17 @@ package integration import ( "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/util/difficulty" "math/rand" "testing" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util" ) func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock { - targetDifficulty := util.CompactToBig(block.Header.Bits()) + targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) headerForMining := block.Header.ToMutable() initialNonce := rand.Uint64() for i := initialNonce; i != initialNonce-1; i++ { diff --git a/util/math.go b/util/difficulty/difficulty.go similarity index 76% rename from util/math.go rename to util/difficulty/difficulty.go index 9b0bb9c55..27bf0d944 100644 --- a/util/math.go +++ b/util/difficulty/difficulty.go @@ -1,7 +1,8 @@ -package util +package difficulty import ( "math/big" + "time" ) var ( @@ -12,27 +13,8 @@ var ( // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid // the overhead of creating it multiple times. oneLsh256 = new(big.Int).Lsh(bigOne, 256) - - // log2FloorMasks defines the masks to use when quickly calculating - // floor(log2(x)) in a constant log2(64) = 6 steps, where x is a uint64, using - // shifts. They are derived from (2^(2^x) - 1) * (2^(2^x)), for x in 5..0. - log2FloorMasks = []uint64{0xffffffff00000000, 0xffff0000, 0xff00, 0xf0, 0xc, 0x2} ) -// FastLog2Floor calculates and returns floor(log2(x)) in a constant 5 steps. -func FastLog2Floor(n uint64) uint8 { - rv := uint8(0) - exponent := uint8(32) - for i := 0; i < 6; i++ { - if n&log2FloorMasks[i] != 0 { - rv += exponent - n >>= exponent - } - exponent >>= 1 - } - return rv -} - // CompactToBig converts a compact representation of a whole number N to an // unsigned 32-bit number. The representation is similar to IEEE754 floating // point numbers. @@ -151,3 +133,46 @@ func CalcWork(bits uint32) *big.Int { denominator := new(big.Int).Add(difficultyNum, bigOne) return new(big.Int).Div(oneLsh256, denominator) } + +func getHashrate(target *big.Int, TargetTimePerBlock time.Duration) *big.Int { + // From: https://bitcoin.stackexchange.com/a/5557/40800 + // difficulty = hashrate / (2^256 / max_target / block_rate_in_seconds) + // hashrate = difficulty * (2^256 / max_target / block_rate_in_seconds) + // difficulty = max_target / target + // hashrate = (max_target / target) * (2^256 / max_target / block_rate_in_seconds) + // hashrate = 2^256 / (target * block_rate_in_seconds) + + tmp := new(big.Int) + divisor := new(big.Int).Set(target) + divisor.Mul(divisor, tmp.SetInt64(TargetTimePerBlock.Milliseconds())) + divisor.Div(divisor, tmp.SetInt64(int64(time.Second/time.Millisecond))) // Scale it up to seconds. + divisor.Div(oneLsh256, divisor) + return divisor +} + +// GetHashrateString returns the expected hashrate of the network on a certain difficulty target. +func GetHashrateString(target *big.Int, TargetTimePerBlock time.Duration) string { + hashrate := getHashrate(target, TargetTimePerBlock) + in := hashrate.Text(10) + var postfix string + switch { + case len(in) <= 3: + return in + " H/s" + case len(in) <= 6: + postfix = " KH/s" + case len(in) <= 9: + postfix = " MH/s" + case len(in) <= 12: + postfix = " GH/s" + case len(in) <= 15: + postfix = " TH/s" + case len(in) <= 18: + postfix = " PH/s" + case len(in) <= 21: + postfix = " EH/s" + default: + return in + " H/s" + } + highPrecision := len(in) - ((len(in)-1)/3)*3 + return in[:highPrecision] + "." + in[highPrecision:highPrecision+2] + postfix +} diff --git a/util/difficulty/difficulty_test.go b/util/difficulty/difficulty_test.go new file mode 100644 index 000000000..b1e5eb5f0 --- /dev/null +++ b/util/difficulty/difficulty_test.go @@ -0,0 +1,24 @@ +package difficulty_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util/difficulty" + "testing" +) + +func TestGetHashrateString(t *testing.T) { + var results = map[string]string{ + "kaspa-mainnet": "2 H/s", + "kaspa-testnet": "131.07 KH/s", + "kaspa-devnet": "131.07 KH/s", + "kaspa-simnet": "2.00 KH/s", + } + testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { + targetGenesis := difficulty.CompactToBig(params.GenesisBlock.Header.Bits()) + hashrate := difficulty.GetHashrateString(targetGenesis, params.TargetTimePerBlock) + if hashrate != results[params.Name] { + t.Errorf("Expected %s, found %s", results[params.Name], hashrate) + } + }) +} diff --git a/util/example_test.go b/util/example_test.go index 5bd50ab24..1cf615281 100644 --- a/util/example_test.go +++ b/util/example_test.go @@ -2,6 +2,7 @@ package util_test import ( "fmt" + "github.com/kaspanet/kaspad/util/difficulty" "math" "math/big" @@ -81,7 +82,7 @@ func ExampleAmount_unitConversions() { // the typical hex notation. func ExampleCompactToBig() { bits := uint32(419465580) - targetDifficulty := util.CompactToBig(bits) + targetDifficulty := difficulty.CompactToBig(bits) // Display it in hex. fmt.Printf("%064x\n", targetDifficulty.Bytes()) @@ -101,7 +102,7 @@ func ExampleBigToCompact() { fmt.Println("invalid target difficulty") return } - bits := util.BigToCompact(targetDifficulty) + bits := difficulty.BigToCompact(targetDifficulty) fmt.Println(bits) diff --git a/util/math/min_test.go b/util/math/min_test.go new file mode 100644 index 000000000..62d46f4d6 --- /dev/null +++ b/util/math/min_test.go @@ -0,0 +1,64 @@ +package math_test + +import ( + utilMath "github.com/kaspanet/kaspad/util/math" + "math" + "testing" +) + +const ( + MaxInt = int(^uint(0) >> 1) + MinInt = -MaxInt - 1 +) + +func TestMinInt(t *testing.T) { + tests := []struct { + inputs [2]int + expected int + }{ + {[2]int{MaxInt, 0}, 0}, + {[2]int{1, 2}, 1}, + {[2]int{MaxInt, MaxInt}, MaxInt}, + {[2]int{MaxInt, MaxInt - 1}, MaxInt - 1}, + {[2]int{MaxInt, MinInt}, MinInt}, + {[2]int{MinInt, 0}, MinInt}, + {[2]int{MinInt, MinInt}, MinInt}, + {[2]int{0, MinInt + 1}, MinInt + 1}, + {[2]int{0, MinInt}, MinInt}, + } + + for i, test := range tests { + result := utilMath.MinInt(test.inputs[0], test.inputs[1]) + if result != test.expected { + t.Fatalf("%d: Expected %d, instead found: %d", i, test.expected, result) + } + reverseResult := utilMath.MinInt(test.inputs[1], test.inputs[0]) + if result != reverseResult { + t.Fatalf("%d: Expected result and reverseResult to be the same, instead: %d!=%d", i, result, reverseResult) + } + } +} + +func TestMinUint32(t *testing.T) { + tests := []struct { + inputs [2]uint32 + expected uint32 + }{ + {[2]uint32{math.MaxUint32, 0}, 0}, + {[2]uint32{1, 2}, 1}, + {[2]uint32{math.MaxUint32, math.MaxUint32}, math.MaxUint32}, + {[2]uint32{math.MaxUint32, math.MaxUint32 - 1}, math.MaxUint32 - 1}, + } + + for _, test := range tests { + result := utilMath.MinUint32(test.inputs[0], test.inputs[1]) + if result != test.expected { + t.Fatalf("Expected %d, instead found: %d", test.expected, result) + + } + reverseResult := utilMath.MinUint32(test.inputs[1], test.inputs[0]) + if result != reverseResult { + t.Fatalf("Expected result and reverseResult to be the same, instead: %d!=%d", result, reverseResult) + } + } +} diff --git a/util/math_test.go b/util/math_test.go deleted file mode 100644 index 1cd6a0b86..000000000 --- a/util/math_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package util - -import ( - "testing" -) - -func TestFastLog2Floor(t *testing.T) { - tests := []struct { - n uint64 - expectedResult uint8 - }{ - {1, 0}, - {2, 1}, - {3, 1}, - {4, 2}, - {5, 2}, - {16, 4}, - {31, 4}, - {1684234, 20}, - {4294967295, 31}, // math.MaxUint32 (2^32 - 1) - {4294967296, 32}, // 2^32 - {4294967297, 32}, // 2^32 + 1 - {4611686018427387904, 62}, - {9223372036854775808, 63}, // 2^63 - {18446744073709551615, 63}, // math.MaxUint64 (2^64 - 1). - } - - for _, test := range tests { - actualResult := FastLog2Floor(test.n) - - if test.expectedResult != actualResult { - t.Errorf("TestFastLog2Floor: %d: expected result: %d but got: %d", test.n, test.expectedResult, actualResult) - } - } -} From 4988817da190472e11041de525cd1c8adfb3f29d Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 13 Jan 2021 15:04:55 +0200 Subject: [PATCH 246/351] Reject SubmitBlock if the node is in IBD (#1409) * Reject SubmitBlock if the node is in IBD * Add comments * Don't use iota for RejectReason constants, since in .proto those are hard-coded --- app/appmessage/rpc_submit_block.go | 24 +- app/protocol/manager.go | 5 + app/rpc/rpchandlers/submit_block.go | 14 +- cmd/kaspaminer/mineloop.go | 6 +- .../server/grpcserver/protowire/rpc.pb.go | 1472 +++++++++-------- .../server/grpcserver/protowire/rpc.proto | 6 + .../grpcserver/protowire/rpc_submit_block.go | 6 +- .../network/rpcclient/rpc_submit_block.go | 10 +- testing/integration/mining_test.go | 7 +- 9 files changed, 833 insertions(+), 717 deletions(-) diff --git a/app/appmessage/rpc_submit_block.go b/app/appmessage/rpc_submit_block.go index 9e221ed7c..02904b90f 100644 --- a/app/appmessage/rpc_submit_block.go +++ b/app/appmessage/rpc_submit_block.go @@ -19,11 +19,33 @@ func NewSubmitBlockRequestMessage(block *MsgBlock) *SubmitBlockRequestMessage { } } +// RejectReason describes the reason why a block sent by SubmitBlock was rejected +type RejectReason byte + +// RejectReason constants +// Not using iota, since in the .proto file those are hardcoded +const ( + RejectReasonNone RejectReason = 0 + RejectReasonBlockInvalid RejectReason = 1 + RejectReasonIsInIBD RejectReason = 2 +) + +var rejectReasonToString = map[RejectReason]string{ + RejectReasonNone: "None", + RejectReasonBlockInvalid: "Block is invalid", + RejectReasonIsInIBD: "Node is in IBD", +} + +func (rr RejectReason) String() string { + return rejectReasonToString[rr] +} + // SubmitBlockResponseMessage is an appmessage corresponding to // its respective RPC message type SubmitBlockResponseMessage struct { baseMessage - Error *RPCError + RejectReason RejectReason + Error *RPCError } // Command returns the protocol command string for the message diff --git a/app/protocol/manager.go b/app/protocol/manager.go index 102f3dcf0..f017c0413 100644 --- a/app/protocol/manager.go +++ b/app/protocol/manager.go @@ -79,3 +79,8 @@ func (m *Manager) SetOnTransactionAddedToMempoolHandler(onTransactionAddedToMemp func (m *Manager) ShouldMine() (bool, error) { return m.context.ShouldMine() } + +// IsIBDRunning returns true if IBD is currently marked as running +func (m *Manager) IsIBDRunning() bool { + return m.context.IsIBDRunning() +} diff --git a/app/rpc/rpchandlers/submit_block.go b/app/rpc/rpchandlers/submit_block.go index 45aca8806..475e2c00c 100644 --- a/app/rpc/rpchandlers/submit_block.go +++ b/app/rpc/rpchandlers/submit_block.go @@ -16,14 +16,22 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap msgBlock := submitBlockRequest.Block domainBlock := appmessage.MsgBlockToDomainBlock(msgBlock) + if context.ProtocolManager.IsIBDRunning() { + return &appmessage.SubmitBlockResponseMessage{ + Error: appmessage.RPCErrorf("Block not submitted - IBD is running"), + RejectReason: appmessage.RejectReasonIsInIBD, + }, nil + } + err := context.ProtocolManager.AddBlock(domainBlock) if err != nil { if !errors.As(err, &ruleerrors.RuleError{}) { return nil, err } - errorMessage := &appmessage.SubmitBlockResponseMessage{} - errorMessage.Error = appmessage.RPCErrorf("Block rejected. Reason: %s", err) - return errorMessage, nil + return &appmessage.SubmitBlockResponseMessage{ + Error: appmessage.RPCErrorf("Block rejected. Reason: %s", err), + RejectReason: appmessage.RejectReasonBlockInvalid, + }, nil } log.Infof("Accepted block %s via submitBlock", consensushashing.BlockHash(domainBlock)) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index bfa9f3e7d..6213a40e9 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -115,8 +115,12 @@ func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error blockHash := consensushashing.BlockHash(block) log.Infof("Found block %s with parents %s. Submitting to %s", blockHash, block.Header.ParentHashes(), client.Address()) - err := client.SubmitBlock(block) + rejectReason, err := client.SubmitBlock(block) if err != nil { + if rejectReason == appmessage.RejectReasonIsInIBD { + log.Warnf("Block %s was rejected because the node is in IBD", blockHash) + return nil + } return errors.Errorf("Error submitting block %s to %s: %s", blockHash, client.Address(), err) } return nil diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 097751b97..7aa17abad 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -35,6 +35,55 @@ const ( // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 +type SubmitBlockResponseMessage_RejectReason int32 + +const ( + SubmitBlockResponseMessage_NONE SubmitBlockResponseMessage_RejectReason = 0 + SubmitBlockResponseMessage_BLOCK_INVALID SubmitBlockResponseMessage_RejectReason = 1 + SubmitBlockResponseMessage_IS_IN_IBD SubmitBlockResponseMessage_RejectReason = 2 +) + +// Enum value maps for SubmitBlockResponseMessage_RejectReason. +var ( + SubmitBlockResponseMessage_RejectReason_name = map[int32]string{ + 0: "NONE", + 1: "BLOCK_INVALID", + 2: "IS_IN_IBD", + } + SubmitBlockResponseMessage_RejectReason_value = map[string]int32{ + "NONE": 0, + "BLOCK_INVALID": 1, + "IS_IN_IBD": 2, + } +) + +func (x SubmitBlockResponseMessage_RejectReason) Enum() *SubmitBlockResponseMessage_RejectReason { + p := new(SubmitBlockResponseMessage_RejectReason) + *p = x + return p +} + +func (x SubmitBlockResponseMessage_RejectReason) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SubmitBlockResponseMessage_RejectReason) Descriptor() protoreflect.EnumDescriptor { + return file_rpc_proto_enumTypes[0].Descriptor() +} + +func (SubmitBlockResponseMessage_RejectReason) Type() protoreflect.EnumType { + return &file_rpc_proto_enumTypes[0] +} + +func (x SubmitBlockResponseMessage_RejectReason) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SubmitBlockResponseMessage_RejectReason.Descriptor instead. +func (SubmitBlockResponseMessage_RejectReason) EnumDescriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{4, 0} +} + // RPCError represents a generic non-internal error. // // Receivers of any ResponseMessage are expected to check whether its error field is not null. @@ -237,7 +286,8 @@ type SubmitBlockResponseMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` + RejectReason SubmitBlockResponseMessage_RejectReason `protobuf:"varint,1,opt,name=rejectReason,proto3,enum=protowire.SubmitBlockResponseMessage_RejectReason" json:"rejectReason,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } func (x *SubmitBlockResponseMessage) Reset() { @@ -272,6 +322,13 @@ func (*SubmitBlockResponseMessage) Descriptor() ([]byte, []int) { return file_rpc_proto_rawDescGZIP(), []int{4} } +func (x *SubmitBlockResponseMessage) GetRejectReason() SubmitBlockResponseMessage_RejectReason { + if x != nil { + return x.RejectReason + } + return SubmitBlockResponseMessage_NONE +} + func (x *SubmitBlockResponseMessage) GetError() *RPCError { if x != nil { return x.Error @@ -4495,583 +4552,592 @@ var file_rpc_proto_rawDesc = []byte{ 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x48, - 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x40, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x1f, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, - 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, - 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, - 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, - 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, - 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 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, 0x39, - 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, - 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, - 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, - 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xdc, + 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x56, 0x0a, + 0x0c, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0c, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, - 0x66, 0x65, 0x65, 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, 0x02, 0x20, - 0x01, 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, 0x22, 0x24, - 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, - 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xd3, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, - 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, - 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, - 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, - 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x1c, - 0x0a, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, 0x22, 0x53, 0x0a, 0x15, - 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, - 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 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, 0x37, 0x0a, - 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 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, 0xb3, 0x01, 0x0a, - 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, - 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, - 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, - 0x0d, 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, 0x92, - 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 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, 0x22, - 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, + 0x72, 0x22, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x42, + 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x01, 0x12, 0x0d, + 0x0a, 0x09, 0x49, 0x53, 0x5f, 0x49, 0x4e, 0x5f, 0x49, 0x42, 0x44, 0x10, 0x02, 0x22, 0x40, 0x0a, + 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0xa6, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 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, 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, + 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x20, 0x0a, 0x1e, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4d, 0x0a, 0x1f, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, + 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, + 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, + 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, + 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, + 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 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, 0x33, 0x0a, + 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, + 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, + 0x74, 0x72, 0x79, 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, + 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xd3, 0x02, 0x0a, 0x1b, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, + 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, + 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, + 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, + 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, + 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, + 0x72, 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, 0x5e, 0x0a, 0x1f, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, + 0x72, 0x22, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, + 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 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, 0x95, 0x01, - 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, - 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, - 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, - 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, - 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, - 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, - 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, - 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, + 0x22, 0xdb, 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, 0x0d, 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, 0x12, 0x22, 0x0a, 0x0c, + 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, + 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 0x0d, 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, 0x92, 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, 0x4a, 0x0a, 0x0f, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x31, - 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, + 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x54, + 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 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, 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, - 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 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, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, + 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, 0x22, + 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, + 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, + 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, + 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, + 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, + 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, + 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, + 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 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, 0x82, 0x01, 0x0a, 0x38, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 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 ( @@ -5086,149 +5152,152 @@ func file_rpc_proto_rawDescGZIP() []byte { return file_rpc_proto_rawDescData } +var file_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 77) var file_rpc_proto_goTypes = []interface{}{ - (*RPCError)(nil), // 0: protowire.RPCError - (*GetCurrentNetworkRequestMessage)(nil), // 1: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 2: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 3: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 4: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 5: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 6: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 7: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 8: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 9: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 10: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 11: protowire.GetPeerAddressesResponseMessage - (*GetPeerAddressesKnownAddressMessage)(nil), // 12: protowire.GetPeerAddressesKnownAddressMessage - (*GetSelectedTipHashRequestMessage)(nil), // 13: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 14: protowire.GetSelectedTipHashResponseMessage - (*GetMempoolEntryRequestMessage)(nil), // 15: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 16: protowire.GetMempoolEntryResponseMessage - (*GetMempoolEntriesRequestMessage)(nil), // 17: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 18: protowire.GetMempoolEntriesResponseMessage - (*MempoolEntry)(nil), // 19: protowire.MempoolEntry - (*GetConnectedPeerInfoRequestMessage)(nil), // 20: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 21: protowire.GetConnectedPeerInfoResponseMessage - (*GetConnectedPeerInfoMessage)(nil), // 22: protowire.GetConnectedPeerInfoMessage - (*AddPeerRequestMessage)(nil), // 23: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 24: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 25: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 26: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 27: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 28: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 29: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*ChainBlock)(nil), // 30: protowire.ChainBlock - (*AcceptedBlock)(nil), // 31: protowire.AcceptedBlock - (*GetBlockRequestMessage)(nil), // 32: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 33: protowire.GetBlockResponseMessage - (*BlockVerboseData)(nil), // 34: protowire.BlockVerboseData - (*TransactionVerboseData)(nil), // 35: protowire.TransactionVerboseData - (*TransactionVerboseInput)(nil), // 36: protowire.TransactionVerboseInput - (*ScriptSig)(nil), // 37: protowire.ScriptSig - (*TransactionVerboseOutput)(nil), // 38: protowire.TransactionVerboseOutput - (*ScriptPublicKeyResult)(nil), // 39: protowire.ScriptPublicKeyResult - (*GetSubnetworkRequestMessage)(nil), // 40: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 41: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 42: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 43: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 44: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 45: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 46: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 47: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 48: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 49: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 50: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 51: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 52: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 53: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 54: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 55: protowire.FinalityConflictResolvedNotificationMessage - (*ShutDownRequestMessage)(nil), // 56: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 57: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 58: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 59: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 60: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 61: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 62: protowire.UtxosChangedNotificationMessage - (*UtxosByAddressesEntry)(nil), // 63: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 64: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 65: protowire.RpcTransactionInput - (*RpcScriptPublicKey)(nil), // 66: protowire.RpcScriptPublicKey - (*RpcTransactionOutput)(nil), // 67: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 68: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 69: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 70: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 71: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 72: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 73: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 74: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 75: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 76: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - (*BlockMessage)(nil), // 77: protowire.BlockMessage + (SubmitBlockResponseMessage_RejectReason)(0), // 0: protowire.SubmitBlockResponseMessage.RejectReason + (*RPCError)(nil), // 1: protowire.RPCError + (*GetCurrentNetworkRequestMessage)(nil), // 2: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 3: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 4: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 5: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 6: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 7: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 8: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 9: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 10: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 11: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 12: protowire.GetPeerAddressesResponseMessage + (*GetPeerAddressesKnownAddressMessage)(nil), // 13: protowire.GetPeerAddressesKnownAddressMessage + (*GetSelectedTipHashRequestMessage)(nil), // 14: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 15: protowire.GetSelectedTipHashResponseMessage + (*GetMempoolEntryRequestMessage)(nil), // 16: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 17: protowire.GetMempoolEntryResponseMessage + (*GetMempoolEntriesRequestMessage)(nil), // 18: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 19: protowire.GetMempoolEntriesResponseMessage + (*MempoolEntry)(nil), // 20: protowire.MempoolEntry + (*GetConnectedPeerInfoRequestMessage)(nil), // 21: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 22: protowire.GetConnectedPeerInfoResponseMessage + (*GetConnectedPeerInfoMessage)(nil), // 23: protowire.GetConnectedPeerInfoMessage + (*AddPeerRequestMessage)(nil), // 24: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 25: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 26: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 27: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 28: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 29: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 30: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*ChainBlock)(nil), // 31: protowire.ChainBlock + (*AcceptedBlock)(nil), // 32: protowire.AcceptedBlock + (*GetBlockRequestMessage)(nil), // 33: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 34: protowire.GetBlockResponseMessage + (*BlockVerboseData)(nil), // 35: protowire.BlockVerboseData + (*TransactionVerboseData)(nil), // 36: protowire.TransactionVerboseData + (*TransactionVerboseInput)(nil), // 37: protowire.TransactionVerboseInput + (*ScriptSig)(nil), // 38: protowire.ScriptSig + (*TransactionVerboseOutput)(nil), // 39: protowire.TransactionVerboseOutput + (*ScriptPublicKeyResult)(nil), // 40: protowire.ScriptPublicKeyResult + (*GetSubnetworkRequestMessage)(nil), // 41: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 42: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 43: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 44: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 45: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 46: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 47: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 48: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 49: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 50: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 51: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 52: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 53: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 54: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 55: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 56: protowire.FinalityConflictResolvedNotificationMessage + (*ShutDownRequestMessage)(nil), // 57: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 58: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 59: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 60: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 61: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 62: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 63: protowire.UtxosChangedNotificationMessage + (*UtxosByAddressesEntry)(nil), // 64: protowire.UtxosByAddressesEntry + (*RpcTransaction)(nil), // 65: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 66: protowire.RpcTransactionInput + (*RpcScriptPublicKey)(nil), // 67: protowire.RpcScriptPublicKey + (*RpcTransactionOutput)(nil), // 68: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 69: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 70: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 71: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 72: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 73: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 74: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 75: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 76: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 77: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*BlockMessage)(nil), // 78: protowire.BlockMessage } var file_rpc_proto_depIdxs = []int32{ - 0, // 0: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 77, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage - 0, // 2: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 77, // 3: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage - 0, // 4: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError - 0, // 5: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 77, // 6: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 12, // 7: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 12, // 8: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 0, // 9: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 0, // 10: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 19, // 11: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 0, // 12: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 19, // 13: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 0, // 14: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 35, // 15: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 22, // 16: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 0, // 17: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 0, // 18: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 64, // 19: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 0, // 20: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 0, // 21: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 30, // 22: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 31, // 23: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 34, // 24: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 0, // 25: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 35, // 26: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 36, // 27: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 38, // 28: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 37, // 29: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 39, // 30: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult - 0, // 31: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 30, // 32: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 0, // 33: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 34, // 34: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 0, // 35: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 0, // 36: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 0, // 37: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 0, // 38: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 0, // 39: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 0, // 40: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 0, // 41: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 0, // 42: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 63, // 43: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 63, // 44: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 68, // 45: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 69, // 46: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 65, // 47: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 67, // 48: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 68, // 49: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 66, // 50: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 66, // 51: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 63, // 52: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 0, // 53: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 0, // 54: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 0, // 55: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 56, // [56:56] is the sub-list for method output_type - 56, // [56:56] is the sub-list for method input_type - 56, // [56:56] is the sub-list for extension type_name - 56, // [56:56] is the sub-list for extension extendee - 0, // [0:56] is the sub-list for field type_name + 1, // 0: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError + 78, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 0, // 2: protowire.SubmitBlockResponseMessage.rejectReason:type_name -> protowire.SubmitBlockResponseMessage.RejectReason + 1, // 3: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError + 78, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 1, // 5: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError + 1, // 6: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError + 78, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 13, // 8: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 13, // 9: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 1, // 10: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 1, // 11: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 20, // 12: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 1, // 13: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 20, // 14: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 1, // 15: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 36, // 16: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 23, // 17: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 1, // 18: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 1, // 19: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 65, // 20: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 1, // 21: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 1, // 22: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 31, // 23: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 32, // 24: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 35, // 25: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 1, // 26: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 36, // 27: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 37, // 28: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 39, // 29: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 38, // 30: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 40, // 31: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult + 1, // 32: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 31, // 33: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 1, // 34: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 35, // 35: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 1, // 36: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 1, // 37: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 1, // 38: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 1, // 39: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 1, // 40: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 1, // 41: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 1, // 42: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 1, // 43: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 64, // 44: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 64, // 45: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 69, // 46: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 70, // 47: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 66, // 48: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 68, // 49: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 69, // 50: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 67, // 51: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 67, // 52: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 64, // 53: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 1, // 54: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 1, // 55: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 1, // 56: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 57, // [57:57] is the sub-list for method output_type + 57, // [57:57] is the sub-list for method input_type + 57, // [57:57] is the sub-list for extension type_name + 57, // [57:57] is the sub-list for extension extendee + 0, // [0:57] is the sub-list for field type_name } func init() { file_rpc_proto_init() } @@ -6168,13 +6237,14 @@ func file_rpc_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_proto_rawDesc, - NumEnums: 0, + NumEnums: 1, NumMessages: 77, NumExtensions: 0, NumServices: 0, }, GoTypes: file_rpc_proto_goTypes, DependencyIndexes: file_rpc_proto_depIdxs, + EnumInfos: file_rpc_proto_enumTypes, MessageInfos: file_rpc_proto_msgTypes, }.Build() File_rpc_proto = out.File diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index 9f8176ad3..290d8f135 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -41,6 +41,12 @@ message SubmitBlockRequestMessage{ } message SubmitBlockResponseMessage{ + enum RejectReason { + NONE = 0; + BLOCK_INVALID = 1; + IS_IN_IBD = 2; + } + RejectReason rejectReason = 1; RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go index 13d7ff9c1..d25049d45 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_submit_block.go @@ -24,7 +24,8 @@ func (x *KaspadMessage_SubmitBlockResponse) toAppMessage() (appmessage.Message, err = &appmessage.RPCError{Message: x.SubmitBlockResponse.Error.Message} } return &appmessage.SubmitBlockResponseMessage{ - Error: err, + RejectReason: appmessage.RejectReason(x.SubmitBlockResponse.RejectReason), + Error: err, }, nil } @@ -34,7 +35,8 @@ func (x *KaspadMessage_SubmitBlockResponse) fromAppMessage(message *appmessage.S err = &RPCError{Message: message.Error.Message} } x.SubmitBlockResponse = &SubmitBlockResponseMessage{ - Error: err, + RejectReason: SubmitBlockResponseMessage_RejectReason(message.RejectReason), + Error: err, } return nil } diff --git a/infrastructure/network/rpcclient/rpc_submit_block.go b/infrastructure/network/rpcclient/rpc_submit_block.go index 303fda5ae..c707fac7c 100644 --- a/infrastructure/network/rpcclient/rpc_submit_block.go +++ b/infrastructure/network/rpcclient/rpc_submit_block.go @@ -6,19 +6,19 @@ import ( ) // SubmitBlock sends an RPC request respective to the function's name and returns the RPC server's response -func (c *RPCClient) SubmitBlock(block *externalapi.DomainBlock) error { +func (c *RPCClient) SubmitBlock(block *externalapi.DomainBlock) (appmessage.RejectReason, error) { err := c.rpcRouter.outgoingRoute().Enqueue( appmessage.NewSubmitBlockRequestMessage(appmessage.DomainBlockToMsgBlock(block))) if err != nil { - return err + return appmessage.RejectReasonNone, err } response, err := c.route(appmessage.CmdSubmitBlockResponseMessage).DequeueWithTimeout(c.timeout) if err != nil { - return err + return appmessage.RejectReasonNone, err } submitBlockResponse := response.(*appmessage.SubmitBlockResponseMessage) if submitBlockResponse.Error != nil { - return c.convertRPCError(submitBlockResponse.Error) + return submitBlockResponse.RejectReason, c.convertRPCError(submitBlockResponse.Error) } - return nil + return appmessage.RejectReasonNone, nil } diff --git a/testing/integration/mining_test.go b/testing/integration/mining_test.go index 62849ee15..75addaead 100644 --- a/testing/integration/mining_test.go +++ b/testing/integration/mining_test.go @@ -1,14 +1,13 @@ package integration import ( - "github.com/kaspanet/kaspad/domain/consensus/model/pow" - "github.com/kaspanet/kaspad/util/difficulty" "math/rand" "testing" "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/util/difficulty" ) func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock { @@ -36,7 +35,7 @@ func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock { solveBlock(block) - err = harness.rpcClient.SubmitBlock(block) + _, err = harness.rpcClient.SubmitBlock(block) if err != nil { t.Fatalf("Error submitting block: %s", err) } From 83134cc2b515e66b547fee181c0d852a6086a1a4 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 13 Jan 2021 15:57:57 +0200 Subject: [PATCH 247/351] Add a codecov yml, disable patch checks and make status checks always pass (#1414) --- .codecov.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .codecov.yml diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..483eab35b --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,7 @@ +coverage: + status: + patch: off + + project: + default: + informational: true From 61be80a60ca4dd32c1da0d325efddd4ea6d09666 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 13 Jan 2021 16:19:52 +0200 Subject: [PATCH 248/351] Add TestCheckMergeSizeLimit (#1408) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- .../blockvalidator/block_header_in_context.go | 2 +- .../block_header_in_context_test.go | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index dccc30b95..3ce16882f 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -134,7 +134,7 @@ func (v *blockValidator) checkMergeSizeLimit(hash *externalapi.DomainHash) error return err } - mergeSetSize := len(ghostdagData.MergeSetReds()) + len(ghostdagData.MergeSetBlues()) + mergeSetSize := len(ghostdagData.MergeSet()) if uint64(mergeSetSize) > v.mergeSetSizeLimit { return errors.Wrapf(ruleerrors.ErrViolatingMergeLimit, diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go index 5e2f77c46..104d96657 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context_test.go @@ -153,3 +153,36 @@ func TestCheckParentsIncest(t *testing.T) { } }) } + +func TestCheckMergeSizeLimit(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.MergeSetSizeLimit = 2 * uint64(params.K) + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentsIncest") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + chain1TipHash := params.GenesisHash + for i := uint64(0); i < params.MergeSetSizeLimit+2; i++ { + chain1TipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1TipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + } + + chain2TipHash := params.GenesisHash + for i := uint64(0); i < params.MergeSetSizeLimit+1; i++ { + chain2TipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chain2TipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + } + + _, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1TipHash, chain2TipHash}, nil, nil) + if !errors.Is(err, ruleerrors.ErrViolatingMergeLimit) { + t.Fatalf("unexpected error: %+v", err) + } + }) +} From 1b97cfb3026cb8262686285a1f4f6df7c2fc45ad Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 13 Jan 2021 17:55:37 +0200 Subject: [PATCH 249/351] Prevent a race condition in findHighestSharedBlockHash where we get headersSelectedTip and then pass it as highHash to GetBlockLocator, without locking consensus (#1410) * Prevent a race condition in findHighestSharedBlockHash where we get headersSelectedTip and then pass it as highHash to GetBlockLocator, without locking consensus * Restart findHighestSharedBlockHash if lowHash or highHash are no longer in selectedParentChain * Test for specifically ErrBlockNotInSelectedParentChain instead of database NotFound error * Fix TestCreateHeadersSelectedChainBlockLocator Co-authored-by: Ori Newman --- app/protocol/flows/blockrelay/ibd.go | 130 +++++++++++------- domain/consensus/consensus.go | 20 ++- domain/consensus/model/errors.go | 7 + .../consensus/model/externalapi/consensus.go | 1 + .../processes/syncmanager/blocklocator.go | 10 ++ .../syncmanager/blocklocator_test.go | 8 +- 6 files changed, 125 insertions(+), 51 deletions(-) create mode 100644 domain/consensus/model/errors.go diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 2eac07659..55103639f 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -3,6 +3,8 @@ package blockrelay import ( "time" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/common" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" @@ -120,59 +122,28 @@ func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) e } func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - lowHash, err := flow.Domain().Consensus().PruningPoint() - if err != nil { - return nil, err - } - highHash, err := flow.Domain().Consensus().GetHeadersSelectedTip() + log.Debugf("Sending a blockLocator to %s between pruning point and headers selected tip", flow.peer) + blockLocator, err := flow.Domain().Consensus().CreateFullHeadersSelectedChainBlockLocator() if err != nil { return nil, err } - for !lowHash.Equal(highHash) { - log.Debugf("Sending a blockLocator to %s between %s and %s", flow.peer, lowHash, highHash) - blockLocator, err := flow.Domain().Consensus().CreateHeadersSelectedChainBlockLocator(lowHash, highHash) + for { + highestHash, err := flow.fetchHighestHash(targetHash, blockLocator) + if err != nil { + return nil, err + } + highestHashIndex, err := flow.findHighestHashIndex(highestHash, blockLocator) if err != nil { return nil, err } - ibdBlockLocatorMessage := appmessage.NewMsgIBDBlockLocator(targetHash, blockLocator) - err = flow.outgoingRoute.Enqueue(ibdBlockLocatorMessage) - if err != nil { - return nil, err - } - message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) - if err != nil { - return nil, err - } - ibdBlockLocatorHighestHashMessage, ok := message.(*appmessage.MsgIBDBlockLocatorHighestHash) - if !ok { - return nil, protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdIBDBlockLocatorHighestHash, message.Command()) - } - highestHash := ibdBlockLocatorHighestHashMessage.HighestHash - log.Debugf("The highest hash the peer %s knows is %s", flow.peer, highestHash) + if highestHashIndex == 0 || + // If the block locator contains only two adjacent chain blocks, the + // syncer will always find the same highest chain block, so to avoid + // an endless loop, we explicitly stop the loop in such situation. + (len(blockLocator) == 2 && highestHashIndex == 1) { - highestHashIndex := 0 - highestHashIndexFound := false - for i, blockLocatorHash := range blockLocator { - if highestHash.Equal(blockLocatorHash) { - highestHashIndex = i - highestHashIndexFound = true - break - } - } - if !highestHashIndexFound { - return nil, protocolerrors.Errorf(true, "highest hash %s "+ - "returned from peer %s is not in the original blockLocator", highestHash, flow.peer) - } - log.Debugf("The index of the highest hash in the original "+ - "blockLocator sent to %s is %d", flow.peer, highestHashIndex) - - // If the block locator contains only two adjacent chain blocks, the - // syncer will always find the same highest chain block, so to avoid - // an endless loop, we explicitly stop the loop in such situation. - if len(blockLocator) == 2 && highestHashIndex == 1 { return highestHash, nil } @@ -180,10 +151,75 @@ func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *external if highestHashIndex > 0 { locatorHashAboveHighestHash = blockLocator[highestHashIndex-1] } - highHash = locatorHashAboveHighestHash - lowHash = highestHash + + blockLocator, err = flow.nextBlockLocator(highestHash, locatorHashAboveHighestHash) + if err != nil { + return nil, err + } } - return highHash, nil +} + +func (flow *handleRelayInvsFlow) nextBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + log.Debugf("Sending a blockLocator to %s between %s and %s", flow.peer, lowHash, highHash) + blockLocator, err := flow.Domain().Consensus().CreateHeadersSelectedChainBlockLocator(lowHash, highHash) + if err != nil { + if errors.Is(model.ErrBlockNotInSelectedParentChain, err) { + return nil, err + } + log.Debugf("Headers selected parent chain moved since findHighestSharedBlockHash - " + + "restarting with full block locator") + blockLocator, err = flow.Domain().Consensus().CreateFullHeadersSelectedChainBlockLocator() + if err != nil { + return nil, err + } + } + + return blockLocator, nil +} + +func (flow *handleRelayInvsFlow) findHighestHashIndex( + highestHash *externalapi.DomainHash, blockLocator externalapi.BlockLocator) (int, error) { + + highestHashIndex := 0 + highestHashIndexFound := false + for i, blockLocatorHash := range blockLocator { + if highestHash.Equal(blockLocatorHash) { + highestHashIndex = i + highestHashIndexFound = true + break + } + } + if !highestHashIndexFound { + return 0, protocolerrors.Errorf(true, "highest hash %s "+ + "returned from peer %s is not in the original blockLocator", highestHash, flow.peer) + } + log.Debugf("The index of the highest hash in the original "+ + "blockLocator sent to %s is %d", flow.peer, highestHashIndex) + + return highestHashIndex, nil +} + +func (flow *handleRelayInvsFlow) fetchHighestHash( + targetHash *externalapi.DomainHash, blockLocator externalapi.BlockLocator) (*externalapi.DomainHash, error) { + + ibdBlockLocatorMessage := appmessage.NewMsgIBDBlockLocator(targetHash, blockLocator) + err := flow.outgoingRoute.Enqueue(ibdBlockLocatorMessage) + if err != nil { + return nil, err + } + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return nil, err + } + ibdBlockLocatorHighestHashMessage, ok := message.(*appmessage.MsgIBDBlockLocatorHighestHash) + if !ok { + return nil, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDBlockLocatorHighestHash, message.Command()) + } + highestHash := ibdBlockLocatorHighestHashMessage.HighestHash + log.Debugf("The highest hash the peer %s knows is %s", flow.peer, highestHash) + + return highestHash, nil } func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash, diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 9d7bf67d6..20f811760 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -1,9 +1,10 @@ package consensus import ( - "github.com/kaspanet/kaspad/infrastructure/db/database" "sync" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -298,6 +299,23 @@ func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash return s.syncManager.CreateBlockLocator(lowHash, highHash, limit) } +func (s *consensus) CreateFullHeadersSelectedChainBlockLocator() (externalapi.BlockLocator, error) { + s.lock.Lock() + defer s.lock.Unlock() + + lowHash, err := s.pruningStore.PruningPoint(s.databaseContext) + if err != nil { + return nil, err + } + + highHash, err := s.headersSelectedTipStore.HeadersSelectedTip(s.databaseContext) + if err != nil { + return nil, err + } + + return s.syncManager.CreateHeadersSelectedChainBlockLocator(lowHash, highHash) +} + func (s *consensus) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { s.lock.Lock() diff --git a/domain/consensus/model/errors.go b/domain/consensus/model/errors.go new file mode 100644 index 000000000..a8d4a009e --- /dev/null +++ b/domain/consensus/model/errors.go @@ -0,0 +1,7 @@ +package model + +import "github.com/pkg/errors" + +// ErrBlockNotInSelectedParentChain is returned from CreateHeadersSelectedChainBlockLocator if one of the parameters +// passed to it are not in the headers selected parent chain +var ErrBlockNotInSelectedParentChain = errors.New("Block is not in selected parent chain") diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index cce6c9b5e..b4696a7d8 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -19,6 +19,7 @@ type Consensus interface { GetVirtualSelectedParent() (*DomainHash, error) CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) + CreateFullHeadersSelectedChainBlockLocator() (BlockLocator, error) GetSyncInfo() (*SyncInfo, error) Tips() ([]*DomainHash, error) GetVirtualInfo() (*VirtualInfo, error) diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index 56ddc3b56..aaa205fad 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -1,7 +1,9 @@ package syncmanager import ( + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" ) @@ -74,11 +76,19 @@ func (sm *syncManager) createHeadersSelectedChainBlockLocator(lowHash, lowHashIndex, err := sm.headersSelectedChainStore.GetIndexByHash(sm.databaseContext, lowHash) if err != nil { + if database.IsNotFoundError(err) { + return nil, errors.Wrapf(model.ErrBlockNotInSelectedParentChain, + "LowHash %s is not in selected parent chain", lowHash) + } return nil, err } highHashIndex, err := sm.headersSelectedChainStore.GetIndexByHash(sm.databaseContext, highHash) if err != nil { + if database.IsNotFoundError(err) { + return nil, errors.Wrapf(model.ErrBlockNotInSelectedParentChain, + "LowHash %s is not in selected parent chain", lowHash) + } return nil, err } diff --git a/domain/consensus/processes/syncmanager/blocklocator_test.go b/domain/consensus/processes/syncmanager/blocklocator_test.go index 6a6276626..8d3e93702 100644 --- a/domain/consensus/processes/syncmanager/blocklocator_test.go +++ b/domain/consensus/processes/syncmanager/blocklocator_test.go @@ -1,14 +1,16 @@ package syncmanager_test import ( + "strings" + "testing" + "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" "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" - "strings" - "testing" ) func TestCreateBlockLocator(t *testing.T) { @@ -224,7 +226,7 @@ func TestCreateHeadersSelectedChainBlockLocator(t *testing.T) { // Check block locator with non chain blocks _, err = tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, sideChainTipHash) - if !errors.Is(err, database.ErrNotFound) { + if !errors.Is(err, model.ErrBlockNotInSelectedParentChain) { t.Fatalf("expected error '%s' but got '%s'", database.ErrNotFound, err) } }) From 15af6641fc456fdf9020cbaf4c04216165e8b932 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 13 Jan 2021 18:03:07 +0200 Subject: [PATCH 250/351] Send the IBD root UTXO set in chunks instead of a massive monolythic message (#1412) * Extract syncPruningPointUTXOSet to a separate method. * Implement logic to send pruning point utxo set chunks in a loop. * Replace IBDRootUTXOSetAndBlockMessage with IbdRootUtxoSetChunkMessage. * Add a new message: RequestNextIBDRootUTXOSetChunk. * Add a new message: DoneIBDRootUTXOSetChunks. * Protect HandleRequestIBDRootUTXOSetAndBlock from rogue messages. * Reimplement receiveIBDRootUTXOSetAndBlock. * Add CmdDoneIBDRootUTXOSetChunks to the HandleRelayInvs flow. * Decrease the max message size to 10mb. * Fix bad step. * Fix confusion between outgoing/incoming routes. * Measure how long it takes to send/receive the UTXO set. * Use LogAndMeasure in handleRequestIBDRootUTXOSetAndBlockFlow. --- app/appmessage/message.go | 66 +- .../p2p_msgdoneibdrootutxosetchunks.go | 16 + .../p2p_msgibdrootutxosetandblock.go | 23 - app/appmessage/p2p_msgibdrootutxosetchunk.go | 19 + .../p2p_msgrequestnextibdrootutxosetchunk.go | 16 + ...dle_request_ibd_root_utxo_set_and_block.go | 62 +- app/protocol/flows/blockrelay/ibd.go | 163 ++- app/protocol/protocol.go | 8 +- .../server/grpcserver/grpc_server.go | 2 +- .../grpcserver/protowire/messages.pb.go | 1234 +++++++++-------- .../grpcserver/protowire/messages.proto | 4 +- .../server/grpcserver/protowire/p2p.pb.go | 395 +++--- .../server/grpcserver/protowire/p2p.proto | 65 +- .../p2p_done_ibd_root_utxo_set_chunks.go | 12 + .../p2p_ibd_root_utxo_set_and_block.go | 21 - .../protowire/p2p_ibd_root_utxo_set_chunk.go | 16 + ...2p_request_next_ibd_root_utxo_set_chunk.go | 12 + .../server/grpcserver/protowire/wire.go | 18 +- 18 files changed, 1193 insertions(+), 959 deletions(-) create mode 100644 app/appmessage/p2p_msgdoneibdrootutxosetchunks.go delete mode 100644 app/appmessage/p2p_msgibdrootutxosetandblock.go create mode 100644 app/appmessage/p2p_msgibdrootutxosetchunk.go create mode 100644 app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 5fb26ad4f..de92b3fe7 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -52,7 +52,7 @@ const ( CmdHeader CmdRequestNextHeaders CmdRequestIBDRootUTXOSetAndBlock - CmdIBDRootUTXOSetAndBlock + CmdIBDRootUTXOSetChunk CmdRequestIBDBlocks CmdIBDRootNotFound CmdRequestIBDRootHash @@ -60,6 +60,8 @@ const ( CmdIBDBlockLocator CmdIBDBlockLocatorHighestHash CmdBlockHeaders + CmdRequestNextIBDRootUTXOSetChunk + CmdDoneIBDRootUTXOSetChunks // rpc CmdGetCurrentNetworkRequestMessage @@ -125,36 +127,38 @@ const ( // ProtocolMessageCommandToString maps all MessageCommands to their string representation var ProtocolMessageCommandToString = map[MessageCommand]string{ - CmdVersion: "Version", - CmdVerAck: "VerAck", - CmdRequestAddresses: "RequestAddresses", - CmdAddresses: "Addresses", - CmdRequestHeaders: "RequestHeaders", - CmdBlock: "Block", - CmdTx: "Tx", - CmdPing: "Ping", - CmdPong: "Pong", - CmdRequestBlockLocator: "RequestBlockLocator", - CmdBlockLocator: "BlockLocator", - CmdInvRelayBlock: "InvRelayBlock", - CmdRequestRelayBlocks: "RequestRelayBlocks", - CmdInvTransaction: "InvTransaction", - CmdRequestTransactions: "RequestTransactions", - CmdIBDBlock: "IBDBlock", - CmdDoneHeaders: "DoneHeaders", - CmdTransactionNotFound: "TransactionNotFound", - CmdReject: "Reject", - CmdHeader: "Header", - CmdRequestNextHeaders: "RequestNextHeaders", - CmdRequestIBDRootUTXOSetAndBlock: "RequestPruningUTXOSetAndBlock", - CmdIBDRootUTXOSetAndBlock: "IBDRootUTXOSetAndBlock", - CmdRequestIBDBlocks: "RequestIBDBlocks", - CmdIBDRootNotFound: "IBDRootNotFound", - CmdRequestIBDRootHash: "IBDRequestIBDRootHash", - CmdIBDRootHash: "IBDIBDRootHash", - CmdIBDBlockLocator: "IBDBlockLocator", - CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", - CmdBlockHeaders: "BlockHeaders", + CmdVersion: "Version", + CmdVerAck: "VerAck", + CmdRequestAddresses: "RequestAddresses", + CmdAddresses: "Addresses", + CmdRequestHeaders: "RequestHeaders", + CmdBlock: "Block", + CmdTx: "Tx", + CmdPing: "Ping", + CmdPong: "Pong", + CmdRequestBlockLocator: "RequestBlockLocator", + CmdBlockLocator: "BlockLocator", + CmdInvRelayBlock: "InvRelayBlock", + CmdRequestRelayBlocks: "RequestRelayBlocks", + CmdInvTransaction: "InvTransaction", + CmdRequestTransactions: "RequestTransactions", + CmdIBDBlock: "IBDBlock", + CmdDoneHeaders: "DoneHeaders", + CmdTransactionNotFound: "TransactionNotFound", + CmdReject: "Reject", + CmdHeader: "Header", + CmdRequestNextHeaders: "RequestNextHeaders", + CmdRequestIBDRootUTXOSetAndBlock: "RequestPruningUTXOSetAndBlock", + CmdIBDRootUTXOSetChunk: "IBDRootUTXOSetChunk", + CmdRequestIBDBlocks: "RequestIBDBlocks", + CmdIBDRootNotFound: "IBDRootNotFound", + CmdRequestIBDRootHash: "IBDRequestIBDRootHash", + CmdIBDRootHash: "IBDIBDRootHash", + CmdIBDBlockLocator: "IBDBlockLocator", + CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", + CmdBlockHeaders: "BlockHeaders", + CmdRequestNextIBDRootUTXOSetChunk: "RequestNextIBDRootUTXOSetChunk", + CmdDoneIBDRootUTXOSetChunks: "DoneIBDRootUTXOSetChunks", } // RPCMessageCommandToString maps all MessageCommands to their string representation diff --git a/app/appmessage/p2p_msgdoneibdrootutxosetchunks.go b/app/appmessage/p2p_msgdoneibdrootutxosetchunks.go new file mode 100644 index 000000000..32760c48a --- /dev/null +++ b/app/appmessage/p2p_msgdoneibdrootutxosetchunks.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgDoneIBDRootUTXOSetChunks represents a kaspa DoneIBDRootUTXOSetChunks message +type MsgDoneIBDRootUTXOSetChunks struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgDoneIBDRootUTXOSetChunks) Command() MessageCommand { + return CmdDoneIBDRootUTXOSetChunks +} + +// NewMsgDoneIBDRootUTXOSetChunks returns a new MsgDoneIBDRootUTXOSetChunks. +func NewMsgDoneIBDRootUTXOSetChunks() *MsgDoneIBDRootUTXOSetChunks { + return &MsgDoneIBDRootUTXOSetChunks{} +} diff --git a/app/appmessage/p2p_msgibdrootutxosetandblock.go b/app/appmessage/p2p_msgibdrootutxosetandblock.go deleted file mode 100644 index d1d1d28a8..000000000 --- a/app/appmessage/p2p_msgibdrootutxosetandblock.go +++ /dev/null @@ -1,23 +0,0 @@ -package appmessage - -// MsgIBDRootUTXOSetAndBlock implements the Message interface and represents a kaspa -// IBDRootUTXOSetAndBlock message. It is used to answer RequestIBDRootUTXOSetAndBlock messages. -type MsgIBDRootUTXOSetAndBlock struct { - baseMessage - UTXOSet []byte - Block *MsgBlock -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgIBDRootUTXOSetAndBlock) Command() MessageCommand { - return CmdIBDRootUTXOSetAndBlock -} - -// NewMsgIBDRootUTXOSetAndBlock returns a new MsgIBDRootUTXOSetAndBlock. -func NewMsgIBDRootUTXOSetAndBlock(utxoSet []byte, block *MsgBlock) *MsgIBDRootUTXOSetAndBlock { - return &MsgIBDRootUTXOSetAndBlock{ - UTXOSet: utxoSet, - Block: block, - } -} diff --git a/app/appmessage/p2p_msgibdrootutxosetchunk.go b/app/appmessage/p2p_msgibdrootutxosetchunk.go new file mode 100644 index 000000000..d1a1e0574 --- /dev/null +++ b/app/appmessage/p2p_msgibdrootutxosetchunk.go @@ -0,0 +1,19 @@ +package appmessage + +// MsgIBDRootUTXOSetChunk represents a kaspa IBDRootUTXOSetChunk message +type MsgIBDRootUTXOSetChunk struct { + baseMessage + Chunk []byte +} + +// Command returns the protocol command string for the message +func (msg *MsgIBDRootUTXOSetChunk) Command() MessageCommand { + return CmdIBDRootUTXOSetChunk +} + +// NewMsgIBDRootUTXOSetChunk returns a new MsgIBDRootUTXOSetChunk. +func NewMsgIBDRootUTXOSetChunk(chunk []byte) *MsgIBDRootUTXOSetChunk { + return &MsgIBDRootUTXOSetChunk{ + Chunk: chunk, + } +} diff --git a/app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go b/app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go new file mode 100644 index 000000000..34689237e --- /dev/null +++ b/app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgRequestNextIBDRootUTXOSetChunk represents a kaspa RequestNextIBDRootUTXOSetChunk message +type MsgRequestNextIBDRootUTXOSetChunk struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgRequestNextIBDRootUTXOSetChunk) Command() MessageCommand { + return CmdRequestNextIBDRootUTXOSetChunk +} + +// NewMsgRequestNextIBDRootUTXOSetChunk returns a new MsgRequestNextIBDRootUTXOSetChunk. +func NewMsgRequestNextIBDRootUTXOSetChunk() *MsgRequestNextIBDRootUTXOSetChunk { + return &MsgRequestNextIBDRootUTXOSetChunk{} +} diff --git a/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go index c031a96df..9a4003597 100644 --- a/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go +++ b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go @@ -2,10 +2,12 @@ package blockrelay import ( "errors" - "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/common" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -38,11 +40,16 @@ func (flow *handleRequestIBDRootUTXOSetAndBlockFlow) start() error { if err != nil { return err } - msgRequestIBDRootUTXOSetAndBlock := message.(*appmessage.MsgRequestIBDRootUTXOSetAndBlock) + msgRequestIBDRootUTXOSetAndBlock, ok := message.(*appmessage.MsgRequestIBDRootUTXOSetAndBlock) + if !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdRequestIBDRootUTXOSetAndBlock, message.Command()) + } + finishMeasuring := logger.LogAndMeasureExecutionTime(log, "handleRequestIBDRootUTXOSetAndBlockFlow") log.Debugf("Got request for IBDRoot UTXOSet and Block") - utxoSet, err := flow.Domain().Consensus().GetPruningPointUTXOSet(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) + serializedUTXOSet, err := flow.Domain().Consensus().GetPruningPointUTXOSet(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) if err != nil { if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) { err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootNotFound()) @@ -53,19 +60,58 @@ func (flow *handleRequestIBDRootUTXOSetAndBlockFlow) start() error { continue } } - log.Debugf("Got utxo set for pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) + log.Debugf("Retrieved utxo set for pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) block, err := flow.Domain().Consensus().GetBlock(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) if err != nil { return err } + log.Debugf("Retrieved pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - log.Debugf("Got pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootUTXOSetAndBlock(utxoSet, - appmessage.DomainBlockToMsgBlock(block))) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(block))) if err != nil { return err } + + // Send the UTXO set in `step`-sized chunks + const step = 1024 * 1024 // 1MB + offset := 0 + chunksSent := 0 + for offset < len(serializedUTXOSet) { + var chunk []byte + if offset+step < len(serializedUTXOSet) { + chunk = serializedUTXOSet[offset : offset+step] + } else { + chunk = serializedUTXOSet[offset:] + } + + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootUTXOSetChunk(chunk)) + if err != nil { + return err + } + + offset += step + chunksSent++ + + // Wait for the peer to request more chunks every `ibdBatchSize` chunks + if chunksSent%ibdBatchSize == 0 { + message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) + if err != nil { + return err + } + _, ok := message.(*appmessage.MsgRequestNextIBDRootUTXOSetChunk) + if !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdRequestNextIBDRootUTXOSetChunk, message.Command()) + } + } + } + + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneIBDRootUTXOSetChunks()) + if err != nil { + return err + } + + finishMeasuring() } } diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 55103639f..d3ab5f9c5 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -1,6 +1,7 @@ package blockrelay import ( + "github.com/kaspanet/kaspad/infrastructure/logger" "time" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -24,67 +25,24 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain log.Debugf("IBD started with peer %s and highHash %s", flow.peer, highHash) - // Fetch all the headers if we don't already have them - log.Debugf("Downloading headers up to %s", highHash) + log.Debugf("Syncing headers up to %s", highHash) err := flow.syncHeaders(highHash) if err != nil { return err } - log.Debugf("Finished downloading headers up to %s", highHash) + log.Debugf("Finished syncing headers up to %s", highHash) - // Fetch the UTXO set if we don't already have it - log.Debugf("Checking if there's a new pruning point under %s", highHash) - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHashMessage()) + log.Debugf("Syncing the current pruning point UTXO set") + syncedPruningPointUTXOSetSuccessfully, err := flow.syncPruningPointUTXOSet() if err != nil { return err } - - message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) - if err != nil { - return err + if !syncedPruningPointUTXOSetSuccessfully { + log.Debugf("Aborting IBD because the pruning point UTXO set failed to sync") + return nil } + log.Debugf("Finished syncing the current pruning point UTXO set") - msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHashMessage) - if !ok { - return protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) - } - - blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgIBDRootHash.Hash) - if err != nil { - return err - } - - if blockInfo.BlockStatus == externalapi.StatusHeaderOnly { - log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", msgIBDRootHash.Hash) - isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) - if err != nil { - return err - } - - if !isValid { - log.Infof("The suggested pruning point %s is incompatible to this node DAG, so stopping IBD with this"+ - " peer", msgIBDRootHash.Hash) - return nil - } - - log.Info("Fetching the pruning point UTXO set") - succeed, err := flow.fetchMissingUTXOSet(msgIBDRootHash.Hash) - if err != nil { - return err - } - - if !succeed { - log.Infof("Couldn't successfully fetch the pruning point UTXO set. Stopping IBD.") - return nil - } - - log.Info("Fetched the new pruning point UTXO set") - } else { - log.Debugf("Already has the block data of the new suggested pruning point %s", msgIBDRootHash.Hash) - } - - // Fetch the block bodies log.Debugf("Downloading block bodies up to %s", highHash) err = flow.syncMissingBlockBodies(highHash) if err != nil { @@ -328,6 +286,59 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo return nil } +func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) { + log.Debugf("Checking if a new pruning point is available") + err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHashMessage()) + if err != nil { + return false, err + } + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return false, err + } + msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHashMessage) + if !ok { + return false, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) + } + + blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgIBDRootHash.Hash) + if err != nil { + return false, err + } + + if blockInfo.BlockStatus != externalapi.StatusHeaderOnly { + log.Debugf("Already has the block data of the new suggested pruning point %s", msgIBDRootHash.Hash) + return true, nil + } + + log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", msgIBDRootHash.Hash) + isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) + if err != nil { + return false, err + } + + if !isValid { + log.Infof("The suggested pruning point %s is incompatible to this node DAG, so stopping IBD with this"+ + " peer", msgIBDRootHash.Hash) + return false, nil + } + + log.Info("Fetching the pruning point UTXO set") + succeed, err := flow.fetchMissingUTXOSet(msgIBDRootHash.Hash) + if err != nil { + return false, err + } + + if !succeed { + log.Infof("Couldn't successfully fetch the pruning point UTXO set. Stopping IBD.") + return false, nil + } + + log.Info("Fetched the new pruning point UTXO set") + return true, nil +} + func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (succeed bool, err error) { err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash)) if err != nil { @@ -356,24 +367,66 @@ func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.Do } func (flow *handleRelayInvsFlow) receiveIBDRootUTXOSetAndBlock() ([]byte, *externalapi.DomainBlock, bool, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "receiveIBDRootUTXOSetAndBlock") + defer onEnd() + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) if err != nil { return nil, nil, false, err } + var block *externalapi.DomainBlock switch message := message.(type) { - case *appmessage.MsgIBDRootUTXOSetAndBlock: - return message.UTXOSet, - appmessage.MsgBlockToDomainBlock(message.Block), true, nil + case *appmessage.MsgIBDBlock: + block = appmessage.MsgBlockToDomainBlock(message.MsgBlock) case *appmessage.MsgIBDRootNotFound: return nil, nil, false, nil default: return nil, nil, false, protocolerrors.Errorf(true, "received unexpected message type. "+ "expected: %s or %s, got: %s", - appmessage.CmdIBDRootUTXOSetAndBlock, appmessage.CmdIBDRootNotFound, message.Command(), + appmessage.CmdIBDBlock, appmessage.CmdIBDRootNotFound, message.Command(), ) } + log.Debugf("Received IBD root block %s", consensushashing.BlockHash(block)) + + serializedUTXOSet := []byte{} + receivedAllChunks := false + receivedChunkCount := 0 + for !receivedAllChunks { + message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) + if err != nil { + return nil, nil, false, err + } + + switch message := message.(type) { + case *appmessage.MsgIBDRootUTXOSetChunk: + serializedUTXOSet = append(serializedUTXOSet, message.Chunk...) + case *appmessage.MsgDoneIBDRootUTXOSetChunks: + receivedAllChunks = true + default: + return nil, nil, false, + protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s or %s, got: %s", + appmessage.CmdIBDRootUTXOSetChunk, appmessage.CmdDoneIBDRootUTXOSetChunks, message.Command(), + ) + } + + receivedChunkCount++ + if !receivedAllChunks && receivedChunkCount%ibdBatchSize == 0 { + log.Debugf("Received %d UTXO set chunks so far, totaling in %d bytes", + receivedChunkCount, len(serializedUTXOSet)) + + requestNextIBDRootUTXOSetChunkMessage := appmessage.NewMsgRequestNextIBDRootUTXOSetChunk() + err := flow.outgoingRoute.Enqueue(requestNextIBDRootUTXOSetChunkMessage) + if err != nil { + return nil, nil, false, err + } + } + } + log.Debugf("Finished receiving the UTXO set. Total bytes: %d", len(serializedUTXOSet)) + + return serializedUTXOSet, block, true, nil } func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.DomainHash) error { diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index fcd5a811b..6ce09a3d7 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -135,8 +135,9 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * return []*flow{ m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, - appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetAndBlock, - appmessage.CmdBlockHeaders, appmessage.CmdIBDRootHash, appmessage.CmdIBDBlockLocatorHighestHash}, + appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetChunk, + appmessage.CmdBlockHeaders, appmessage.CmdIBDRootHash, appmessage.CmdIBDBlockLocatorHighestHash, + appmessage.CmdDoneIBDRootUTXOSetChunks}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) @@ -164,7 +165,8 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * ), m.registerFlow("HandleRequestIBDRootUTXOSetAndBlock", router, - []appmessage.MessageCommand{appmessage.CmdRequestIBDRootUTXOSetAndBlock}, isStopping, errChan, + []appmessage.MessageCommand{appmessage.CmdRequestIBDRootUTXOSetAndBlock, + appmessage.CmdRequestNextIBDRootUTXOSetChunk}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRequestIBDRootUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute) }, diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go index 2cf4407b2..269fef7d7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go @@ -18,7 +18,7 @@ type gRPCServer struct { } // MaxMessageSize is the max size allowed for a message -const MaxMessageSize = 1024 * 1024 * 1024 // 1GB +const MaxMessageSize = 10 * 1024 * 1024 // 10MB // newGRPCServer creates a gRPC server func newGRPCServer(listeningAddresses []string) *gRPCServer { diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index a3f05bb7f..6185c7945 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -52,7 +52,7 @@ type KaspadMessage struct { // *KaspadMessage_TransactionNotFound // *KaspadMessage_Reject // *KaspadMessage_RequestIBDRootUTXOSetAndBlock - // *KaspadMessage_IbdRootUTXOSetAndBlock + // *KaspadMessage_IbdRootUtxoSetChunk // *KaspadMessage_RequestIBDBlocks // *KaspadMessage_IbdRootNotFound // *KaspadMessage_RequestIBDRootHash @@ -60,6 +60,8 @@ type KaspadMessage struct { // *KaspadMessage_IbdBlockLocator // *KaspadMessage_IbdBlockLocatorHighestHash // *KaspadMessage_BlockHeaders + // *KaspadMessage_RequestNextIbdRootUtxoSetChunk + // *KaspadMessage_DoneIbdRootUtxoSetChunks // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -307,9 +309,9 @@ func (x *KaspadMessage) GetRequestIBDRootUTXOSetAndBlock() *RequestIBDRootUTXOSe return nil } -func (x *KaspadMessage) GetIbdRootUTXOSetAndBlock() *IBDRootUTXOSetAndBlockMessage { - if x, ok := x.GetPayload().(*KaspadMessage_IbdRootUTXOSetAndBlock); ok { - return x.IbdRootUTXOSetAndBlock +func (x *KaspadMessage) GetIbdRootUtxoSetChunk() *IbdRootUtxoSetChunkMessage { + if x, ok := x.GetPayload().(*KaspadMessage_IbdRootUtxoSetChunk); ok { + return x.IbdRootUtxoSetChunk } return nil } @@ -363,6 +365,20 @@ func (x *KaspadMessage) GetBlockHeaders() *BlockHeadersMessage { return nil } +func (x *KaspadMessage) GetRequestNextIbdRootUtxoSetChunk() *RequestNextIbdRootUtxoSetChunkMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestNextIbdRootUtxoSetChunk); ok { + return x.RequestNextIbdRootUtxoSetChunk + } + return nil +} + +func (x *KaspadMessage) GetDoneIbdRootUtxoSetChunks() *DoneIbdRootUtxoSetChunksMessage { + if x, ok := x.GetPayload().(*KaspadMessage_DoneIbdRootUtxoSetChunks); ok { + return x.DoneIbdRootUtxoSetChunks + } + return nil +} + func (x *KaspadMessage) GetGetCurrentNetworkRequest() *GetCurrentNetworkRequestMessage { if x, ok := x.GetPayload().(*KaspadMessage_GetCurrentNetworkRequest); ok { return x.GetCurrentNetworkRequest @@ -857,8 +873,8 @@ type KaspadMessage_RequestIBDRootUTXOSetAndBlock struct { RequestIBDRootUTXOSetAndBlock *RequestIBDRootUTXOSetAndBlockMessage `protobuf:"bytes,24,opt,name=requestIBDRootUTXOSetAndBlock,proto3,oneof"` } -type KaspadMessage_IbdRootUTXOSetAndBlock struct { - IbdRootUTXOSetAndBlock *IBDRootUTXOSetAndBlockMessage `protobuf:"bytes,25,opt,name=ibdRootUTXOSetAndBlock,proto3,oneof"` +type KaspadMessage_IbdRootUtxoSetChunk struct { + IbdRootUtxoSetChunk *IbdRootUtxoSetChunkMessage `protobuf:"bytes,25,opt,name=ibdRootUtxoSetChunk,proto3,oneof"` } type KaspadMessage_RequestIBDBlocks struct { @@ -889,6 +905,14 @@ type KaspadMessage_BlockHeaders struct { BlockHeaders *BlockHeadersMessage `protobuf:"bytes,32,opt,name=blockHeaders,proto3,oneof"` } +type KaspadMessage_RequestNextIbdRootUtxoSetChunk struct { + RequestNextIbdRootUtxoSetChunk *RequestNextIbdRootUtxoSetChunkMessage `protobuf:"bytes,33,opt,name=requestNextIbdRootUtxoSetChunk,proto3,oneof"` +} + +type KaspadMessage_DoneIbdRootUtxoSetChunks struct { + DoneIbdRootUtxoSetChunks *DoneIbdRootUtxoSetChunksMessage `protobuf:"bytes,34,opt,name=doneIbdRootUtxoSetChunks,proto3,oneof"` +} + type KaspadMessage_GetCurrentNetworkRequest struct { GetCurrentNetworkRequest *GetCurrentNetworkRequestMessage `protobuf:"bytes,1001,opt,name=getCurrentNetworkRequest,proto3,oneof"` } @@ -1163,7 +1187,7 @@ func (*KaspadMessage_Reject) isKaspadMessage_Payload() {} func (*KaspadMessage_RequestIBDRootUTXOSetAndBlock) isKaspadMessage_Payload() {} -func (*KaspadMessage_IbdRootUTXOSetAndBlock) isKaspadMessage_Payload() {} +func (*KaspadMessage_IbdRootUtxoSetChunk) isKaspadMessage_Payload() {} func (*KaspadMessage_RequestIBDBlocks) isKaspadMessage_Payload() {} @@ -1179,6 +1203,10 @@ func (*KaspadMessage_IbdBlockLocatorHighestHash) isKaspadMessage_Payload() {} func (*KaspadMessage_BlockHeaders) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestNextIbdRootUtxoSetChunk) isKaspadMessage_Payload() {} + +func (*KaspadMessage_DoneIbdRootUtxoSetChunks) isKaspadMessage_Payload() {} + func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkResponse) isKaspadMessage_Payload() {} @@ -1301,7 +1329,7 @@ var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xd6, 0x45, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x6f, 0x22, 0xb3, 0x47, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, @@ -1396,482 +1424,496 @@ var file_messages_proto_rawDesc = []byte{ 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, - 0x62, 0x0a, 0x16, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, - 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, - 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x69, 0x62, 0x64, - 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, - 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, - 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, - 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, - 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, - 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, - 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, - 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, - 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, - 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, - 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, - 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, - 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, + 0x59, 0x0a, 0x13, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, + 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, + 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, + 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4d, 0x0a, 0x0f, + 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, + 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, + 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, + 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, + 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x7a, 0x0a, 0x1e, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, + 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x21, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, 0x64, 0x52, 0x6f, + 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, + 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x68, 0x0a, 0x18, 0x64, 0x6f, 0x6e, 0x65, 0x49, + 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, + 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x64, 0x6f, 0x6e, 0x65, 0x49, 0x62, 0x64, + 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x73, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, + 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, + 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, - 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, - 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, + 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, + 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, - 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, + 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, - 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, - 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, - 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, - 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, - 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, + 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, + 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, + 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, + 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, - 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, - 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, - 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, - 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, - 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, - 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, - 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, - 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, - 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, 0x18, 0x8d, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, - 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, - 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, - 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, - 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, - 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, - 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, - 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, + 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x6e, 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, 0x48, + 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, + 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, + 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, + 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, + 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, + 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, + 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, + 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, - 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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 ( @@ -1909,7 +1951,7 @@ var file_messages_proto_goTypes = []interface{}{ (*TransactionNotFoundMessage)(nil), // 18: protowire.TransactionNotFoundMessage (*RejectMessage)(nil), // 19: protowire.RejectMessage (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 20: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IBDRootUTXOSetAndBlockMessage)(nil), // 21: protowire.IBDRootUTXOSetAndBlockMessage + (*IbdRootUtxoSetChunkMessage)(nil), // 21: protowire.IbdRootUtxoSetChunkMessage (*RequestIBDBlocksMessage)(nil), // 22: protowire.RequestIBDBlocksMessage (*IBDRootNotFoundMessage)(nil), // 23: protowire.IBDRootNotFoundMessage (*RequestIBDRootHashMessage)(nil), // 24: protowire.RequestIBDRootHashMessage @@ -1917,64 +1959,66 @@ var file_messages_proto_goTypes = []interface{}{ (*IbdBlockLocatorMessage)(nil), // 26: protowire.IbdBlockLocatorMessage (*IbdBlockLocatorHighestHashMessage)(nil), // 27: protowire.IbdBlockLocatorHighestHashMessage (*BlockHeadersMessage)(nil), // 28: protowire.BlockHeadersMessage - (*GetCurrentNetworkRequestMessage)(nil), // 29: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 30: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 31: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 32: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 33: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 34: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 35: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 36: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 37: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 38: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 39: protowire.GetPeerAddressesResponseMessage - (*GetSelectedTipHashRequestMessage)(nil), // 40: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 41: protowire.GetSelectedTipHashResponseMessage - (*GetMempoolEntryRequestMessage)(nil), // 42: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 43: protowire.GetMempoolEntryResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 44: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 45: protowire.GetConnectedPeerInfoResponseMessage - (*AddPeerRequestMessage)(nil), // 46: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 47: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 48: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 49: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 50: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 51: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 52: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*GetBlockRequestMessage)(nil), // 53: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 54: protowire.GetBlockResponseMessage - (*GetSubnetworkRequestMessage)(nil), // 55: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 56: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 57: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 58: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 59: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 60: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 61: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 62: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 63: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 64: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 65: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 66: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 67: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 68: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 69: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 70: protowire.FinalityConflictResolvedNotificationMessage - (*GetMempoolEntriesRequestMessage)(nil), // 71: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 72: protowire.GetMempoolEntriesResponseMessage - (*ShutDownRequestMessage)(nil), // 73: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 74: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 75: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 76: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 77: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 78: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 79: protowire.UtxosChangedNotificationMessage - (*GetUtxosByAddressesRequestMessage)(nil), // 80: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 81: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 82: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 83: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 84: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 85: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 86: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*RequestNextIbdRootUtxoSetChunkMessage)(nil), // 29: protowire.RequestNextIbdRootUtxoSetChunkMessage + (*DoneIbdRootUtxoSetChunksMessage)(nil), // 30: protowire.DoneIbdRootUtxoSetChunksMessage + (*GetCurrentNetworkRequestMessage)(nil), // 31: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 32: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 33: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 34: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 35: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 36: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 37: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 38: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 39: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 40: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 41: protowire.GetPeerAddressesResponseMessage + (*GetSelectedTipHashRequestMessage)(nil), // 42: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 43: protowire.GetSelectedTipHashResponseMessage + (*GetMempoolEntryRequestMessage)(nil), // 44: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 45: protowire.GetMempoolEntryResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 46: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 47: protowire.GetConnectedPeerInfoResponseMessage + (*AddPeerRequestMessage)(nil), // 48: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 49: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 50: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 51: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 52: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 53: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 54: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*GetBlockRequestMessage)(nil), // 55: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 56: protowire.GetBlockResponseMessage + (*GetSubnetworkRequestMessage)(nil), // 57: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 58: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 59: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 60: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 61: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 62: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 63: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 64: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 65: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 66: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 67: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 68: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 69: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 70: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 71: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 72: protowire.FinalityConflictResolvedNotificationMessage + (*GetMempoolEntriesRequestMessage)(nil), // 73: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 74: protowire.GetMempoolEntriesResponseMessage + (*ShutDownRequestMessage)(nil), // 75: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 76: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 77: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 78: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 79: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 80: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 81: protowire.UtxosChangedNotificationMessage + (*GetUtxosByAddressesRequestMessage)(nil), // 82: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 83: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 84: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 85: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 86: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 87: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 88: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage } var file_messages_proto_depIdxs = []int32{ 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -1998,7 +2042,7 @@ var file_messages_proto_depIdxs = []int32{ 18, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage 19, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage 20, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage - 21, // 21: protowire.KaspadMessage.ibdRootUTXOSetAndBlock:type_name -> protowire.IBDRootUTXOSetAndBlockMessage + 21, // 21: protowire.KaspadMessage.ibdRootUtxoSetChunk:type_name -> protowire.IbdRootUtxoSetChunkMessage 22, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage 23, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage 24, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage @@ -2006,73 +2050,75 @@ var file_messages_proto_depIdxs = []int32{ 26, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage 27, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage 28, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage - 29, // 29: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 30, // 30: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 31, // 31: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 32, // 32: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 33, // 33: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 34, // 34: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 35, // 35: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 36, // 36: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 37, // 37: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 38, // 38: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 39, // 39: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 40, // 40: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 41, // 41: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 42, // 42: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 43, // 43: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 44, // 44: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 45, // 45: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 46, // 46: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 47, // 47: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 48, // 48: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 49, // 49: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 50, // 50: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 51, // 51: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 52, // 52: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 53, // 53: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 54, // 54: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 55, // 55: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 56, // 56: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 57, // 57: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 58, // 58: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 59, // 59: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 60, // 60: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 61, // 61: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 62, // 62: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 63, // 63: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 64, // 64: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 65, // 65: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 66, // 66: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 67, // 67: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 68, // 68: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 69, // 69: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 70, // 70: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 71, // 71: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 72, // 72: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 73, // 73: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 74, // 74: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 75, // 75: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 76, // 76: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 77, // 77: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 78, // 78: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 79, // 79: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 80, // 80: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 81, // 81: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 82, // 82: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 83, // 83: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 84, // 84: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 85, // 85: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 86, // 86: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 0, // 87: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 88: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 89: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 90: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 89, // [89:91] is the sub-list for method output_type - 87, // [87:89] is the sub-list for method input_type - 87, // [87:87] is the sub-list for extension type_name - 87, // [87:87] is the sub-list for extension extendee - 0, // [0:87] is the sub-list for field type_name + 29, // 29: protowire.KaspadMessage.requestNextIbdRootUtxoSetChunk:type_name -> protowire.RequestNextIbdRootUtxoSetChunkMessage + 30, // 30: protowire.KaspadMessage.doneIbdRootUtxoSetChunks:type_name -> protowire.DoneIbdRootUtxoSetChunksMessage + 31, // 31: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 32, // 32: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 33, // 33: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 34, // 34: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 35, // 35: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 36, // 36: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 37, // 37: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 38, // 38: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 39, // 39: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 40, // 40: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 41, // 41: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 42, // 42: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 43, // 43: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 44, // 44: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 45, // 45: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 46, // 46: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 47, // 47: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 48, // 48: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 49, // 49: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 50, // 50: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 51, // 51: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 52, // 52: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 53, // 53: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 54, // 54: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 55, // 55: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 56, // 56: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 57, // 57: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 58, // 58: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 59, // 59: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 60, // 60: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 61, // 61: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 62, // 62: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 63, // 63: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 64, // 64: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 65, // 65: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 66, // 66: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 67, // 67: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 68, // 68: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 69, // 69: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 70, // 70: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 71, // 71: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 72, // 72: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 73, // 73: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 74, // 74: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 75, // 75: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 76, // 76: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 77, // 77: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 78, // 78: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 79, // 79: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 80, // 80: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 81, // 81: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 82, // 82: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 83, // 83: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 84, // 84: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 85, // 85: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 86, // 86: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 87, // 87: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 88, // 88: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 0, // 89: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 90: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 91: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 92: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 91, // [91:93] is the sub-list for method output_type + 89, // [89:91] is the sub-list for method input_type + 89, // [89:89] is the sub-list for extension type_name + 89, // [89:89] is the sub-list for extension extendee + 0, // [0:89] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2118,7 +2164,7 @@ func file_messages_proto_init() { (*KaspadMessage_TransactionNotFound)(nil), (*KaspadMessage_Reject)(nil), (*KaspadMessage_RequestIBDRootUTXOSetAndBlock)(nil), - (*KaspadMessage_IbdRootUTXOSetAndBlock)(nil), + (*KaspadMessage_IbdRootUtxoSetChunk)(nil), (*KaspadMessage_RequestIBDBlocks)(nil), (*KaspadMessage_IbdRootNotFound)(nil), (*KaspadMessage_RequestIBDRootHash)(nil), @@ -2126,6 +2172,8 @@ func file_messages_proto_init() { (*KaspadMessage_IbdBlockLocator)(nil), (*KaspadMessage_IbdBlockLocatorHighestHash)(nil), (*KaspadMessage_BlockHeaders)(nil), + (*KaspadMessage_RequestNextIbdRootUtxoSetChunk)(nil), + (*KaspadMessage_DoneIbdRootUtxoSetChunks)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index f22669001..4aed64c5d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -29,7 +29,7 @@ message KaspadMessage { TransactionNotFoundMessage transactionNotFound = 21; RejectMessage reject = 22; RequestIBDRootUTXOSetAndBlockMessage requestIBDRootUTXOSetAndBlock = 24; - IBDRootUTXOSetAndBlockMessage ibdRootUTXOSetAndBlock = 25; + IbdRootUtxoSetChunkMessage ibdRootUtxoSetChunk = 25; RequestIBDBlocksMessage requestIBDBlocks = 26; IBDRootNotFoundMessage ibdRootNotFound = 27; RequestIBDRootHashMessage requestIBDRootHash = 28; @@ -37,6 +37,8 @@ message KaspadMessage { IbdBlockLocatorMessage ibdBlockLocator = 30; IbdBlockLocatorHighestHashMessage ibdBlockLocatorHighestHash = 31; BlockHeadersMessage blockHeaders = 32; + RequestNextIbdRootUtxoSetChunkMessage requestNextIbdRootUtxoSetChunk = 33; + DoneIbdRootUtxoSetChunksMessage doneIbdRootUtxoSetChunks = 34; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go index 8fc332a65..45c2793ec 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go @@ -25,7 +25,6 @@ const ( // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 -// RequestAddressesMessage start type RequestAddressesMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -81,7 +80,6 @@ func (x *RequestAddressesMessage) GetSubnetworkId() *SubnetworkId { return nil } -// AddressesMessage start type AddressesMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -247,7 +245,6 @@ func (x *SubnetworkId) GetBytes() []byte { return nil } -// TransactionMessage start type TransactionMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -626,7 +623,6 @@ func (x *TransactionOutput) GetScriptPublicKey() *ScriptPublicKey { return nil } -// BlockMessage start type BlockMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -832,7 +828,6 @@ func (x *Hash) GetBytes() []byte { return nil } -// GetBlockLocatorMessage start type RequestBlockLocatorMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -896,7 +891,6 @@ func (x *RequestBlockLocatorMessage) GetLimit() uint32 { return 0 } -// BlockLocatorMessage start type BlockLocatorMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -944,7 +938,6 @@ func (x *BlockLocatorMessage) GetHashes() []*Hash { return nil } -// GetBlocksMessage start type RequestHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1000,7 +993,6 @@ func (x *RequestHeadersMessage) GetHighHash() *Hash { return nil } -// RequestNextIBDBlocksMessage start type RequestNextHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1039,7 +1031,6 @@ func (*RequestNextHeadersMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{16} } -// DoneIBDBlocksMessage start type DoneHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1078,7 +1069,6 @@ func (*DoneHeadersMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{17} } -// RequestRelayBlocksMessage start type RequestRelayBlocksMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1126,7 +1116,6 @@ func (x *RequestRelayBlocksMessage) GetHashes() []*Hash { return nil } -// RequestTransactionsMessage start type RequestTransactionsMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1174,7 +1163,6 @@ func (x *RequestTransactionsMessage) GetIds() []*TransactionId { return nil } -// TransactionNotFoundMessage start type TransactionNotFoundMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1222,7 +1210,6 @@ func (x *TransactionNotFoundMessage) GetId() *TransactionId { return nil } -// InvRelayBlockMessage start type InvRelayBlockMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1270,7 +1257,6 @@ func (x *InvRelayBlockMessage) GetHash() *Hash { return nil } -// InvTransactionMessage start type InvTransactionsMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1318,7 +1304,6 @@ func (x *InvTransactionsMessage) GetIds() []*TransactionId { return nil } -// PingMessage start type PingMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1366,7 +1351,6 @@ func (x *PingMessage) GetNonce() uint64 { return 0 } -// PongMessage start type PongMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1414,7 +1398,6 @@ func (x *PongMessage) GetNonce() uint64 { return 0 } -// VerackMessage start type VerackMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1453,7 +1436,6 @@ func (*VerackMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{25} } -// VersionMessage start type VersionMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1565,7 +1547,6 @@ func (x *VersionMessage) GetNetwork() string { return "" } -// RejectMessage start type RejectMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1613,7 +1594,6 @@ func (x *RejectMessage) GetReason() string { return "" } -// RequestIBDRootUTXOSetAndBlockMessage start type RequestIBDRootUTXOSetAndBlockMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1661,18 +1641,16 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { return nil } -// IBDRootUTXOSetAndBlockMessage start -type IBDRootUTXOSetAndBlockMessage struct { +type IbdRootUtxoSetChunkMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - UtxoSet []byte `protobuf:"bytes,1,opt,name=utxoSet,proto3" json:"utxoSet,omitempty"` - Block *BlockMessage `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` + Chunk []byte `protobuf:"bytes,1,opt,name=chunk,proto3" json:"chunk,omitempty"` } -func (x *IBDRootUTXOSetAndBlockMessage) Reset() { - *x = IBDRootUTXOSetAndBlockMessage{} +func (x *IbdRootUtxoSetChunkMessage) Reset() { + *x = IbdRootUtxoSetChunkMessage{} if protoimpl.UnsafeEnabled { mi := &file_p2p_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1680,13 +1658,13 @@ func (x *IBDRootUTXOSetAndBlockMessage) Reset() { } } -func (x *IBDRootUTXOSetAndBlockMessage) String() string { +func (x *IbdRootUtxoSetChunkMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*IBDRootUTXOSetAndBlockMessage) ProtoMessage() {} +func (*IbdRootUtxoSetChunkMessage) ProtoMessage() {} -func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { +func (x *IbdRootUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { mi := &file_p2p_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1698,26 +1676,94 @@ func (x *IBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use IBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. -func (*IBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use IbdRootUtxoSetChunkMessage.ProtoReflect.Descriptor instead. +func (*IbdRootUtxoSetChunkMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{29} } -func (x *IBDRootUTXOSetAndBlockMessage) GetUtxoSet() []byte { +func (x *IbdRootUtxoSetChunkMessage) GetChunk() []byte { if x != nil { - return x.UtxoSet + return x.Chunk } return nil } -func (x *IBDRootUTXOSetAndBlockMessage) GetBlock() *BlockMessage { - if x != nil { - return x.Block - } - return nil +type RequestNextIbdRootUtxoSetChunkMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RequestNextIbdRootUtxoSetChunkMessage) Reset() { + *x = RequestNextIbdRootUtxoSetChunkMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestNextIbdRootUtxoSetChunkMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestNextIbdRootUtxoSetChunkMessage) ProtoMessage() {} + +func (x *RequestNextIbdRootUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestNextIbdRootUtxoSetChunkMessage.ProtoReflect.Descriptor instead. +func (*RequestNextIbdRootUtxoSetChunkMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{30} +} + +type DoneIbdRootUtxoSetChunksMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DoneIbdRootUtxoSetChunksMessage) Reset() { + *x = DoneIbdRootUtxoSetChunksMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DoneIbdRootUtxoSetChunksMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DoneIbdRootUtxoSetChunksMessage) ProtoMessage() {} + +func (x *DoneIbdRootUtxoSetChunksMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DoneIbdRootUtxoSetChunksMessage.ProtoReflect.Descriptor instead. +func (*DoneIbdRootUtxoSetChunksMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{31} } -// RequestIBDBlocksMessage start type RequestIBDBlocksMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1729,7 +1775,7 @@ type RequestIBDBlocksMessage struct { func (x *RequestIBDBlocksMessage) Reset() { *x = RequestIBDBlocksMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[30] + mi := &file_p2p_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1742,7 +1788,7 @@ func (x *RequestIBDBlocksMessage) String() string { func (*RequestIBDBlocksMessage) ProtoMessage() {} func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[30] + mi := &file_p2p_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1755,7 +1801,7 @@ func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{30} + return file_p2p_proto_rawDescGZIP(), []int{32} } func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { @@ -1765,7 +1811,6 @@ func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { return nil } -// IBDRootNotFoundMessage start type IBDRootNotFoundMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1775,7 +1820,7 @@ type IBDRootNotFoundMessage struct { func (x *IBDRootNotFoundMessage) Reset() { *x = IBDRootNotFoundMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[31] + mi := &file_p2p_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1788,7 +1833,7 @@ func (x *IBDRootNotFoundMessage) String() string { func (*IBDRootNotFoundMessage) ProtoMessage() {} func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[31] + mi := &file_p2p_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1801,10 +1846,9 @@ func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{31} + return file_p2p_proto_rawDescGZIP(), []int{33} } -// RequestIBDRootHashMessage start type RequestIBDRootHashMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1814,7 +1858,7 @@ type RequestIBDRootHashMessage struct { func (x *RequestIBDRootHashMessage) Reset() { *x = RequestIBDRootHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[32] + mi := &file_p2p_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1827,7 +1871,7 @@ func (x *RequestIBDRootHashMessage) String() string { func (*RequestIBDRootHashMessage) ProtoMessage() {} func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[32] + mi := &file_p2p_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1840,10 +1884,9 @@ func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestIBDRootHashMessage.ProtoReflect.Descriptor instead. func (*RequestIBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{32} + return file_p2p_proto_rawDescGZIP(), []int{34} } -// IBDRootHashMessage start type IBDRootHashMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1855,7 +1898,7 @@ type IBDRootHashMessage struct { func (x *IBDRootHashMessage) Reset() { *x = IBDRootHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[33] + mi := &file_p2p_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1868,7 +1911,7 @@ func (x *IBDRootHashMessage) String() string { func (*IBDRootHashMessage) ProtoMessage() {} func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[33] + mi := &file_p2p_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1881,7 +1924,7 @@ func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IBDRootHashMessage.ProtoReflect.Descriptor instead. func (*IBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{33} + return file_p2p_proto_rawDescGZIP(), []int{35} } func (x *IBDRootHashMessage) GetHash() *Hash { @@ -1891,7 +1934,6 @@ func (x *IBDRootHashMessage) GetHash() *Hash { return nil } -// IbdBlockLocatorMessage start type IbdBlockLocatorMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1904,7 +1946,7 @@ type IbdBlockLocatorMessage struct { func (x *IbdBlockLocatorMessage) Reset() { *x = IbdBlockLocatorMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[34] + mi := &file_p2p_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1917,7 +1959,7 @@ func (x *IbdBlockLocatorMessage) String() string { func (*IbdBlockLocatorMessage) ProtoMessage() {} func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[34] + mi := &file_p2p_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1930,7 +1972,7 @@ func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IbdBlockLocatorMessage.ProtoReflect.Descriptor instead. func (*IbdBlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{34} + return file_p2p_proto_rawDescGZIP(), []int{36} } func (x *IbdBlockLocatorMessage) GetTargetHash() *Hash { @@ -1947,7 +1989,6 @@ func (x *IbdBlockLocatorMessage) GetBlockLocatorHashes() []*Hash { return nil } -// IbdBlockLocatorHighestHashMessage start type IbdBlockLocatorHighestHashMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1959,7 +2000,7 @@ type IbdBlockLocatorHighestHashMessage struct { func (x *IbdBlockLocatorHighestHashMessage) Reset() { *x = IbdBlockLocatorHighestHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[35] + mi := &file_p2p_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1972,7 +2013,7 @@ func (x *IbdBlockLocatorHighestHashMessage) String() string { func (*IbdBlockLocatorHighestHashMessage) ProtoMessage() {} func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[35] + mi := &file_p2p_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1985,7 +2026,7 @@ func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message // Deprecated: Use IbdBlockLocatorHighestHashMessage.ProtoReflect.Descriptor instead. func (*IbdBlockLocatorHighestHashMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{35} + return file_p2p_proto_rawDescGZIP(), []int{37} } func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { @@ -2006,7 +2047,7 @@ type BlockHeadersMessage struct { func (x *BlockHeadersMessage) Reset() { *x = BlockHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[36] + mi := &file_p2p_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2019,7 +2060,7 @@ func (x *BlockHeadersMessage) String() string { func (*BlockHeadersMessage) ProtoMessage() {} func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[36] + mi := &file_p2p_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2032,7 +2073,7 @@ func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{36} + return file_p2p_proto_rawDescGZIP(), []int{38} } func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { @@ -2232,48 +2273,49 @@ var file_p2p_proto_rawDesc = []byte{ 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x68, 0x0a, 0x1d, 0x49, - 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x75, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, - 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x32, 0x0a, 0x1a, 0x49, + 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, + 0x27, 0x0a, 0x25, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, + 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x44, 0x6f, 0x6e, 0x65, + 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x42, 0x0a, 0x17, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, + 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, + 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, + 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, - 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, - 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, - 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, - 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, - 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 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, + 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, + 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, + 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, + 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, + 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 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 ( @@ -2288,45 +2330,47 @@ func file_p2p_proto_rawDescGZIP() []byte { return file_p2p_proto_rawDescData } -var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 37) +var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 39) var file_p2p_proto_goTypes = []interface{}{ - (*RequestAddressesMessage)(nil), // 0: protowire.RequestAddressesMessage - (*AddressesMessage)(nil), // 1: protowire.AddressesMessage - (*NetAddress)(nil), // 2: protowire.NetAddress - (*SubnetworkId)(nil), // 3: protowire.SubnetworkId - (*TransactionMessage)(nil), // 4: protowire.TransactionMessage - (*TransactionInput)(nil), // 5: protowire.TransactionInput - (*Outpoint)(nil), // 6: protowire.Outpoint - (*TransactionId)(nil), // 7: protowire.TransactionId - (*ScriptPublicKey)(nil), // 8: protowire.ScriptPublicKey - (*TransactionOutput)(nil), // 9: protowire.TransactionOutput - (*BlockMessage)(nil), // 10: protowire.BlockMessage - (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage - (*Hash)(nil), // 12: protowire.Hash - (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage - (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage - (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage - (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage - (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage - (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage - (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage - (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage - (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage - (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage - (*PingMessage)(nil), // 23: protowire.PingMessage - (*PongMessage)(nil), // 24: protowire.PongMessage - (*VerackMessage)(nil), // 25: protowire.VerackMessage - (*VersionMessage)(nil), // 26: protowire.VersionMessage - (*RejectMessage)(nil), // 27: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IBDRootUTXOSetAndBlockMessage)(nil), // 29: protowire.IBDRootUTXOSetAndBlockMessage - (*RequestIBDBlocksMessage)(nil), // 30: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 31: protowire.IBDRootNotFoundMessage - (*RequestIBDRootHashMessage)(nil), // 32: protowire.RequestIBDRootHashMessage - (*IBDRootHashMessage)(nil), // 33: protowire.IBDRootHashMessage - (*IbdBlockLocatorMessage)(nil), // 34: protowire.IbdBlockLocatorMessage - (*IbdBlockLocatorHighestHashMessage)(nil), // 35: protowire.IbdBlockLocatorHighestHashMessage - (*BlockHeadersMessage)(nil), // 36: protowire.BlockHeadersMessage + (*RequestAddressesMessage)(nil), // 0: protowire.RequestAddressesMessage + (*AddressesMessage)(nil), // 1: protowire.AddressesMessage + (*NetAddress)(nil), // 2: protowire.NetAddress + (*SubnetworkId)(nil), // 3: protowire.SubnetworkId + (*TransactionMessage)(nil), // 4: protowire.TransactionMessage + (*TransactionInput)(nil), // 5: protowire.TransactionInput + (*Outpoint)(nil), // 6: protowire.Outpoint + (*TransactionId)(nil), // 7: protowire.TransactionId + (*ScriptPublicKey)(nil), // 8: protowire.ScriptPublicKey + (*TransactionOutput)(nil), // 9: protowire.TransactionOutput + (*BlockMessage)(nil), // 10: protowire.BlockMessage + (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage + (*Hash)(nil), // 12: protowire.Hash + (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage + (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage + (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage + (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage + (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage + (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage + (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 23: protowire.PingMessage + (*PongMessage)(nil), // 24: protowire.PongMessage + (*VerackMessage)(nil), // 25: protowire.VerackMessage + (*VersionMessage)(nil), // 26: protowire.VersionMessage + (*RejectMessage)(nil), // 27: protowire.RejectMessage + (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage + (*IbdRootUtxoSetChunkMessage)(nil), // 29: protowire.IbdRootUtxoSetChunkMessage + (*RequestNextIbdRootUtxoSetChunkMessage)(nil), // 30: protowire.RequestNextIbdRootUtxoSetChunkMessage + (*DoneIbdRootUtxoSetChunksMessage)(nil), // 31: protowire.DoneIbdRootUtxoSetChunksMessage + (*RequestIBDBlocksMessage)(nil), // 32: protowire.RequestIBDBlocksMessage + (*IBDRootNotFoundMessage)(nil), // 33: protowire.IBDRootNotFoundMessage + (*RequestIBDRootHashMessage)(nil), // 34: protowire.RequestIBDRootHashMessage + (*IBDRootHashMessage)(nil), // 35: protowire.IBDRootHashMessage + (*IbdBlockLocatorMessage)(nil), // 36: protowire.IbdBlockLocatorMessage + (*IbdBlockLocatorHighestHashMessage)(nil), // 37: protowire.IbdBlockLocatorHighestHashMessage + (*BlockHeadersMessage)(nil), // 38: protowire.BlockHeadersMessage } var file_p2p_proto_depIdxs = []int32{ 3, // 0: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId @@ -2357,18 +2401,17 @@ var file_p2p_proto_depIdxs = []int32{ 2, // 25: protowire.VersionMessage.address:type_name -> protowire.NetAddress 3, // 26: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId 12, // 27: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 10, // 28: protowire.IBDRootUTXOSetAndBlockMessage.block:type_name -> protowire.BlockMessage - 12, // 29: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 12, // 30: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash - 12, // 31: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash - 12, // 32: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash - 12, // 33: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash - 11, // 34: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage - 35, // [35:35] is the sub-list for method output_type - 35, // [35:35] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 12, // 28: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 12, // 29: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash + 12, // 30: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash + 12, // 31: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash + 12, // 32: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash + 11, // 33: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage + 34, // [34:34] is the sub-list for method output_type + 34, // [34:34] is the sub-list for method input_type + 34, // [34:34] is the sub-list for extension type_name + 34, // [34:34] is the sub-list for extension extendee + 0, // [0:34] is the sub-list for field type_name } func init() { file_p2p_proto_init() } @@ -2726,7 +2769,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootUTXOSetAndBlockMessage); i { + switch v := v.(*IbdRootUtxoSetChunkMessage); i { case 0: return &v.state case 1: @@ -2738,7 +2781,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDBlocksMessage); i { + switch v := v.(*RequestNextIbdRootUtxoSetChunkMessage); i { case 0: return &v.state case 1: @@ -2750,7 +2793,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootNotFoundMessage); i { + switch v := v.(*DoneIbdRootUtxoSetChunksMessage); i { case 0: return &v.state case 1: @@ -2762,7 +2805,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootHashMessage); i { + switch v := v.(*RequestIBDBlocksMessage); i { case 0: return &v.state case 1: @@ -2774,7 +2817,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootHashMessage); i { + switch v := v.(*IBDRootNotFoundMessage); i { case 0: return &v.state case 1: @@ -2786,7 +2829,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorMessage); i { + switch v := v.(*RequestIBDRootHashMessage); i { case 0: return &v.state case 1: @@ -2798,7 +2841,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorHighestHashMessage); i { + switch v := v.(*IBDRootHashMessage); i { case 0: return &v.state case 1: @@ -2810,6 +2853,30 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorHighestHashMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlockHeadersMessage); i { case 0: return &v.state @@ -2828,7 +2895,7 @@ func file_p2p_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_p2p_proto_rawDesc, NumEnums: 0, - NumMessages: 37, + NumMessages: 39, NumExtensions: 0, NumServices: 0, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto index cbc34d1da..14d3e9ff1 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto @@ -3,14 +3,11 @@ package protowire; option go_package = "github.com/kaspanet/kaspad/protowire"; -// RequestAddressesMessage start message RequestAddressesMessage{ bool includeAllSubnetworks = 1; SubnetworkId subnetworkId = 2; } -// RequestAddressesMessage end -// AddressesMessage start message AddressesMessage{ repeated NetAddress addressList = 1; } @@ -25,9 +22,7 @@ message NetAddress{ message SubnetworkId{ bytes bytes = 1; } -// AddressesMessage end -// TransactionMessage start message TransactionMessage{ uint32 version = 1; repeated TransactionInput inputs = 2; @@ -62,9 +57,7 @@ message TransactionOutput{ uint64 value = 1; ScriptPublicKey scriptPublicKey = 2; } -// TransactionMessage end -// BlockMessage start message BlockMessage{ BlockHeaderMessage header = 1; repeated TransactionMessage transactions = 2; @@ -84,87 +77,59 @@ message BlockHeaderMessage{ message Hash{ bytes bytes = 1; } -// BlockMessage end -// GetBlockLocatorMessage start message RequestBlockLocatorMessage{ Hash lowHash = 1; Hash highHash = 2; uint32 limit = 3; } -// GetBlockLocatorMessage end -// BlockLocatorMessage start message BlockLocatorMessage{ repeated Hash hashes = 1; } -// BlockLocatorMessage end -// GetBlocksMessage start message RequestHeadersMessage{ Hash lowHash = 1; Hash highHash = 2; } -// GetBlocksMessage end -// RequestNextIBDBlocksMessage start message RequestNextHeadersMessage{ } -// RequestNextIBDBlocksMessage end -// DoneIBDBlocksMessage start message DoneHeadersMessage{ } -// DoneIBDBlocksMessage end -// RequestRelayBlocksMessage start message RequestRelayBlocksMessage{ repeated Hash hashes = 1; } -// RequestRelayBlocksMessage end -// RequestTransactionsMessage start message RequestTransactionsMessage { repeated TransactionId ids = 1; } -// GetTransactionsMessage end -// TransactionNotFoundMessage start message TransactionNotFoundMessage{ TransactionId id = 1; } -// TransactionsNotFoundMessage end -// InvRelayBlockMessage start message InvRelayBlockMessage{ Hash hash = 1; } -// InvRelayBlockMessage end -// InvTransactionMessage start message InvTransactionsMessage{ repeated TransactionId ids = 1; } -// InvTransactionMessage end -// PingMessage start message PingMessage{ uint64 nonce = 1; } -// PingMessage end -// PongMessage start message PongMessage{ uint64 nonce = 1; } -// PongMessage end -// VerackMessage start message VerackMessage{ } -// VerackMessage end -// VersionMessage start message VersionMessage{ uint32 protocolVersion = 1; uint64 services = 2; @@ -176,61 +141,47 @@ message VersionMessage{ SubnetworkId subnetworkId = 9; string network = 10; } -// VersionMessage end -// RejectMessage start message RejectMessage{ string reason = 1; } -// RejectMessage end -// RequestIBDRootUTXOSetAndBlockMessage start message RequestIBDRootUTXOSetAndBlockMessage{ Hash ibdRoot = 1; } -// RequestIBDRootUTXOSetAndBlockMessage end -// IBDRootUTXOSetAndBlockMessage start -message IBDRootUTXOSetAndBlockMessage{ - bytes utxoSet = 1; - BlockMessage block = 2; +message IbdRootUtxoSetChunkMessage{ + bytes chunk = 1; +} + +message RequestNextIbdRootUtxoSetChunkMessage { +} + +message DoneIbdRootUtxoSetChunksMessage { } -// IBDRootUTXOSetAndBlockMessage end -// RequestIBDBlocksMessage start message RequestIBDBlocksMessage{ repeated Hash hashes = 1; } -// RequestIBDBlocksMessage end -// IBDRootNotFoundMessage start message IBDRootNotFoundMessage{ } -// IBDRootNotFoundMessage end -// RequestIBDRootHashMessage start message RequestIBDRootHashMessage{ } -// RequestIBDRootHashMessage end -// IBDRootHashMessage start message IBDRootHashMessage{ Hash hash = 1; } -// IBDRootHashMessage end -// IbdBlockLocatorMessage start message IbdBlockLocatorMessage { Hash targetHash = 1; repeated Hash blockLocatorHashes = 2; } -// IbdBlockLocatorMessage end -// IbdBlockLocatorHighestHashMessage start message IbdBlockLocatorHighestHashMessage { Hash highestHash = 1; } -// IbdBlockLocatorHighestHashMessage end message BlockHeadersMessage { repeated BlockHeaderMessage blockHeaders = 1; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go new file mode 100644 index 000000000..4c9a75059 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go @@ -0,0 +1,12 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_DoneIbdRootUtxoSetChunks) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgDoneIBDRootUTXOSetChunks{}, nil +} + +func (x *KaspadMessage_DoneIbdRootUtxoSetChunks) fromAppMessage(_ *appmessage.MsgDoneIBDRootUTXOSetChunks) error { + x.DoneIbdRootUtxoSetChunks = &DoneIbdRootUtxoSetChunksMessage{} + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go deleted file mode 100644 index 3ac16aa0b..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_and_block.go +++ /dev/null @@ -1,21 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_IbdRootUTXOSetAndBlock) toAppMessage() (appmessage.Message, error) { - msgBlock, err := x.IbdRootUTXOSetAndBlock.Block.toAppMessage() - if err != nil { - return nil, err - } - return &appmessage.MsgIBDRootUTXOSetAndBlock{ - UTXOSet: x.IbdRootUTXOSetAndBlock.UtxoSet, - Block: msgBlock, - }, nil -} - -func (x *KaspadMessage_IbdRootUTXOSetAndBlock) fromAppMessage(msgIBDRootUTXOSetAndBlock *appmessage.MsgIBDRootUTXOSetAndBlock) error { - x.IbdRootUTXOSetAndBlock = &IBDRootUTXOSetAndBlockMessage{} - x.IbdRootUTXOSetAndBlock.UtxoSet = msgIBDRootUTXOSetAndBlock.UTXOSet - x.IbdRootUTXOSetAndBlock.Block = &BlockMessage{} - return x.IbdRootUTXOSetAndBlock.Block.fromAppMessage(msgIBDRootUTXOSetAndBlock.Block) -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go new file mode 100644 index 000000000..22dcdebbe --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go @@ -0,0 +1,16 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_IbdRootUtxoSetChunk) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgIBDRootUTXOSetChunk{ + Chunk: x.IbdRootUtxoSetChunk.Chunk, + }, nil +} + +func (x *KaspadMessage_IbdRootUtxoSetChunk) fromAppMessage(message *appmessage.MsgIBDRootUTXOSetChunk) error { + x.IbdRootUtxoSetChunk = &IbdRootUtxoSetChunkMessage{ + Chunk: message.Chunk, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go new file mode 100644 index 000000000..fbdb88db4 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go @@ -0,0 +1,12 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestNextIbdRootUtxoSetChunk) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgRequestNextIBDRootUTXOSetChunk{}, nil +} + +func (x *KaspadMessage_RequestNextIbdRootUtxoSetChunk) fromAppMessage(message *appmessage.MsgRequestNextIBDRootUTXOSetChunk) error { + x.RequestNextIbdRootUtxoSetChunk = &RequestNextIbdRootUtxoSetChunkMessage{} + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index fff7537c2..26c7038a5 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -202,8 +202,8 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgIBDRootUTXOSetAndBlock: - payload := new(KaspadMessage_IbdRootUTXOSetAndBlock) + case *appmessage.MsgIBDRootUTXOSetChunk: + payload := new(KaspadMessage_IbdRootUtxoSetChunk) err := payload.fromAppMessage(message) if err != nil { return nil, err @@ -258,6 +258,20 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.MsgRequestNextIBDRootUTXOSetChunk: + payload := new(KaspadMessage_RequestNextIbdRootUtxoSetChunk) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.MsgDoneIBDRootUTXOSetChunks: + payload := new(KaspadMessage_DoneIbdRootUtxoSetChunks) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil default: return nil, nil } From a35f8269ea6e75acbb6905fff1d44f41d3148236 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 14 Jan 2021 10:56:22 +0200 Subject: [PATCH 251/351] Add checkBlockIsNotPruned (#1413) * Add checkBlockIsNotPruned * Fix test name and comment Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- domain/consensus/factory.go | 1 + .../blockvalidator/block_body_in_context.go | 38 +++++++++++- .../block_body_in_context_test.go | 60 +++++++++++++++++++ .../blockvalidator/blockvalidator.go | 25 ++++---- domain/consensus/ruleerrors/rule_error.go | 3 + 5 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 domain/consensus/processes/blockvalidator/block_body_in_context_test.go diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 38ec3cc26..b9da722ee 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -192,6 +192,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockHeaderStore, blockStatusStore, reachabilityDataStore, + consensusStateStore, ) consensusStateManager, err := consensusstatemanager.New( dbManager, diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context.go b/domain/consensus/processes/blockvalidator/block_body_in_context.go index ca8c3a74f..b3147d653 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context.go @@ -17,7 +17,12 @@ func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext") defer onEnd() - err := v.checkBlockTransactionsFinalized(blockHash) + err := v.checkBlockIsNotPruned(blockHash) + if err != nil { + return err + } + + err = v.checkBlockTransactionsFinalized(blockHash) if err != nil { return err } @@ -31,6 +36,37 @@ func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash return nil } +// checkBlockIsNotPruned Checks we don't add block bodies to pruned blocks +func (v *blockValidator) checkBlockIsNotPruned(blockHash *externalapi.DomainHash) error { + hasValidatedHeader, err := v.hasValidatedHeader(blockHash) + if err != nil { + return err + } + + // If we don't add block body to a header only block it can't be in the past + // of the tips, because it'll be a new tip. + if !hasValidatedHeader { + return nil + } + + tips, err := v.consensusStateStore.Tips(v.databaseContext) + if err != nil { + return err + } + + isAncestorOfSomeTips, err := v.dagTopologyManager.IsAncestorOfAny(blockHash, tips) + if err != nil { + return err + } + + // A header only block in the past of one of the tips has to be pruned + if isAncestorOfSomeTips { + return errors.Wrapf(ruleerrors.ErrPrunedBlock, "cannot add block body to a pruned block %s", blockHash) + } + + return nil +} + func (v *blockValidator) checkParentBlockBodiesExist(blockHash *externalapi.DomainHash) error { missingParentHashes := []*externalapi.DomainHash{} header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go new file mode 100644 index 000000000..232eac83a --- /dev/null +++ b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go @@ -0,0 +1,60 @@ +package blockvalidator_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" + "testing" +) + +func TestCheckBlockIsNotPruned(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // This is done to reduce the pruning depth to 6 blocks + params.FinalityDuration = 2 * params.TargetTimePerBlock + params.K = 0 + + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockIsNotPruned") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + // Add blocks until the pruning point changes + tipHash := params.GenesisHash + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + beforePruningBlock, err := tc.GetBlock(tipHash) + if err != nil { + t.Fatalf("beforePruningBlock: %+v", err) + } + + for { + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + pruningPoint, err := tc.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + + _, err = tc.ValidateAndInsertBlock(beforePruningBlock) + if !errors.Is(err, ruleerrors.ErrPrunedBlock) { + t.Fatalf("Unexpected error: %+v", err) + } + }) +} diff --git a/domain/consensus/processes/blockvalidator/blockvalidator.go b/domain/consensus/processes/blockvalidator/blockvalidator.go index e73209f29..1fb52cc5b 100644 --- a/domain/consensus/processes/blockvalidator/blockvalidator.go +++ b/domain/consensus/processes/blockvalidator/blockvalidator.go @@ -35,11 +35,12 @@ type blockValidator struct { pruningStore model.PruningStore reachabilityManager model.ReachabilityManager - blockStore model.BlockStore - ghostdagDataStore model.GHOSTDAGDataStore - blockHeaderStore model.BlockHeaderStore - blockStatusStore model.BlockStatusStore - reachabilityStore model.ReachabilityDataStore + blockStore model.BlockStore + ghostdagDataStore model.GHOSTDAGDataStore + blockHeaderStore model.BlockHeaderStore + blockStatusStore model.BlockStatusStore + reachabilityStore model.ReachabilityDataStore + consensusStateStore model.ConsensusStateStore } // New instantiates a new BlockValidator @@ -72,6 +73,7 @@ func New(powMax *big.Int, blockHeaderStore model.BlockHeaderStore, blockStatusStore model.BlockStatusStore, reachabilityStore model.ReachabilityDataStore, + consensusStateStore model.ConsensusStateStore, ) model.BlockValidator { return &blockValidator{ @@ -97,11 +99,12 @@ func New(powMax *big.Int, mergeDepthManager: mergeDepthManager, reachabilityManager: reachabilityManager, - pruningStore: pruningStore, - blockStore: blockStore, - ghostdagDataStore: ghostdagDataStore, - blockHeaderStore: blockHeaderStore, - blockStatusStore: blockStatusStore, - reachabilityStore: reachabilityStore, + pruningStore: pruningStore, + blockStore: blockStore, + ghostdagDataStore: ghostdagDataStore, + blockHeaderStore: blockHeaderStore, + blockStatusStore: blockStatusStore, + reachabilityStore: reachabilityStore, + consensusStateStore: consensusStateStore, } } diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index bdc88e58d..2df60003c 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -185,6 +185,9 @@ var ( //ErrTransactionVersionIsUnknown indicates that the transaction version is unknown. ErrTransactionVersionIsUnknown = newRuleError("ErrTransactionVersionIsUnknown") + + // ErrPrunedBlock indicates that the block currently being validated had already been pruned. + ErrPrunedBlock = newRuleError("ErrPrunedBlock") ) // RuleError identifies a rule violation. It is used to indicate that From 10b519a3e2ebaf71399f1de6ddfdf8cfec7f8113 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 14 Jan 2021 11:06:08 +0200 Subject: [PATCH 252/351] Add tests to ValidateHeaderInIsolation (#1415) * Add tests to ValidateHeaderInIsolation * Fix tests db names Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- .../block_header_in_isolation_test.go | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 domain/consensus/processes/blockvalidator/block_header_in_isolation_test.go diff --git a/domain/consensus/processes/blockvalidator/block_header_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_header_in_isolation_test.go new file mode 100644 index 000000000..78d64afc1 --- /dev/null +++ b/domain/consensus/processes/blockvalidator/block_header_in_isolation_test.go @@ -0,0 +1,114 @@ +package blockvalidator_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/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util/mstime" + "github.com/pkg/errors" + "testing" +) + +func TestCheckParentsLimit(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentsLimit") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + for i := model.KType(0); i < params.MaxBlockParents+1; i++ { + _, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + } + + tips, err := tc.Tips() + if err != nil { + t.Fatalf("Tips: %+v", err) + } + + _, _, err = tc.AddBlock(tips, nil, nil) + if !errors.Is(err, ruleerrors.ErrTooManyParents) { + t.Fatalf("Unexpected error: %+v", err) + } + }) +} + +func TestCheckBlockVersion(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockVersion") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + block.Header = blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion+1, + block.Header.ParentHashes(), + block.Header.HashMerkleRoot(), + block.Header.AcceptedIDMerkleRoot(), + block.Header.UTXOCommitment(), + block.Header.TimeInMilliseconds(), + block.Header.Bits(), + block.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(block) + if !errors.Is(err, ruleerrors.ErrBlockVersionIsUnknown) { + t.Fatalf("Unexpected error: %+v", err) + } + }) +} + +func TestCheckBlockTimestampInIsolation(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockTimestampInIsolation") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + // Give 10 seconds slack to take care of the test duration + timestamp := mstime.Now().UnixMilliseconds() + + int64(params.TimestampDeviationTolerance)*params.TargetTimePerBlock.Milliseconds() + 10_000 + + block.Header = blockheader.NewImmutableBlockHeader( + block.Header.Version(), + block.Header.ParentHashes(), + block.Header.HashMerkleRoot(), + block.Header.AcceptedIDMerkleRoot(), + block.Header.UTXOCommitment(), + timestamp, + block.Header.Bits(), + block.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(block) + if !errors.Is(err, ruleerrors.ErrTimeTooMuchInTheFuture) { + t.Fatalf("Unexpected error: %+v", err) + } + }) +} From a1381d6768220af436217b65b11d126f2982ce79 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 14 Jan 2021 13:31:17 +0200 Subject: [PATCH 253/351] Add TestCheckParentBlockBodiesExist (#1405) * Add TestCheckParentBlockBodiesExist * Use block in pruning point's anticone for the test * Fix test db name --- .../model/testapi/test_block_builder.go | 5 ++ .../consensus/model/testapi/test_consensus.go | 10 ++- .../blockbuilder/test_block_builder.go | 77 ++++++++++++++++--- .../validateandinsertblock_test.go | 4 +- .../block_body_in_context_test.go | 70 +++++++++++++++++ domain/consensus/test_consensus.go | 46 ++++++++++- 6 files changed, 195 insertions(+), 17 deletions(-) diff --git a/domain/consensus/model/testapi/test_block_builder.go b/domain/consensus/model/testapi/test_block_builder.go index ce2e4d9bb..8fc40cd69 100644 --- a/domain/consensus/model/testapi/test_block_builder.go +++ b/domain/consensus/model/testapi/test_block_builder.go @@ -13,4 +13,9 @@ type TestBlockBuilder interface { // and returns the block together with its past UTXO-diff from the virtual. BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) + + BuildUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (externalapi.BlockHeader, error) + + BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, + error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index b1ec12320..5e7c5e726 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -18,13 +18,19 @@ type TestConsensus interface { BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error) + BuildHeaderWithParents(parentHashes []*externalapi.DomainHash) (externalapi.BlockHeader, error) + + BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) + // 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, *externalapi.BlockInsertionResult, error) - AddHeader(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) + AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) + + AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, + *externalapi.BlockInsertionResult, error) DiscardAllStores() diff --git a/domain/consensus/processes/blockbuilder/test_block_builder.go b/domain/consensus/processes/blockbuilder/test_block_builder.go index 6316216e4..6fdc00586 100644 --- a/domain/consensus/processes/blockbuilder/test_block_builder.go +++ b/domain/consensus/processes/blockbuilder/test_block_builder.go @@ -61,9 +61,8 @@ func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.Do return block, diff, nil } -func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, - transactions []*externalapi.DomainTransaction, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) ( - externalapi.BlockHeader, error) { +func (bb *testBlockBuilder) buildUTXOInvalidHeader(parentHashes []*externalapi.DomainHash, + transactions []*externalapi.DomainTransaction) (externalapi.BlockHeader, error) { timeInMilliseconds, err := bb.minBlockTime(tempBlockHash) if err != nil { @@ -74,6 +73,31 @@ func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.D if err != nil { return nil, err } + + hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions) + + bb.nonceCounter++ + return blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + parentHashes, + hashMerkleRoot, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + timeInMilliseconds, + bits, + bb.nonceCounter, + ), nil +} + +func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash, + transactions []*externalapi.DomainTransaction, acceptanceData externalapi.AcceptanceData, multiset model.Multiset) ( + externalapi.BlockHeader, error) { + + header, err := bb.buildUTXOInvalidHeader(parentHashes, transactions) + if err != nil { + return nil, err + } + hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions) acceptedIDMerkleRoot, err := bb.calculateAcceptedIDMerkleRoot(acceptanceData) if err != nil { @@ -81,16 +105,15 @@ func (bb *testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.D } utxoCommitment := multiset.Hash() - bb.nonceCounter++ return blockheader.NewImmutableBlockHeader( - constants.MaxBlockVersion, - parentHashes, + header.Version(), + header.ParentHashes(), hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, - timeInMilliseconds, - bits, - bb.nonceCounter, + header.TimeInMilliseconds(), + header.Bits(), + header.Nonce(), ), nil } @@ -150,3 +173,39 @@ func (bb *testBlockBuilder) buildBlockWithParents(parentHashes []*externalapi.Do Transactions: transactionsWithCoinbase, }, pastUTXO, nil } + +func (bb *testBlockBuilder) BuildUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (externalapi.BlockHeader, + error) { + + block, err := bb.BuildUTXOInvalidBlock(parentHashes) + if err != nil { + return nil, err + } + + return block.Header, nil +} + +func (bb *testBlockBuilder) BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, + error) { + + defer bb.testConsensus.DiscardAllStores() + + bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes}) + + err := bb.ghostdagManager.GHOSTDAG(tempBlockHash) + if err != nil { + return nil, err + } + + // We use genesis transactions so we'll have something to build merkle root and coinbase with + genesisTransactions := bb.testConsensus.DAGParams().GenesisBlock.Transactions + header, err := bb.buildUTXOInvalidHeader(parentHashes, genesisTransactions) + if err != nil { + return nil, err + } + + return &externalapi.DomainBlock{ + Header: header, + Transactions: genesisTransactions, + }, nil +} diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go index 8552c5565..f0f5c44a7 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go @@ -44,9 +44,9 @@ func TestBlockStatus(t *testing.T) { checkStatus(tipHash, externalapi.StatusUTXOValid) } - headerHash, _, err := tc.AddHeader([]*externalapi.DomainHash{tipHash}, nil, nil) + headerHash, _, err := tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{tipHash}) if err != nil { - t.Fatalf("AddBlock: %+v", err) + t.Fatalf("AddUTXOInvalidHeader: %+v", err) } checkStatus(headerHash, externalapi.StatusHeaderOnly) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go index 232eac83a..13a77f5e1 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go @@ -58,3 +58,73 @@ func TestCheckBlockIsNotPruned(t *testing.T) { } }) } + +func TestCheckParentBlockBodiesExist(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // This is done to reduce the pruning depth to 6 blocks + params.FinalityDuration = 2 * params.TargetTimePerBlock + params.K = 0 + + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentBlockBodiesExist") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + headerHash, _, err := tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{params.GenesisHash}) + if err != nil { + t.Fatalf("AddUTXOInvalidHeader: %+v", err) + } + + _, _, err = tc.AddUTXOInvalidBlock([]*externalapi.DomainHash{headerHash}) + errMissingParents := &ruleerrors.ErrMissingParents{} + if !errors.As(err, errMissingParents) { + t.Fatalf("Unexpected error: %+v", err) + } + + if !externalapi.HashesEqual(errMissingParents.MissingParentHashes, []*externalapi.DomainHash{headerHash}) { + t.Fatalf("unexpected missing parents %s", errMissingParents.MissingParentHashes) + } + + // Add blocks until the pruning point changes + tipHash := params.GenesisHash + anticonePruningBlock, err := tc.BuildUTXOInvalidBlock([]*externalapi.DomainHash{tipHash}) + if err != nil { + t.Fatalf("BuildUTXOInvalidBlock: %+v", err) + } + + // Add only the header of anticonePruningBlock + _, err = tc.ValidateAndInsertBlock(&externalapi.DomainBlock{ + Header: anticonePruningBlock.Header, + Transactions: nil, + }) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + for { + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddUTXOInvalidHeader: %+v", err) + } + + pruningPoint, err := tc.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + + // Add anticonePruningBlock's body and Check that it's valid to point to + // a header only block in the past of the pruning point. + _, err = tc.ValidateAndInsertBlock(anticonePruningBlock) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + }) +} diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 7c18b13e7..35e490f0c 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -60,19 +60,40 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba return consensushashing.BlockHash(block), blockInsertionResult, nil } -func (tc *testConsensus) AddHeader(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData, - transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) { +func (tc *testConsensus) AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, + *externalapi.BlockInsertionResult, error) { // Require write lock because BuildBlockWithParents stages temporary data tc.lock.Lock() defer tc.lock.Unlock() - block, _, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions) + header, err := tc.testBlockBuilder.BuildUTXOInvalidHeader(parentHashes) if err != nil { return nil, nil, err } - block.Transactions = nil + blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(&externalapi.DomainBlock{ + Header: header, + Transactions: nil, + }) + if err != nil { + return nil, nil, err + } + + return consensushashing.HeaderHash(header), blockInsertionResult, nil +} + +func (tc *testConsensus) AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, + *externalapi.BlockInsertionResult, error) { + + // Require write lock because BuildBlockWithParents stages temporary data + tc.lock.Lock() + defer tc.lock.Unlock() + + block, err := tc.testBlockBuilder.BuildUTXOInvalidBlock(parentHashes) + if err != nil { + return nil, nil, err + } blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(block) if err != nil { @@ -82,6 +103,23 @@ func (tc *testConsensus) AddHeader(parentHashes []*externalapi.DomainHash, coinb return consensushashing.BlockHash(block), blockInsertionResult, nil } +func (tc *testConsensus) BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) { + + // Require write lock because BuildBlockWithParents stages temporary data + tc.lock.Lock() + defer tc.lock.Unlock() + + return tc.testBlockBuilder.BuildUTXOInvalidBlock(parentHashes) +} + +func (tc *testConsensus) BuildHeaderWithParents(parentHashes []*externalapi.DomainHash) (externalapi.BlockHeader, error) { + // Require write lock because BuildUTXOInvalidHeader stages temporary data + tc.lock.Lock() + defer tc.lock.Unlock() + + return tc.testBlockBuilder.BuildUTXOInvalidHeader(parentHashes) +} + func (tc *testConsensus) DiscardAllStores() { tc.AcceptanceDataStore().Discard() tc.BlockHeaderStore().Discard() From 67be4d82bf51a892495c91dd30454ad4f083fe1b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 17 Jan 2021 10:40:05 +0200 Subject: [PATCH 254/351] Don't mark bad merkle root as invalid (#1419) * Don't mark bad merkle root as invalid * Fix TestBlockStatus * Move discardAllChanges inside the inner if --- .../validateandinsertblock_test.go | 5 ++- .../processes/blockprocessor/validateblock.go | 10 +++-- .../blockvalidator/block_body_in_isolation.go | 10 ++--- .../block_body_in_isolation_test.go | 38 +++++++++++++++++-- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go index f0f5c44a7..03086d213 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go @@ -1,6 +1,8 @@ package blockprocessor_test import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" "strings" "testing" @@ -84,10 +86,11 @@ func TestBlockStatus(t *testing.T) { if err != nil { t.Fatalf("AddBlock: %+v", err) } + invalidBlock.Transactions[0].Version = constants.MaxTransactionVersion + 1 // This should invalidate the block invalidBlock.Header = blockheader.NewImmutableBlockHeader( disqualifiedBlock.Header.Version(), disqualifiedBlock.Header.ParentHashes(), - externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}), // This should invalidate the block + merkle.CalculateHashMerkleRoot(invalidBlock.Transactions), disqualifiedBlock.Header.AcceptedIDMerkleRoot(), disqualifiedBlock.Header.UTXOCommitment(), disqualifiedBlock.Header.TimeInMilliseconds(), diff --git a/domain/consensus/processes/blockprocessor/validateblock.go b/domain/consensus/processes/blockprocessor/validateblock.go index 8d2d163b6..11ce29a80 100644 --- a/domain/consensus/processes/blockprocessor/validateblock.go +++ b/domain/consensus/processes/blockprocessor/validateblock.go @@ -53,10 +53,14 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, isPrunin err = bp.validatePostProofOfWork(block, isPruningPoint) if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { - bp.discardAllChanges() // If we got ErrMissingParents the block shouldn't be considered as invalid - // because it could be added later on when its parents are present. - if !errors.As(err, &ruleerrors.ErrMissingParents{}) { + // because it could be added later on when its parents are present, and if + // we get ErrBadMerkleRoot we shouldn't mark the block as invalid because + // later on we can get the block with transactions that fits the merkle + // root. + if !errors.As(err, &ruleerrors.ErrMissingParents{}) && !errors.Is(err, ruleerrors.ErrBadMerkleRoot) { + // Discard all changes so we save only the block status + bp.discardAllChanges() hash := consensushashing.BlockHash(block) bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid) commitErr := bp.commitAllChanges() diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go index 3c1bdb48b..9da0ff1ec 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation.go @@ -28,6 +28,11 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa return err } + err = v.checkBlockHashMerkleRoot(block) + if err != nil { + return err + } + err = v.checkBlockSize(block) if err != nil { return err @@ -63,11 +68,6 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa return err } - err = v.checkBlockHashMerkleRoot(block) - if err != nil { - return err - } - err = v.checkBlockDuplicateTransactions(block) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 5906b8f30..847ab3a0d 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -714,10 +714,10 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ }), }, externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ - 0xac, 0xa4, 0x21, 0xe1, 0xa6, 0xc3, 0xbe, 0x5d, - 0x52, 0x66, 0xf3, 0x0b, 0x21, 0x87, 0xbc, 0xf3, - 0xf3, 0x2d, 0xd1, 0x05, 0x64, 0xb5, 0x16, 0x76, - 0xe4, 0x66, 0x7d, 0x51, 0x53, 0x18, 0x6d, 0xb1, + 0xaf, 0xba, 0x3c, 0x18, 0x9e, 0x44, 0xac, 0x7c, + 0xb7, 0xcc, 0x90, 0x0b, 0x75, 0x88, 0x6b, 0x9c, + 0x3e, 0xc9, 0xea, 0xf1, 0x5c, 0xaf, 0x28, 0x30, + 0x34, 0x23, 0xf5, 0xeb, 0x18, 0xdf, 0xd1, 0x75, }), externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ 0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, @@ -1004,3 +1004,33 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{ }, }, } + +func TestCheckBlockHashMerkleRoot(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockHashMerkleRoot") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + blockWithInvalidMerkleRoot := block.Clone() + blockWithInvalidMerkleRoot.Transactions[0].Version += 1 + + _, err = tc.ValidateAndInsertBlock(blockWithInvalidMerkleRoot) + if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) { + t.Fatalf("Unexpected error: %+v", err) + } + + // Check that a block with invalid merkle root is not marked as invalid + // and can be re-added with the right transactions. + _, err = tc.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + }) +} From dd57e6abe650fab87769f36ce3055d3a07de55bb Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 17 Jan 2021 11:27:04 +0200 Subject: [PATCH 255/351] Fix checkParentHeadersExist and cover pruning_violation_proof_of_work_and_difficulty.go with tests (#1418) * Fix checkParentHeadersExist and cover pruning_violation_proof_of_work_and_difficulty.go with tests * Remove unused variable * Change consensus violation * Change condition order * Get rid of irrelevant error codes in extractRejectCode * Fix wrong test db names * Fix checkParentHeadersExist --- .../blockvalidator/proof_of_work_test.go | 70 ----- ...violation_proof_of_work_and_difficulty.go} | 23 +- ...ation_proof_of_work_and_difficulty_test.go | 243 ++++++++++++++++++ domain/consensus/ruleerrors/rule_error.go | 16 +- domain/consensus/utils/math/math.go | 153 ----------- domain/consensus/utils/math/math_test.go | 123 --------- domain/consensus/utils/mining/solve.go | 4 +- domain/miningmanager/mempool/error.go | 33 --- infrastructure/config/network.go | 4 +- util/difficulty/difficulty_test.go | 88 +++++++ 10 files changed, 357 insertions(+), 400 deletions(-) delete mode 100644 domain/consensus/processes/blockvalidator/proof_of_work_test.go rename domain/consensus/processes/blockvalidator/{proof_of_work.go => pruning_violation_proof_of_work_and_difficulty.go} (88%) create mode 100644 domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go delete mode 100644 domain/consensus/utils/math/math.go delete mode 100644 domain/consensus/utils/math/math_test.go diff --git a/domain/consensus/processes/blockvalidator/proof_of_work_test.go b/domain/consensus/processes/blockvalidator/proof_of_work_test.go deleted file mode 100644 index ddc6b479e..000000000 --- a/domain/consensus/processes/blockvalidator/proof_of_work_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package blockvalidator_test - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/pow" - "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/domain/consensus/utils/mining" - "github.com/kaspanet/kaspad/util/difficulty" - "math" - "math/rand" - - "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" - "github.com/pkg/errors" -) - -// TestPOW tests the validation of the block's POW. -func TestPOW(t *testing.T) { - // We set the flag "skip pow" to be false (second argument in the function) for not skipping the check of POW and validate its correctness. - testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { - factory := consensus.NewFactory() - tc, teardown, err := factory.NewTestConsensus(params, false, "TestPOW") - if err != nil { - t.Fatalf("Error setting up consensus: %+v", err) - } - defer teardown(false) - - // Builds and checks block with invalid POW. - invalidBlockWrongPOW, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) - if err != nil { - t.Fatal(err) - } - invalidBlockWrongPOW = solveBlockWithWrongPOW(invalidBlockWrongPOW) - _, err = tc.ValidateAndInsertBlock(invalidBlockWrongPOW) - if !errors.Is(err, ruleerrors.ErrInvalidPoW) { - t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrInvalidPoW, err) - } - - // test on a valid block. - validBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) - if err != nil { - t.Fatal(err) - } - random := rand.New(rand.NewSource(0)) - mining.SolveBlock(validBlock, random) - _, err = tc.ValidateAndInsertBlock(validBlock) - if err != nil { - t.Fatal(err) - } - }) -} - -// solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!). -func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock { - targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) - headerForMining := block.Header.ToMutable() - initialNonce := uint64(0) - for i := initialNonce; i < math.MaxUint64; i++ { - headerForMining.SetNonce(i) - if !pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { - block.Header = headerForMining.ToImmutable() - return block - } - } - - panic("Failed to solve block! cannot find a invalid POW for the test") -} diff --git a/domain/consensus/processes/blockvalidator/proof_of_work.go b/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty.go similarity index 88% rename from domain/consensus/processes/blockvalidator/proof_of_work.go rename to domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty.go index cddf21b04..6ea6b2aa7 100644 --- a/domain/consensus/processes/blockvalidator/proof_of_work.go +++ b/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty.go @@ -5,6 +5,7 @@ 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/db/database" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/util/difficulty" "github.com/pkg/errors" @@ -83,13 +84,13 @@ func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error // The target difficulty must be larger than zero. target := difficulty.CompactToBig(header.Bits()) if target.Sign() <= 0 { - return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block target difficulty of %064x is too low", + return errors.Wrapf(ruleerrors.ErrNegativeTarget, "block target difficulty of %064x is too low", target) } // The target difficulty must be less than the maximum allowed. if target.Cmp(v.powMax) > 0 { - return errors.Wrapf(ruleerrors.ErrUnexpectedDifficulty, "block target difficulty of %064x is "+ + return errors.Wrapf(ruleerrors.ErrTargetTooHigh, "block target difficulty of %064x is "+ "higher than max of %064x", target, v.powMax) } @@ -111,18 +112,18 @@ func (v *blockValidator) checkParentHeadersExist(header externalapi.BlockHeader) return err } if !parentHeaderExists { + parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent) + if err != nil { + if !database.IsNotFoundError(err) { + return err + } + } else if parentStatus == externalapi.StatusInvalid { + return errors.Wrapf(ruleerrors.ErrInvalidAncestorBlock, "parent %s is invalid", parent) + } + missingParentHashes = append(missingParentHashes, parent) continue } - - 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 len(missingParentHashes) > 0 { diff --git a/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go b/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go new file mode 100644 index 000000000..a78d355dc --- /dev/null +++ b/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go @@ -0,0 +1,243 @@ +package blockvalidator_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" + "github.com/kaspanet/kaspad/domain/consensus/utils/mining" + "github.com/kaspanet/kaspad/util/difficulty" + "math" + "math/big" + "math/rand" + + "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" + "github.com/pkg/errors" +) + +// TestPOW tests the validation of the block's POW. +func TestPOW(t *testing.T) { + // We set the flag "skip pow" to be false (second argument in the function) for not skipping the check of POW and validate its correctness. + testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestPOW") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + // Builds and checks block with invalid POW. + invalidBlockWrongPOW, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + invalidBlockWrongPOW = solveBlockWithWrongPOW(invalidBlockWrongPOW) + _, err = tc.ValidateAndInsertBlock(invalidBlockWrongPOW) + if !errors.Is(err, ruleerrors.ErrInvalidPoW) { + t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrInvalidPoW, err) + } + + abovePowMaxBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + + abovePowMaxTarget := big.NewInt(0).Add(big.NewInt(1), params.PowMax) + abovePowMaxBlock.Header = blockheader.NewImmutableBlockHeader( + abovePowMaxBlock.Header.Version(), + abovePowMaxBlock.Header.ParentHashes(), + abovePowMaxBlock.Header.HashMerkleRoot(), + abovePowMaxBlock.Header.AcceptedIDMerkleRoot(), + abovePowMaxBlock.Header.UTXOCommitment(), + abovePowMaxBlock.Header.TimeInMilliseconds(), + difficulty.BigToCompact(abovePowMaxTarget), + abovePowMaxBlock.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(abovePowMaxBlock) + if !errors.Is(err, ruleerrors.ErrTargetTooHigh) { + t.Fatalf("Unexpected error: %+v", err) + } + + negativeTargetBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + + negativeTargetBlock.Header = blockheader.NewImmutableBlockHeader( + negativeTargetBlock.Header.Version(), + negativeTargetBlock.Header.ParentHashes(), + negativeTargetBlock.Header.HashMerkleRoot(), + negativeTargetBlock.Header.AcceptedIDMerkleRoot(), + negativeTargetBlock.Header.UTXOCommitment(), + negativeTargetBlock.Header.TimeInMilliseconds(), + 0x00800000, + negativeTargetBlock.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(negativeTargetBlock) + if !errors.Is(err, ruleerrors.ErrNegativeTarget) { + t.Fatalf("Unexpected error: %+v", err) + } + + // test on a valid block. + validBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + random := rand.New(rand.NewSource(0)) + mining.SolveBlock(validBlock, random) + _, err = tc.ValidateAndInsertBlock(validBlock) + if err != nil { + t.Fatal(err) + } + }) +} + +// solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!). +func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock { + targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) + headerForMining := block.Header.ToMutable() + initialNonce := uint64(0) + for i := initialNonce; i < math.MaxUint64; i++ { + headerForMining.SetNonce(i) + if !pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { + block.Header = headerForMining.ToImmutable() + return block + } + } + + panic("Failed to solve block! cannot find a invalid POW for the test") +} + +func TestCheckParentHeadersExist(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentHeadersExist") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + orphanBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + + parentHash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{}) // Non existing parent hash + orphanBlock.Header = blockheader.NewImmutableBlockHeader( + orphanBlock.Header.Version(), + []*externalapi.DomainHash{ + parentHash, + }, + orphanBlock.Header.HashMerkleRoot(), + orphanBlock.Header.AcceptedIDMerkleRoot(), + orphanBlock.Header.UTXOCommitment(), + orphanBlock.Header.TimeInMilliseconds(), + orphanBlock.Header.Bits(), + orphanBlock.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(orphanBlock) + errMissingParents := &ruleerrors.ErrMissingParents{} + if !errors.As(err, errMissingParents) { + t.Fatalf("Unexpected error: %+v", err) + } + + if !externalapi.HashesEqual(errMissingParents.MissingParentHashes, []*externalapi.DomainHash{parentHash}) { + t.Fatalf("unexpected missing parents %s", errMissingParents.MissingParentHashes) + } + + invalidBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + + invalidBlock.Transactions[0].Version = constants.MaxTransactionVersion + 1 // This should invalidate the block + invalidBlock.Header = blockheader.NewImmutableBlockHeader( + invalidBlock.Header.Version(), + invalidBlock.Header.ParentHashes(), + merkle.CalculateHashMerkleRoot(invalidBlock.Transactions), + orphanBlock.Header.AcceptedIDMerkleRoot(), + orphanBlock.Header.UTXOCommitment(), + orphanBlock.Header.TimeInMilliseconds(), + orphanBlock.Header.Bits(), + orphanBlock.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(invalidBlock) + if !errors.Is(err, ruleerrors.ErrTransactionVersionIsUnknown) { + t.Fatalf("Unexpected error: %+v", err) + } + + invalidBlockHash := consensushashing.BlockHash(invalidBlock) + + invalidBlockChild, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatal(err) + } + + invalidBlockChild.Header = blockheader.NewImmutableBlockHeader( + invalidBlockChild.Header.Version(), + []*externalapi.DomainHash{invalidBlockHash}, + invalidBlockChild.Header.HashMerkleRoot(), + invalidBlockChild.Header.AcceptedIDMerkleRoot(), + invalidBlockChild.Header.UTXOCommitment(), + invalidBlockChild.Header.TimeInMilliseconds(), + invalidBlockChild.Header.Bits(), + invalidBlockChild.Header.Nonce(), + ) + + _, err = tc.ValidateAndInsertBlock(invalidBlockChild) + if !errors.Is(err, ruleerrors.ErrInvalidAncestorBlock) { + t.Fatalf("Unexpected error: %+v", err) + } + }) +} + +func TestCheckPruningPointViolation(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // This is done to reduce the pruning depth to 6 blocks + params.FinalityDuration = 2 * params.TargetTimePerBlock + params.K = 0 + + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckPruningPointViolation") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + // Add blocks until the pruning point changes + tipHash := params.GenesisHash + for { + tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + pruningPoint, err := tc.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + + _, _, err = tc.AddUTXOInvalidBlock([]*externalapi.DomainHash{params.GenesisHash}) + if !errors.Is(err, ruleerrors.ErrPruningPointViolation) { + t.Fatalf("Unexpected error: %+v", err) + } + }) +} diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 2df60003c..12d2e106e 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -29,16 +29,20 @@ var ( // ErrNoParents indicates that the block is missing parents ErrNoParents = newRuleError("ErrNoParents") - // ErrDifficultyTooLow indicates the difficulty for the block is lower - // than the difficulty required. - ErrDifficultyTooLow = newRuleError("ErrDifficultyTooLow") - // ErrUnexpectedDifficulty indicates specified bits do not align with // the expected value either because it doesn't match the calculated - // valued based on difficulty regarted rules or it is out of the valid - // range. + // valued based on difficulty regarted rules. ErrUnexpectedDifficulty = newRuleError("ErrUnexpectedDifficulty") + // ErrTargetTooHigh indicates specified bits do not align with + // the expected value either because it is above the valid + // range. + ErrTargetTooHigh = newRuleError("ErrTargetTooHigh") + + // ErrUnexpectedDifficulty indicates specified bits do not align with + // the expected value either because it is negative. + ErrNegativeTarget = newRuleError("ErrNegativeTarget") + // ErrInvalidPoW indicates that the block proof-of-work is invalid. ErrInvalidPoW = newRuleError("ErrInvalidPoW") diff --git a/domain/consensus/utils/math/math.go b/domain/consensus/utils/math/math.go deleted file mode 100644 index 301231a9e..000000000 --- a/domain/consensus/utils/math/math.go +++ /dev/null @@ -1,153 +0,0 @@ -package math - -import ( - "math/big" -) - -var ( - // bigOne is 1 represented as a big.Int. It is defined here to avoid - // the overhead of creating it multiple times. - bigOne = big.NewInt(1) - - // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid - // the overhead of creating it multiple times. - oneLsh256 = new(big.Int).Lsh(bigOne, 256) - - // log2FloorMasks defines the masks to use when quickly calculating - // floor(log2(x)) in a constant log2(64) = 6 steps, where x is a uint64, using - // shifts. They are derived from (2^(2^x) - 1) * (2^(2^x)), for x in 5..0. - log2FloorMasks = []uint64{0xffffffff00000000, 0xffff0000, 0xff00, 0xf0, 0xc, 0x2} -) - -// FastLog2Floor calculates and returns floor(log2(x)) in a constant 5 steps. -func FastLog2Floor(n uint64) uint8 { - rv := uint8(0) - exponent := uint8(32) - for i := 0; i < 6; i++ { - if n&log2FloorMasks[i] != 0 { - rv += exponent - n >>= exponent - } - exponent >>= 1 - } - return rv -} - -// CompactToBig converts a compact representation of a whole number N to an -// unsigned 32-bit number. The representation is similar to IEEE754 floating -// point numbers. -// -// Like IEEE754 floating point, there are three basic components: the sign, -// the exponent, and the mantissa. They are broken out as follows: -// -// * the most significant 8 bits represent the unsigned base 256 exponent -// * bit 23 (the 24th bit) represents the sign bit -// * the least significant 23 bits represent the mantissa -// -// ------------------------------------------------- -// | Exponent | Sign | Mantissa | -// ------------------------------------------------- -// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] | -// ------------------------------------------------- -// -// The formula to calculate N is: -// N = (-1^sign) * mantissa * 256^(exponent-3) -func CompactToBig(compact uint32) *big.Int { - destination := big.NewInt(0) - CompactToBigWithDestination(compact, destination) - return destination -} - -// CompactToBigWithDestination is a version of CompactToBig that -// takes a destination parameter. This is useful for saving memory, -// as then the destination big.Int can be reused. -// See CompactToBig for further details. -func CompactToBigWithDestination(compact uint32, destination *big.Int) { - // Extract the mantissa, sign bit, and exponent. - mantissa := compact & 0x007fffff - isNegative := compact&0x00800000 != 0 - exponent := uint(compact >> 24) - - // Since the base for the exponent is 256, the exponent can be treated - // as the number of bytes to represent the full 256-bit number. So, - // treat the exponent as the number of bytes and shift the mantissa - // right or left accordingly. This is equivalent to: - // N = mantissa * 256^(exponent-3) - if exponent <= 3 { - mantissa >>= 8 * (3 - exponent) - destination.SetInt64(int64(mantissa)) - } else { - destination.SetInt64(int64(mantissa)) - destination.Lsh(destination, 8*(exponent-3)) - } - - // Make it negative if the sign bit is set. - if isNegative { - destination.Neg(destination) - } -} - -// BigToCompact converts a whole number N to a compact representation using -// an unsigned 32-bit number. The compact representation only provides 23 bits -// of precision, so values larger than (2^23 - 1) only encode the most -// significant digits of the number. See CompactToBig for details. -func BigToCompact(n *big.Int) uint32 { - // No need to do any work if it's zero. - if n.Sign() == 0 { - return 0 - } - - // Since the base for the exponent is 256, the exponent can be treated - // as the number of bytes. So, shift the number right or left - // accordingly. This is equivalent to: - // mantissa = mantissa / 256^(exponent-3) - var mantissa uint32 - exponent := uint(len(n.Bytes())) - if exponent <= 3 { - mantissa = uint32(n.Bits()[0]) - mantissa <<= 8 * (3 - exponent) - } else { - // Use a copy to avoid modifying the caller's original number. - tn := new(big.Int).Set(n) - mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0]) - } - - // When the mantissa already has the sign bit set, the number is too - // large to fit into the available 23-bits, so divide the number by 256 - // and increment the exponent accordingly. - if mantissa&0x00800000 != 0 { - mantissa >>= 8 - exponent++ - } - - // Pack the exponent, sign bit, and mantissa into an unsigned 32-bit - // int and return it. - compact := uint32(exponent<<24) | mantissa - if n.Sign() < 0 { - compact |= 0x00800000 - } - return compact -} - -// CalcWork calculates a work value from difficulty bits. Kaspa increases -// the difficulty for generating a block by decreasing the value which the -// generated hash must be less than. This difficulty target is stored in each -// block header using a compact representation as described in the documentation -// for CompactToBig. Since a lower target difficulty value equates to higher -// actual difficulty, the work value which will be accumulated must be the -// inverse of the difficulty. Also, in order to avoid potential division by -// zero and really small floating point numbers, the result adds 1 to the -// denominator and multiplies the numerator by 2^256. -func CalcWork(bits uint32) *big.Int { - // Return a work value of zero if the passed difficulty bits represent - // a negative number. Note this should not happen in practice with valid - // blocks, but an invalid block could trigger it. - difficultyNum := CompactToBig(bits) - if difficultyNum.Sign() <= 0 { - return big.NewInt(0) - } - - // (1 << 256) / (difficultyNum + 1) - denominator := new(big.Int).Add(difficultyNum, bigOne) - return new(big.Int).Div(oneLsh256, denominator) -} diff --git a/domain/consensus/utils/math/math_test.go b/domain/consensus/utils/math/math_test.go deleted file mode 100644 index 007f3ad40..000000000 --- a/domain/consensus/utils/math/math_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package math - -import ( - "fmt" - "math" - "math/big" - "testing" -) - -func TestFastLog2Floor(t *testing.T) { - tests := []struct { - n uint64 - expectedResult uint8 - }{ - {1, 0}, - {2, 1}, - {3, 1}, - {4, 2}, - {5, 2}, - {16, 4}, - {31, 4}, - {1684234, 20}, - {4294967295, 31}, // math.MaxUint32 (2^32 - 1) - {4294967296, 32}, // 2^32 - {4294967297, 32}, // 2^32 + 1 - {4611686018427387904, 62}, - {9223372036854775808, 63}, // 2^63 - {18446744073709551615, 63}, // math.MaxUint64 (2^64 - 1). - } - - for _, test := range tests { - actualResult := FastLog2Floor(test.n) - - if test.expectedResult != actualResult { - t.Errorf("TestFastLog2Floor: %d: expected result: %d but got: %d", test.n, test.expectedResult, actualResult) - } - } -} - -// TestBigToCompact ensures BigToCompact converts big integers to the expected -// compact representation. -func TestBigToCompact(t *testing.T) { - tests := []struct { - in string - out uint32 - }{ - {"0000000000000000000000000000000000000000000000000000000000000000", 0}, - {"-1", 25231360}, - {"9223372036854775807", 142606335}, - {"922337203685477580712312312123487", 237861256}, - {"128", 0x02008000}, - } - - for x, test := range tests { - n := new(big.Int) - n.SetString(test.in, 10) - r := BigToCompact(n) - if r != test.out { - t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n", - x, r, test.out) - return - } - } -} - -// TestCompactToBig ensures CompactToBig converts numbers using the compact -// representation to the expected big integers. -func TestCompactToBig(t *testing.T) { - tests := []struct { - before uint32 - intHex string - after uint32 - }{ - {math.MaxUint32, "-7fffff000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000", math.MaxUint32}, - {0x00000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x0989680, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x87fffff, "0000000000000000000000000000000000000000000000007fffff0000000000", 0x87fffff}, - {0x1810000, "-000000000000000000000000000000000000000000000000000000000000001", 0x1810000}, - {0xe2d7988, "0000000000000000000000000000000000002d79880000000000000000000000", 0xe2d7988}, - {0x00123456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x01003456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x02000056, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x03000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x04000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x00923456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x01803456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x02800056, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x03800000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x04800000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, - {0x01123456, "0000000000000000000000000000000000000000000000000000000000000012", 0x01120000}, - {0x02008000, "0000000000000000000000000000000000000000000000000000000000000080", 0x02008000}, - {0x01fedcba, "-00000000000000000000000000000000000000000000000000000000000007e", 0x01fe0000}, - {0x02123456, "0000000000000000000000000000000000000000000000000000000000001234", 0x02123400}, - {0x03123456, "0000000000000000000000000000000000000000000000000000000000123456", 0x03123456}, - {0x04123456, "0000000000000000000000000000000000000000000000000000000012345600", 0x04123456}, - {0x04923456, "-000000000000000000000000000000000000000000000000000000012345600", 0x04923456}, - {0x05009234, "0000000000000000000000000000000000000000000000000000000092340000", 0x05009234}, - {0x20123456, "1234560000000000000000000000000000000000000000000000000000000000", 0x20123456}, - {0xff123456, "123456000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 0xff123456}, - } - - for i, test := range tests { - n := CompactToBig(test.before) - convertBack := BigToCompact(n) - got := fmt.Sprintf("%064x", n) - if got != test.intHex { - t.Errorf("TestCompactToBig test #%d failed: got %s want %s, input: 0x%08x", - i, got, test.intHex, test.before) - } - if convertBack != test.after { - t.Errorf("TestCompactToBig test #%d failed: got: 0x%08x want 0x%08x input: 0x%08x", i, convertBack, test.after, test.before) - } - } -} diff --git a/domain/consensus/utils/mining/solve.go b/domain/consensus/utils/mining/solve.go index 2188f8a3c..5b3468371 100644 --- a/domain/consensus/utils/mining/solve.go +++ b/domain/consensus/utils/mining/solve.go @@ -2,17 +2,17 @@ package mining import ( "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/util/difficulty" "math" "math/rand" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - utilsMath "github.com/kaspanet/kaspad/domain/consensus/utils/math" "github.com/pkg/errors" ) // SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) { - targetDifficulty := utilsMath.CompactToBig(block.Header.Bits()) + targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) headerForMining := block.Header.ToMutable() for i := rd.Uint64(); i < math.MaxUint64; i++ { headerForMining.SetNonce(i) diff --git a/domain/miningmanager/mempool/error.go b/domain/miningmanager/mempool/error.go index 0e7b5dc93..001bb4daa 100644 --- a/domain/miningmanager/mempool/error.go +++ b/domain/miningmanager/mempool/error.go @@ -7,8 +7,6 @@ package mempool import ( "fmt" - "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/pkg/errors" ) @@ -115,41 +113,10 @@ func extractRejectCode(err error) (RejectCode, bool) { err = ruleErr.Err } - var dagRuleErr ruleerrors.RuleError - if errors.As(err, &dagRuleErr) { - // Convert the DAG error to a reject code. - var code RejectCode - switch dagRuleErr { - // Rejected due to duplicate. - case ruleerrors.ErrDuplicateBlock: - code = RejectDuplicate - - // Rejected due to obsolete version. - case ruleerrors.ErrBlockVersionTooOld: - code = RejectObsolete - - // Rejected due to being earlier than the last finality point. - case ruleerrors.ErrFinalityPointTimeTooOld: - code = RejectFinality - case ruleerrors.ErrDifficultyTooLow: - code = RejectDifficulty - - // Everything else is due to the block or transaction being invalid. - default: - code = RejectInvalid - } - - return code, true - } - var trErr TxRuleError if errors.As(err, &trErr) { return trErr.RejectCode, true } - if err == nil { - return RejectInvalid, false - } - return RejectInvalid, false } diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index edaadb660..a4a1556b6 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/jessevdk/go-flags" "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/utils/math" "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util/difficulty" "github.com/pkg/errors" "math/big" "os" @@ -165,7 +165,7 @@ func (networkFlags *NetworkFlags) overrideDAGParams() error { return errors.Errorf("couldn't convert %s to big int", *config.PowMax) } - genesisTarget := math.CompactToBig(networkFlags.ActiveNetParams.GenesisBlock.Header.Bits()) + genesisTarget := difficulty.CompactToBig(networkFlags.ActiveNetParams.GenesisBlock.Header.Bits()) if powMax.Cmp(genesisTarget) > 0 { return errors.Errorf("powMax (%s) is smaller than genesis's target (%s)", powMax.Text(16), genesisTarget.Text(16)) diff --git a/util/difficulty/difficulty_test.go b/util/difficulty/difficulty_test.go index b1e5eb5f0..2abd922f0 100644 --- a/util/difficulty/difficulty_test.go +++ b/util/difficulty/difficulty_test.go @@ -1,9 +1,12 @@ package difficulty_test import ( + "fmt" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/util/difficulty" + "math" + "math/big" "testing" ) @@ -22,3 +25,88 @@ func TestGetHashrateString(t *testing.T) { } }) } + +// TestBigToCompact ensures BigToCompact converts big integers to the expected +// compact representation. +func TestBigToCompact(t *testing.T) { + tests := []struct { + in string + out uint32 + }{ + {"0000000000000000000000000000000000000000000000000000000000000000", 0}, + {"-1", 25231360}, + {"9223372036854775807", 142606335}, + {"922337203685477580712312312123487", 237861256}, + {"128", 0x02008000}, + } + + for x, test := range tests { + n := new(big.Int) + n.SetString(test.in, 10) + r := difficulty.BigToCompact(n) + if r != test.out { + t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n", + x, r, test.out) + return + } + } +} + +// TestCompactToBig ensures CompactToBig converts numbers using the compact +// representation to the expected big integers. +func TestCompactToBig(t *testing.T) { + tests := []struct { + before uint32 + intHex string + after uint32 + }{ + {math.MaxUint32, "-7fffff000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000", math.MaxUint32}, + {0x00000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x0989680, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x87fffff, "0000000000000000000000000000000000000000000000007fffff0000000000", 0x87fffff}, + {0x1810000, "-000000000000000000000000000000000000000000000000000000000000001", 0x1810000}, + {0xe2d7988, "0000000000000000000000000000000000002d79880000000000000000000000", 0xe2d7988}, + {0x00123456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x01003456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x02000056, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x03000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x04000000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x00923456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x01803456, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x02800056, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x03800000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x04800000, "0000000000000000000000000000000000000000000000000000000000000000", 0x00000000}, + {0x01123456, "0000000000000000000000000000000000000000000000000000000000000012", 0x01120000}, + {0x02008000, "0000000000000000000000000000000000000000000000000000000000000080", 0x02008000}, + {0x01fedcba, "-00000000000000000000000000000000000000000000000000000000000007e", 0x01fe0000}, + {0x02123456, "0000000000000000000000000000000000000000000000000000000000001234", 0x02123400}, + {0x03123456, "0000000000000000000000000000000000000000000000000000000000123456", 0x03123456}, + {0x04123456, "0000000000000000000000000000000000000000000000000000000012345600", 0x04123456}, + {0x04923456, "-000000000000000000000000000000000000000000000000000000012345600", 0x04923456}, + {0x05009234, "0000000000000000000000000000000000000000000000000000000092340000", 0x05009234}, + {0x20123456, "1234560000000000000000000000000000000000000000000000000000000000", 0x20123456}, + {0xff123456, "123456000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 0xff123456}, + } + + for i, test := range tests { + n := difficulty.CompactToBig(test.before) + convertBack := difficulty.BigToCompact(n) + got := fmt.Sprintf("%064x", n) + if got != test.intHex { + t.Errorf("TestCompactToBig test #%d failed: got %s want %s, input: 0x%08x", + i, got, test.intHex, test.before) + } + if convertBack != test.after { + t.Errorf("TestCompactToBig test #%d failed: got: 0x%08x want 0x%08x input: 0x%08x", i, convertBack, test.after, test.before) + } + } +} From f14527de4c5b1f5ba683db22b5dcf9781b0a01cc Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 17 Jan 2021 13:58:42 +0200 Subject: [PATCH 256/351] Give different limit to the RPC server (#1421) --- .../netadapter/server/grpcserver/grpc_server.go | 10 +++------- .../network/netadapter/server/grpcserver/p2pserver.go | 6 ++++-- .../network/netadapter/server/grpcserver/rpcserver.go | 5 ++++- .../network/rpcclient/grpcclient/grpcclient.go | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go index 269fef7d7..ed4870eb5 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go @@ -17,13 +17,11 @@ type gRPCServer struct { server *grpc.Server } -// MaxMessageSize is the max size allowed for a message -const MaxMessageSize = 10 * 1024 * 1024 // 10MB - // newGRPCServer creates a gRPC server -func newGRPCServer(listeningAddresses []string) *gRPCServer { +func newGRPCServer(listeningAddresses []string, maxMessageSize int) *gRPCServer { + log.Debugf("Created new GRPC server with maxMessageSize %d", maxMessageSize) return &gRPCServer{ - server: grpc.NewServer(grpc.MaxRecvMsgSize(MaxMessageSize), grpc.MaxSendMsgSize(MaxMessageSize)), + server: grpc.NewServer(grpc.MaxRecvMsgSize(maxMessageSize), grpc.MaxSendMsgSize(maxMessageSize)), listeningAddresses: listeningAddresses, } } @@ -40,8 +38,6 @@ func (s *gRPCServer) Start() error { } } - log.Debugf("Server started with MaxMessageSize %d", MaxMessageSize) - return nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/p2pserver.go b/infrastructure/network/netadapter/server/grpcserver/p2pserver.go index 7add4fdfd..9500be622 100644 --- a/infrastructure/network/netadapter/server/grpcserver/p2pserver.go +++ b/infrastructure/network/netadapter/server/grpcserver/p2pserver.go @@ -18,9 +18,11 @@ type p2pServer struct { gRPCServer } +const p2pMaxMessageSize = 10 * 1024 * 1024 // 10MB + // NewP2PServer creates a new P2PServer func NewP2PServer(listeningAddresses []string) (server.P2PServer, error) { - gRPCServer := newGRPCServer(listeningAddresses) + gRPCServer := newGRPCServer(listeningAddresses, p2pMaxMessageSize) p2pServer := &p2pServer{gRPCServer: *gRPCServer} protowire.RegisterP2PServer(gRPCServer.server, p2pServer) return p2pServer, nil @@ -48,7 +50,7 @@ func (p *p2pServer) Connect(address string) (server.Connection, error) { client := protowire.NewP2PClient(gRPCClientConnection) stream, err := client.MessageStream(context.Background(), grpc.UseCompressor(gzip.Name), - grpc.MaxCallRecvMsgSize(MaxMessageSize), grpc.MaxCallSendMsgSize(MaxMessageSize)) + grpc.MaxCallRecvMsgSize(p2pMaxMessageSize), grpc.MaxCallSendMsgSize(p2pMaxMessageSize)) if err != nil { return nil, errors.Wrapf(err, "error getting client stream for %s", address) } diff --git a/infrastructure/network/netadapter/server/grpcserver/rpcserver.go b/infrastructure/network/netadapter/server/grpcserver/rpcserver.go index 6cd1a5bd0..420cc0dae 100644 --- a/infrastructure/network/netadapter/server/grpcserver/rpcserver.go +++ b/infrastructure/network/netadapter/server/grpcserver/rpcserver.go @@ -11,9 +11,12 @@ type rpcServer struct { gRPCServer } +// RPCMaxMessageSize is the max message size for the RPC server to send and receive +const RPCMaxMessageSize = 1024 * 1024 * 1024 // 1 GB + // NewRPCServer creates a new RPCServer func NewRPCServer(listeningAddresses []string) (server.Server, error) { - gRPCServer := newGRPCServer(listeningAddresses) + gRPCServer := newGRPCServer(listeningAddresses, RPCMaxMessageSize) rpcServer := &rpcServer{gRPCServer: *gRPCServer} protowire.RegisterRPCServer(gRPCServer.server, rpcServer) return rpcServer, nil diff --git a/infrastructure/network/rpcclient/grpcclient/grpcclient.go b/infrastructure/network/rpcclient/grpcclient/grpcclient.go index 800c609ac..27652254d 100644 --- a/infrastructure/network/rpcclient/grpcclient/grpcclient.go +++ b/infrastructure/network/rpcclient/grpcclient/grpcclient.go @@ -35,7 +35,7 @@ func Connect(address string) (*GRPCClient, error) { grpcClient := protowire.NewRPCClient(gRPCConnection) stream, err := grpcClient.MessageStream(context.Background(), grpc.UseCompressor(gzip.Name), - grpc.MaxCallRecvMsgSize(grpcserver.MaxMessageSize), grpc.MaxCallSendMsgSize(grpcserver.MaxMessageSize)) + grpc.MaxCallRecvMsgSize(grpcserver.RPCMaxMessageSize), grpc.MaxCallSendMsgSize(grpcserver.RPCMaxMessageSize)) if err != nil { return nil, errors.Wrapf(err, "error getting client stream for %s", address) } From d4f3a252ff0c9105de17ef4d8657ce5881538554 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 17 Jan 2021 15:47:49 +0200 Subject: [PATCH 257/351] Add TestIsFinalizedTransaction (#1422) Co-authored-by: Svarog --- .../block_body_in_context_test.go | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go index 13a77f5e1..f25339966 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go @@ -2,8 +2,10 @@ package blockvalidator_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/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" @@ -128,3 +130,60 @@ func TestCheckParentBlockBodiesExist(t *testing.T) { } }) } + +func TestIsFinalizedTransaction(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + params.BlockCoinbaseMaturity = 0 + factory := consensus.NewFactory() + + tc, teardown, err := factory.NewTestConsensus(params, false, "TestIsFinalizedTransaction") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + + block1, err := tc.GetBlock(block1Hash) + if err != nil { + t.Fatalf("Error getting block1: %+v", err) + } + + checkForLockTimeAndSequence := func(lockTime, sequence uint64, shouldPass bool) { + tx, err := testutils.CreateTransaction(block1.Transactions[0]) + if err != nil { + t.Fatalf("Error creating tx: %+v", err) + } + + tx.LockTime = lockTime + tx.Inputs[0].Sequence = sequence + + _, _, err = tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil, []*externalapi.DomainTransaction{tx}) + if (shouldPass && err != nil) || (!shouldPass && !errors.Is(err, ruleerrors.ErrUnfinalizedTx)) { + t.Fatalf("Unexpected error: %+v", err) + } + } + + // The next block blue score is 2, so we check if we see the expected + // behaviour when the lock time blue score is higher, lower or equal + // to it. + checkForLockTimeAndSequence(3, 0, false) + checkForLockTimeAndSequence(2, 0, false) + checkForLockTimeAndSequence(1, 0, true) + + pastMedianTime, err := tc.PastMedianTimeManager().PastMedianTime(model.VirtualBlockHash) + if err != nil { + t.Fatalf("PastMedianTime: %+v", err) + } + checkForLockTimeAndSequence(uint64(pastMedianTime)+1, 0, false) + checkForLockTimeAndSequence(uint64(pastMedianTime), 0, false) + checkForLockTimeAndSequence(uint64(pastMedianTime)-1, 0, true) + + // We check that if the transaction is marked as finalized it'll pass for any lock time. + checkForLockTimeAndSequence(uint64(pastMedianTime), constants.MaxTxInSequenceNum, true) + checkForLockTimeAndSequence(2, constants.MaxTxInSequenceNum, true) + }) +} From 9a81b1328a4c482f4d51f964406a2d77e1501dc3 Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 17 Jan 2021 16:31:48 +0200 Subject: [PATCH 258/351] Add the Address of node to whom connected in log of send/receiveVersion (#1423) * Add the Address of node to whom connected in log of send/receiveVersion * Don't call functions before LogAndMeasureExecutionTime Co-authored-by: Ori Newman --- app/protocol/flows/handshake/receiveversion.go | 4 +++- app/protocol/flows/handshake/sendversion.go | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/protocol/flows/handshake/receiveversion.go b/app/protocol/flows/handshake/receiveversion.go index f3357dab1..fc2c5a87b 100644 --- a/app/protocol/flows/handshake/receiveversion.go +++ b/app/protocol/flows/handshake/receiveversion.go @@ -42,9 +42,11 @@ func ReceiveVersion(context HandleHandshakeContext, incomingRoute *router.Route, } func (flow *receiveVersionFlow) start() (*appmessage.NetAddress, error) { - onEnd := logger.LogAndMeasureExecutionTime(log, "receiveVersionFlow.start()") + onEnd := logger.LogAndMeasureExecutionTime(log, "receiveVersionFlow.start") defer onEnd() + log.Debugf("Starting receiveVersionFlow with %s", flow.peer.Address()) + message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) if err != nil { return nil, err diff --git a/app/protocol/flows/handshake/sendversion.go b/app/protocol/flows/handshake/sendversion.go index a98c8568d..dcd4ce602 100644 --- a/app/protocol/flows/handshake/sendversion.go +++ b/app/protocol/flows/handshake/sendversion.go @@ -51,6 +51,8 @@ func (flow *sendVersionFlow) start() error { onEnd := logger.LogAndMeasureExecutionTime(log, "sendVersionFlow.start") defer onEnd() + log.Debugf("Starting sendVersionFlow with %s", flow.peer.Address()) + // Version message. localAddress := flow.AddressManager().BestLocalAddress(flow.peer.Connection().NetAddress()) subnetworkID := flow.Config().SubnetworkID From d70740331a909d3420374505fa706681ba412f2f Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 18 Jan 2021 09:10:26 +0200 Subject: [PATCH 259/351] Remove hashesQueueSet (#1424) Co-authored-by: Svarog --- .../flows/blockrelay/hashes_queue_set.go | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 app/protocol/flows/blockrelay/hashes_queue_set.go diff --git a/app/protocol/flows/blockrelay/hashes_queue_set.go b/app/protocol/flows/blockrelay/hashes_queue_set.go deleted file mode 100644 index a09cd2013..000000000 --- a/app/protocol/flows/blockrelay/hashes_queue_set.go +++ /dev/null @@ -1,37 +0,0 @@ -package blockrelay - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -type hashesQueueSet struct { - queue []*externalapi.DomainHash - set map[externalapi.DomainHash]struct{} -} - -func (r *hashesQueueSet) enqueueIfNotExists(hash *externalapi.DomainHash) { - if _, ok := r.set[*hash]; ok { - return - } - r.queue = append(r.queue, hash) - r.set[*hash] = struct{}{} -} - -func (r *hashesQueueSet) dequeue(numItems int) []*externalapi.DomainHash { - var hashes []*externalapi.DomainHash - hashes, r.queue = r.queue[:numItems], r.queue[numItems:] - for _, hash := range hashes { - delete(r.set, *hash) - } - return hashes -} - -func (r *hashesQueueSet) len() int { - return len(r.queue) -} - -func newHashesQueueSet() *hashesQueueSet { - return &hashesQueueSet{ - set: make(map[externalapi.DomainHash]struct{}), - } -} From 189e3b6be9ee5fcc5e64306bb413a04abf2f23c7 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 18 Jan 2021 13:08:16 +0200 Subject: [PATCH 260/351] Fix missing utxo notifications (#1428) * fix missing UTXO notifications (#1426) * Remove redundant semicolon Co-authored-by: aspect --- app/rpc/rpccontext/notificationmanager.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/rpc/rpccontext/notificationmanager.go b/app/rpc/rpccontext/notificationmanager.go index 284e5e4d0..119d31fef 100644 --- a/app/rpc/rpccontext/notificationmanager.go +++ b/app/rpc/rpccontext/notificationmanager.go @@ -229,7 +229,8 @@ func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification( for _, listenerAddress := range nl.propagateUTXOsChangedNotificationAddresses { listenerScriptPublicKeyString := listenerAddress.ScriptPublicKeyString if addedPairs, ok := utxoChanges.Added[listenerScriptPublicKeyString]; ok { - notification.Added = ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs) + notification.Added = append(notification.Added, + ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs)...) } if removedOutpoints, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok { for outpoint := range removedOutpoints { From 0769705b37132b1cce23f7e9215d821d6d215e6e Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Mon, 18 Jan 2021 14:52:32 +0200 Subject: [PATCH 261/351] Update to version 0.8.6 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index b71a37827..e38956ff9 100644 --- a/version/version.go +++ b/version/version.go @@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 appMinor uint = 8 - appPatch uint = 5 + appPatch uint = 6 ) // appBuild is defined as a variable so it can be overridden during the build From 799eb7515c66fe005ff19f13a81851a638aac0ba Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 18 Jan 2021 18:17:13 +0200 Subject: [PATCH 262/351] Test validateAndInsertPruningPoint (#1420) * Add TestValidateAndInsertPruningPoint * Check fake UTXO set and validate that the pruning point changed --- .../validateandinsertpruningpoint_test.go | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go new file mode 100644 index 000000000..0d899c80d --- /dev/null +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go @@ -0,0 +1,219 @@ +package blockprocessor_test + +import ( + "github.com/kaspanet/kaspad/domain/consensus" + "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/testutils" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" + "testing" + "time" +) + +func TestValidateAndInsertPruningPoint(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // This is done to reduce the pruning depth to 6 blocks + finalityDepth := 3 + params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock + params.K = 0 + + factory := consensus.NewFactory() + + tcSyncer, teardownSyncer, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncer") + if err != nil { + t.Fatalf("Error setting up tcSyncer: %+v", err) + } + defer teardownSyncer(false) + + tcSyncee, teardownSyncee, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncee") + if err != nil { + t.Fatalf("Error setting up tcSyncee: %+v", err) + } + defer teardownSyncee(false) + + addBlock := func(parentHashes []*externalapi.DomainHash) *externalapi.DomainHash { + block, _, err := tcSyncer.BuildBlockWithParents(parentHashes, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + _, err = tcSyncer.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + _, err = tcSyncee.ValidateAndInsertBlock(&externalapi.DomainBlock{ + Header: block.Header, + Transactions: nil, + }) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + return consensushashing.BlockHash(block) + } + + tipHash := params.GenesisHash + for i := 0; i < finalityDepth-2; i++ { + tipHash = addBlock([]*externalapi.DomainHash{tipHash}) + } + + // Add block in the anticone of the pruning point to test such situation + pruningPointAnticoneBlock := addBlock([]*externalapi.DomainHash{tipHash}) + tipHash = addBlock([]*externalapi.DomainHash{tipHash}) + nextPruningPoint := addBlock([]*externalapi.DomainHash{tipHash}) + + tipHash = addBlock([]*externalapi.DomainHash{pruningPointAnticoneBlock, nextPruningPoint}) + + // Add blocks until the pruning point changes + for { + tipHash = addBlock([]*externalapi.DomainHash{tipHash}) + + pruningPoint, err := tcSyncer.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + + pruningPoint, err := tcSyncer.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(nextPruningPoint) { + t.Fatalf("Unexpected pruning point %s", pruningPoint) + } + + pruningPointUTXOSet, err := tcSyncer.GetPruningPointUTXOSet(pruningPoint) + if err != nil { + t.Fatalf("GetPruningPointUTXOSet: %+v", err) + } + + tip, err := tcSyncer.GetBlock(tipHash) + if err != nil { + t.Fatalf("GetBlock: %+v", err) + } + + // Check that ValidateAndInsertPruningPoint fails for invalid pruning point + err = tcSyncee.ValidateAndInsertPruningPoint(tip, pruningPointUTXOSet) + if !errors.Is(err, ruleerrors.ErrUnexpectedPruningPoint) { + t.Fatalf("Unexpected error: %+v", err) + } + + pruningPointBlock, err := tcSyncer.GetBlock(pruningPoint) + if err != nil { + t.Fatalf("GetBlock: %+v", err) + } + + invalidPruningPointBlock := pruningPointBlock.Clone() + invalidPruningPointBlock.Transactions[0].Version += 1 + + // Check that ValidateAndInsertPruningPoint fails for invalid block + err = tcSyncee.ValidateAndInsertPruningPoint(invalidPruningPointBlock, pruningPointUTXOSet) + if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) { + t.Fatalf("Unexpected error: %+v", err) + } + + serializedFakeUTXOSet, err := makeSerializedFakeUTXOSet() + if err != nil { + t.Fatalf("makeSerializedFakeUTXOSet: %+v", err) + } + + // Check that ValidateAndInsertPruningPoint fails if the UTXO commitment doesn't fit the provided UTXO set. + err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, serializedFakeUTXOSet) + if !errors.Is(err, ruleerrors.ErrBadPruningPointUTXOSet) { + t.Fatalf("Unexpected error: %+v", err) + } + + // Check that ValidateAndInsertPruningPoint works given the right arguments. + err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, pruningPointUTXOSet) + if err != nil { + t.Fatalf("ValidateAndInsertPruningPoint: %+v", err) + } + + virtualSelectedParent, err := tcSyncer.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("GetVirtualSelectedParent: %+v", err) + } + + missingBlockBodyHashes, err := tcSyncee.GetMissingBlockBodyHashes(virtualSelectedParent) + if err != nil { + t.Fatalf("GetMissingBlockBodyHashes: %+v", err) + } + + for _, missingHash := range missingBlockBodyHashes { + block, err := tcSyncer.GetBlock(missingHash) + if err != nil { + t.Fatalf("GetBlock: %+v", err) + } + + _, err = tcSyncee.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + } + + synceeTips, err := tcSyncee.Tips() + if err != nil { + t.Fatalf("Tips: %+v", err) + } + + syncerTips, err := tcSyncer.Tips() + if err != nil { + t.Fatalf("Tips: %+v", err) + } + + if !externalapi.HashesEqual(synceeTips, syncerTips) { + t.Fatalf("Syncee's tips are %s while syncer's are %s", synceeTips, syncerTips) + } + + synceePruningPoint, err := tcSyncee.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !synceePruningPoint.Equal(pruningPoint) { + t.Fatalf("The syncee pruning point has not changed as exepcted") + } + }) +} + +type fakeUTXOSetIterator struct { + nextCalled bool +} + +func (f *fakeUTXOSetIterator) Next() bool { + if f.nextCalled { + return false + } + f.nextCalled = true + return true +} + +func (f *fakeUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) { + return &externalapi.DomainOutpoint{ + TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), + Index: 0, + }, utxo.NewUTXOEntry(1000, &externalapi.ScriptPublicKey{ + Script: []byte{1, 2, 3}, + Version: 0, + }, false, 2000), nil +} + +func makeSerializedFakeUTXOSet() ([]byte, error) { + serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(&fakeUTXOSetIterator{}) + if err != nil { + return nil, err + } + + return proto.Marshal(serializedUtxo) +} From a4adbabf96af9132ce974449990456714f5ffd21 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 19 Jan 2021 10:37:51 +0200 Subject: [PATCH 263/351] TestBuildBlockErrorCases and remove redundant check of coinbase script length (#1427) * Write structure of TestBlockBuilderErrorCases * Remove double verification of script length in serializeCoinbasePayload * Remove redundant code in TestBuildBlockErrorCases * Rename povTransactionHash -> povBlockHash * Convert coinbasePayloadScriptPublicKeyMaxLength to uint8 * Re-use consensus in TestBuildBlockErrorCases --- ...nterface_processes_transactionvalidator.go | 2 +- .../blockbuilder/block_builder_test.go | 56 +++++++++++++++++++ .../coinbasemanager/coinbasemanager.go | 4 +- .../processes/coinbasemanager/payload.go | 8 +-- domain/dagconfig/params.go | 2 +- infrastructure/config/network.go | 9 +-- 6 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 domain/consensus/processes/blockbuilder/block_builder_test.go diff --git a/domain/consensus/model/interface_processes_transactionvalidator.go b/domain/consensus/model/interface_processes_transactionvalidator.go index d7ea7735e..7e2eddd51 100644 --- a/domain/consensus/model/interface_processes_transactionvalidator.go +++ b/domain/consensus/model/interface_processes_transactionvalidator.go @@ -9,5 +9,5 @@ import ( type TransactionValidator interface { ValidateTransactionInIsolation(transaction *externalapi.DomainTransaction) error ValidateTransactionInContextAndPopulateMassAndFee(tx *externalapi.DomainTransaction, - povTransactionHash *externalapi.DomainHash, selectedParentMedianTime int64) error + povBlockHash *externalapi.DomainHash, selectedParentMedianTime int64) error } diff --git a/domain/consensus/processes/blockbuilder/block_builder_test.go b/domain/consensus/processes/blockbuilder/block_builder_test.go new file mode 100644 index 000000000..9cb48e636 --- /dev/null +++ b/domain/consensus/processes/blockbuilder/block_builder_test.go @@ -0,0 +1,56 @@ +package blockbuilder_test + +import ( + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + + "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" + "github.com/pkg/errors" +) + +func TestBuildBlockErrorCases(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + testConsensus, teardown, err := factory.NewTestConsensus( + params, false, "TestBlockBuilderErrorCases") + if err != nil { + t.Fatalf("Error initializing consensus for: %+v", err) + } + defer teardown(false) + + tests := []struct { + name string + coinbaseData *externalapi.DomainCoinbaseData + transactions []*externalapi.DomainTransaction + expectedErrorType error + }{ + { + "scriptPublicKey too long", + &externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: make([]byte, params.CoinbasePayloadScriptPublicKeyMaxLength+1), + Version: 0, + }, + ExtraData: nil, + }, + nil, + ruleerrors.ErrBadCoinbasePayloadLen, + }, + } + + for _, test := range tests { + _, err = testConsensus.BlockBuilder().BuildBlock(test.coinbaseData, test.transactions) + if err == nil { + t.Errorf("%s: No error from BuildBlock", test.name) + return + } + if test.expectedErrorType != nil && !errors.Is(err, test.expectedErrorType) { + t.Errorf("%s: Expected error '%s', but got '%s'", test.name, test.expectedErrorType, err) + } + } + }) +} diff --git a/domain/consensus/processes/coinbasemanager/coinbasemanager.go b/domain/consensus/processes/coinbasemanager/coinbasemanager.go index ccf4cb71c..198a654cf 100644 --- a/domain/consensus/processes/coinbasemanager/coinbasemanager.go +++ b/domain/consensus/processes/coinbasemanager/coinbasemanager.go @@ -11,7 +11,7 @@ import ( type coinbaseManager struct { subsidyReductionInterval uint64 baseSubsidy uint64 - coinbasePayloadScriptPublicKeyMaxLength uint64 + coinbasePayloadScriptPublicKeyMaxLength uint8 databaseContext model.DBReader ghostdagDataStore model.GHOSTDAGDataStore @@ -129,7 +129,7 @@ func New( subsidyReductionInterval uint64, baseSubsidy uint64, - coinbasePayloadScriptPublicKeyMaxLength uint64, + coinbasePayloadScriptPublicKeyMaxLength uint8, ghostdagDataStore model.GHOSTDAGDataStore, acceptanceDataStore model.AcceptanceDataStore) model.CoinbaseManager { diff --git a/domain/consensus/processes/coinbasemanager/payload.go b/domain/consensus/processes/coinbasemanager/payload.go index ee98d371d..1fad11cfe 100644 --- a/domain/consensus/processes/coinbasemanager/payload.go +++ b/domain/consensus/processes/coinbasemanager/payload.go @@ -2,7 +2,6 @@ package coinbasemanager import ( "encoding/binary" - "math" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -17,16 +16,13 @@ const lengthOfVersionScriptPubKey = uint16Len // serializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data. func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) { scriptLengthOfScriptPubKey := len(coinbaseData.ScriptPublicKey.Script) - if uint64(scriptLengthOfScriptPubKey) > c.coinbasePayloadScriptPublicKeyMaxLength { + if scriptLengthOfScriptPubKey > int(c.coinbasePayloadScriptPublicKeyMaxLength) { return nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+ "longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength) } payload := make([]byte, uint64Len+lengthOfVersionScriptPubKey+lengthOfscriptPubKeyLength+scriptLengthOfScriptPubKey+len(coinbaseData.ExtraData)) binary.LittleEndian.PutUint64(payload[:uint64Len], blueScore) - if len(coinbaseData.ScriptPublicKey.Script) > math.MaxUint8 { - return nil, errors.Errorf("script public key is bigger than %d", math.MaxUint8) - } payload[uint64Len] = uint8(coinbaseData.ScriptPublicKey.Version) payload[uint64Len+lengthOfVersionScriptPubKey] = uint8(len(coinbaseData.ScriptPublicKey.Script)) @@ -49,7 +45,7 @@ func (c *coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalap scriptPubKeyVersion := uint16(coinbaseTx.Payload[uint64Len]) scriptPubKeyScriptLength := coinbaseTx.Payload[uint64Len+lengthOfVersionScriptPubKey] - if uint64(scriptPubKeyScriptLength) > c.coinbasePayloadScriptPublicKeyMaxLength { + if scriptPubKeyScriptLength > c.coinbasePayloadScriptPublicKeyMaxLength { return 0, nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+ "longer than the max allowed length of %d", c.coinbasePayloadScriptPublicKeyMaxLength) } diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 476582f5f..44b66983e 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -175,7 +175,7 @@ type Params struct { MaxMassAcceptedByBlock uint64 // CoinbasePayloadScriptPublicKeyMaxLength is the maximum allowed script public key in the coinbase's payload - CoinbasePayloadScriptPublicKeyMaxLength uint64 + CoinbasePayloadScriptPublicKeyMaxLength uint8 // BaseSubsidy is the starting subsidy amount for mined blocks. BaseSubsidy uint64 diff --git a/infrastructure/config/network.go b/infrastructure/config/network.go index a4a1556b6..8e8cb576b 100644 --- a/infrastructure/config/network.go +++ b/infrastructure/config/network.go @@ -3,14 +3,15 @@ package config import ( "encoding/json" "fmt" + "math/big" + "os" + "time" + "github.com/jessevdk/go-flags" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/util/difficulty" "github.com/pkg/errors" - "math/big" - "os" - "time" ) // NetworkFlags holds the network configuration, that is which network is selected. @@ -33,7 +34,7 @@ type overrideDAGParamsConfig struct { MassPerTxByte *uint64 `json:"massPerTxByte"` MassPerScriptPubKeyByte *uint64 `json:"massPerScriptPubKeyByte"` MassPerSigOp *uint64 `json:"massPerSigOp"` - CoinbasePayloadScriptPublicKeyMaxLength *uint64 `json:"coinbasePayloadScriptPublicKeyMaxLength"` + CoinbasePayloadScriptPublicKeyMaxLength *uint8 `json:"coinbasePayloadScriptPublicKeyMaxLength"` PowMax *string `json:"powMax"` BlockCoinbaseMaturity *uint64 `json:"blockCoinbaseMaturity"` SubsidyReductionInterval *uint64 `json:"subsidyReductionInterval"` From ad9c213a06bbf44abc0cfe33c5d02bf8612a0972 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 19 Jan 2021 14:19:08 +0200 Subject: [PATCH 264/351] Restructure database to prevent double-slashes in keys, causing bugs in cursors (#1432) * Add TestValidateAndInsertPruningPointWithSideBlocks * Optimize infrastracture bucket paths * Update infrastracture tests * Refactor the consensus/database layer * Remove utils/dbkeys * Use consensus/database in consensus instead of infrastructure * Fix a bug in dbBucketToDatabaseBucket and MakeBucket combination Co-authored-by: Elichai Turkel Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- domain/consensus/consensus.go | 3 +- domain/consensus/database/bucket.go | 11 +- domain/consensus/database/errors.go | 14 ++ domain/consensus/database/key.go | 3 + .../acceptancedatastore.go | 4 +- .../blockheaderstore/blockheaderstore.go | 6 +- .../blockrelationstore/blockrelationstore.go | 4 +- .../blockstatusstore/blockstatusstore.go | 4 +- .../datastructures/blockstore/blockstore.go | 6 +- .../consensusstatestore/tips.go | 4 +- .../consensusstatestore/utxo.go | 4 +- .../virtual_diff_parents.go | 4 +- .../finalitystore/finality_store.go | 4 +- .../ghostdagdatastore/ghostdagdatastore.go | 4 +- .../headersselectedchainstore.go | 9 +- .../headertipsstore.go | 4 +- .../multisetstore/multisetstore.go | 4 +- .../pruningstore/pruningstore.go | 8 +- .../reachabilitydatastore.go | 6 +- .../utxodiffstore/utxodiffstore.go | 6 +- .../validateandinsertpruningpoint_test.go | 235 +++++++++++++++--- .../finalitymanager/finality_manager.go | 2 +- .../processes/reachabilitymanager/fetch.go | 2 +- .../processes/syncmanager/blocklocator.go | 2 +- domain/consensus/utils/dbkeys/dbkeys.go | 86 ------- infrastructure/db/database/common_test.go | 2 +- infrastructure/db/database/cursor_test.go | 6 +- infrastructure/db/database/database_test.go | 12 +- infrastructure/db/database/keys.go | 27 +- infrastructure/db/database/keys_test.go | 12 +- infrastructure/db/database/ldb/cursor_test.go | 6 +- .../db/database/ldb/leveldb_test.go | 6 +- .../db/database/ldb/transaction_test.go | 8 +- .../db/database/transaction_test.go | 24 +- 34 files changed, 327 insertions(+), 215 deletions(-) create mode 100644 domain/consensus/database/errors.go delete mode 100644 domain/consensus/utils/dbkeys/dbkeys.go diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 20f811760..fbd50e501 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -3,8 +3,7 @@ package consensus import ( "sync" - "github.com/kaspanet/kaspad/infrastructure/db/database" - + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" diff --git a/domain/consensus/database/bucket.go b/domain/consensus/database/bucket.go index 80a7c66a7..348e1b8d6 100644 --- a/domain/consensus/database/bucket.go +++ b/domain/consensus/database/bucket.go @@ -6,9 +6,18 @@ import ( ) func dbBucketToDatabaseBucket(bucket model.DBBucket) *database.Bucket { + if bucket, ok := bucket.(dbBucket); ok { + return bucket.bucket + } + // This assumes that MakeBucket(src).Path() == src. which is not promised anywhere. return database.MakeBucket(bucket.Path()) } +// MakeBucket creates a new Bucket using the given path of buckets. +func MakeBucket(path []byte) model.DBBucket { + return dbBucket{bucket: database.MakeBucket(path)} +} + type dbBucket struct { bucket *database.Bucket } @@ -26,5 +35,5 @@ func (d dbBucket) Path() []byte { } func newDBBucket(bucket *database.Bucket) model.DBBucket { - return &dbBucket{bucket: bucket} + return dbBucket{bucket: bucket} } diff --git a/domain/consensus/database/errors.go b/domain/consensus/database/errors.go new file mode 100644 index 000000000..025a624a6 --- /dev/null +++ b/domain/consensus/database/errors.go @@ -0,0 +1,14 @@ +package database + +import ( + "github.com/kaspanet/kaspad/infrastructure/db/database" +) + +// ErrNotFound denotes that the requested item was not +// found in the database. +var ErrNotFound = database.ErrNotFound + +// IsNotFoundError checks whether an error is an ErrNotFound. +func IsNotFoundError(err error) bool { + return database.IsNotFoundError(err) +} diff --git a/domain/consensus/database/key.go b/domain/consensus/database/key.go index 2524c3b8e..5f75471f6 100644 --- a/domain/consensus/database/key.go +++ b/domain/consensus/database/key.go @@ -6,6 +6,9 @@ import ( ) func dbKeyToDatabaseKey(key model.DBKey) *database.Key { + if key, ok := key.(dbKey); ok { + return key.key + } return dbBucketToDatabaseBucket(key.Bucket()).Key(key.Suffix()) } diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index 2cbb76acf..8698904bc 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -1,15 +1,15 @@ package acceptancedatastore import ( + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" "google.golang.org/protobuf/proto" ) -var bucket = dbkeys.MakeBucket([]byte("acceptance-data")) +var bucket = database.MakeBucket([]byte("acceptance-data")) // acceptanceDataStore represents a store of AcceptanceData type acceptanceDataStore struct { diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index e0169fecf..2d5a9d25a 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -2,15 +2,15 @@ package blockheaderstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("block-headers")) -var countKey = dbkeys.MakeBucket().Key([]byte("block-headers-count")) +var bucket = database.MakeBucket([]byte("block-headers")) +var countKey = database.MakeBucket(nil).Key([]byte("block-headers-count")) // blockHeaderStore represents a store of blocks type blockHeaderStore struct { diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index d1c6a75c2..ec7a2e566 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -2,14 +2,14 @@ package blockrelationstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("block-relations")) +var bucket = database.MakeBucket([]byte("block-relations")) // blockRelationStore represents a store of BlockRelations type blockRelationStore struct { diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index 40c97433b..e6fc1ed1c 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -2,14 +2,14 @@ package blockstatusstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("block-statuses")) +var bucket = database.MakeBucket([]byte("block-statuses")) // blockStatusStore represents a store of BlockStatuses type blockStatusStore struct { diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index a688d0853..fd332c4a0 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -2,15 +2,15 @@ package blockstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("blocks")) -var countKey = dbkeys.MakeBucket().Key([]byte("blocks-count")) +var bucket = database.MakeBucket([]byte("blocks")) +var countKey = database.MakeBucket(nil).Key([]byte("blocks-count")) // blockStore represents a store of blocks type blockStore struct { diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go index c9cb4400c..f8e748316 100644 --- a/domain/consensus/datastructures/consensusstatestore/tips.go +++ b/domain/consensus/datastructures/consensusstatestore/tips.go @@ -2,13 +2,13 @@ package consensusstatestore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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 tipsKey = dbkeys.MakeBucket().Key([]byte("tips")) +var tipsKey = database.MakeBucket(nil).Key([]byte("tips")) func (css *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { if css.tipsStaging != nil { diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index 8c1dc2854..f25de5fd5 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -1,14 +1,14 @@ package consensusstatestore import ( + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/pkg/errors" ) -var utxoSetBucket = dbkeys.MakeBucket([]byte("virtual-utxo-set")) +var utxoSetBucket = database.MakeBucket([]byte("virtual-utxo-set")) func utxoKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) { serializedOutpoint, err := serializeOutpoint(outpoint) diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go index c834a191f..2baac4b0f 100644 --- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go +++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go @@ -2,13 +2,13 @@ package consensusstatestore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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 virtualDiffParentsKey = dbkeys.MakeBucket().Key([]byte("virtual-diff-parents")) +var virtualDiffParentsKey = database.MakeBucket(nil).Key([]byte("virtual-diff-parents")) func (css *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { if css.virtualDiffParentsStaging != nil { diff --git a/domain/consensus/datastructures/finalitystore/finality_store.go b/domain/consensus/datastructures/finalitystore/finality_store.go index 002f1d309..3d726adab 100644 --- a/domain/consensus/datastructures/finalitystore/finality_store.go +++ b/domain/consensus/datastructures/finalitystore/finality_store.go @@ -1,13 +1,13 @@ package finalitystore import ( + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("finality-points")) +var bucket = database.MakeBucket([]byte("finality-points")) type finalityStore struct { staging map[externalapi.DomainHash]*externalapi.DomainHash diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index 8c61ba06d..41f0ba58b 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -2,14 +2,14 @@ package ghostdagdatastore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("block-ghostdag-data")) +var bucket = database.MakeBucket([]byte("block-ghostdag-data")) // ghostdagDataStore represents a store of BlockGHOSTDAGData type ghostdagDataStore struct { diff --git a/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go b/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go index 34406ec91..f6b2334a2 100644 --- a/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go +++ b/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go @@ -2,19 +2,18 @@ package headersselectedchainstore import ( "encoding/binary" + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/database/binaryserialization" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucacheuint64tohash" - "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" ) -var bucketChainBlockHashByIndex = dbkeys.MakeBucket([]byte("chain-block-hash-by-index")) -var bucketChainBlockIndexByHash = dbkeys.MakeBucket([]byte("chain-block-index-by-hash")) -var highestChainBlockIndexKey = dbkeys.MakeBucket().Key([]byte("highest-chain-block-index")) +var bucketChainBlockHashByIndex = database.MakeBucket([]byte("chain-block-hash-by-index")) +var bucketChainBlockIndexByHash = database.MakeBucket([]byte("chain-block-index-by-hash")) +var highestChainBlockIndexKey = database.MakeBucket(nil).Key([]byte("highest-chain-block-index")) type headersSelectedChainStore struct { stagingAddedByHash map[externalapi.DomainHash]uint64 diff --git a/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go b/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go index f0df6910b..dd4b4b0ae 100644 --- a/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go +++ b/domain/consensus/datastructures/headersselectedtipstore/headertipsstore.go @@ -2,13 +2,13 @@ package headersselectedtipstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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")) +var headerSelectedTipKey = database.MakeBucket(nil).Key([]byte("headers-selected-tip")) type headerSelectedTipStore struct { staging *externalapi.DomainHash diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go index 20beca609..b6a565d2d 100644 --- a/domain/consensus/datastructures/multisetstore/multisetstore.go +++ b/domain/consensus/datastructures/multisetstore/multisetstore.go @@ -2,14 +2,14 @@ package multisetstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var bucket = dbkeys.MakeBucket([]byte("multisets")) +var bucket = database.MakeBucket([]byte("multisets")) // multisetStore represents a store of Multisets type multisetStore struct { diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index 24a25258a..31eefdc9a 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -2,15 +2,15 @@ package pruningstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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 pruningBlockHashKey = dbkeys.MakeBucket().Key([]byte("pruning-block-hash")) -var candidatePruningPointHashKey = dbkeys.MakeBucket().Key([]byte("candidate-pruning-point-hash")) -var pruningSerializedUTXOSetKey = dbkeys.MakeBucket().Key([]byte("pruning-utxo-set")) +var pruningBlockHashKey = database.MakeBucket(nil).Key([]byte("pruning-block-hash")) +var candidatePruningPointHashKey = database.MakeBucket(nil).Key([]byte("candidate-pruning-point-hash")) +var pruningSerializedUTXOSetKey = database.MakeBucket(nil).Key([]byte("pruning-utxo-set")) // pruningStore represents a store for the current pruning state type pruningStore struct { diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index 187510453..7d72e0e96 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -2,15 +2,15 @@ package reachabilitydatastore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" ) -var reachabilityDataBucket = dbkeys.MakeBucket([]byte("reachability-data")) -var reachabilityReindexRootKey = dbkeys.MakeBucket().Key([]byte("reachability-reindex-root")) +var reachabilityDataBucket = database.MakeBucket([]byte("reachability-data")) +var reachabilityReindexRootKey = database.MakeBucket(nil).Key([]byte("reachability-reindex-root")) // reachabilityDataStore represents a store of ReachabilityData type reachabilityDataStore struct { diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index 9fa0adc18..caab31e3e 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -2,16 +2,16 @@ package utxodiffstore import ( "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" "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" "github.com/kaspanet/kaspad/domain/consensus/utils/lrucache" "github.com/pkg/errors" ) -var utxoDiffBucket = dbkeys.MakeBucket([]byte("utxo-diffs")) -var utxoDiffChildBucket = dbkeys.MakeBucket([]byte("utxo-diff-children")) +var utxoDiffBucket = database.MakeBucket([]byte("utxo-diffs")) +var utxoDiffChildBucket = database.MakeBucket([]byte("utxo-diff-children")) // utxoDiffStore represents a store of UTXODiffs type utxoDiffStore struct { diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go index 0d899c80d..059112dde 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go @@ -1,8 +1,12 @@ package blockprocessor_test import ( + "testing" + "time" + "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" @@ -11,10 +15,30 @@ import ( "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" "google.golang.org/protobuf/proto" - "testing" - "time" ) +func addBlock(tcSyncer, tcSyncee testapi.TestConsensus, parentHashes []*externalapi.DomainHash, t *testing.T) *externalapi.DomainHash { + block, _, err := tcSyncer.BuildBlockWithParents(parentHashes, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + _, err = tcSyncer.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + _, err = tcSyncee.ValidateAndInsertBlock(&externalapi.DomainBlock{ + Header: block.Header, + Transactions: nil, + }) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + return consensushashing.BlockHash(block) +} + func TestValidateAndInsertPruningPoint(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { // This is done to reduce the pruning depth to 6 blocks @@ -36,43 +60,21 @@ func TestValidateAndInsertPruningPoint(t *testing.T) { } defer teardownSyncee(false) - addBlock := func(parentHashes []*externalapi.DomainHash) *externalapi.DomainHash { - block, _, err := tcSyncer.BuildBlockWithParents(parentHashes, nil, nil) - if err != nil { - t.Fatalf("BuildBlockWithParents: %+v", err) - } - - _, err = tcSyncer.ValidateAndInsertBlock(block) - if err != nil { - t.Fatalf("ValidateAndInsertBlock: %+v", err) - } - - _, err = tcSyncee.ValidateAndInsertBlock(&externalapi.DomainBlock{ - Header: block.Header, - Transactions: nil, - }) - if err != nil { - t.Fatalf("ValidateAndInsertBlock: %+v", err) - } - - return consensushashing.BlockHash(block) - } - tipHash := params.GenesisHash for i := 0; i < finalityDepth-2; i++ { - tipHash = addBlock([]*externalapi.DomainHash{tipHash}) + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) } // Add block in the anticone of the pruning point to test such situation - pruningPointAnticoneBlock := addBlock([]*externalapi.DomainHash{tipHash}) - tipHash = addBlock([]*externalapi.DomainHash{tipHash}) - nextPruningPoint := addBlock([]*externalapi.DomainHash{tipHash}) + pruningPointAnticoneBlock := addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) + nextPruningPoint := addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) - tipHash = addBlock([]*externalapi.DomainHash{pruningPointAnticoneBlock, nextPruningPoint}) + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{pruningPointAnticoneBlock, nextPruningPoint}, t) // Add blocks until the pruning point changes for { - tipHash = addBlock([]*externalapi.DomainHash{tipHash}) + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) pruningPoint, err := tcSyncer.PruningPoint() if err != nil { @@ -187,6 +189,179 @@ func TestValidateAndInsertPruningPoint(t *testing.T) { }) } +// TestValidateAndInsertPruningPointWithSideBlocks makes sure that when a node applies a UTXO-Set downloaded during +// IBD, while it already has a non-empty UTXO-Set originating from blocks mined on top of genesis - the resulting +// UTXO set is correct +func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // This is done to reduce the pruning depth to 6 blocks + finalityDepth := 3 + params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock + params.K = 0 + + factory := consensus.NewFactory() + + tcSyncer, teardownSyncer, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncer") + if err != nil { + t.Fatalf("Error setting up tcSyncer: %+v", err) + } + defer teardownSyncer(false) + + tcSyncee, teardownSyncee, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncee") + if err != nil { + t.Fatalf("Error setting up tcSyncee: %+v", err) + } + defer teardownSyncee(false) + + // Mine 2 block in the syncee on top of genesis + side, _, err := tcSyncee.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, &externalapi.DomainCoinbaseData{ScriptPublicKey: &externalapi.ScriptPublicKey{}, ExtraData: []byte{1, 2}}, nil) + if err != nil { + t.Fatal(err) + } + _, _, err = tcSyncee.AddBlock([]*externalapi.DomainHash{side}, nil, nil) + if err != nil { + t.Fatal(err) + } + + tipHash := params.GenesisHash + for i := 0; i < finalityDepth-2; i++ { + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) + } + + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) + nextPruningPoint := addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) + + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{nextPruningPoint}, t) + + // Add blocks until the pruning point changes + for { + tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t) + + pruningPoint, err := tcSyncer.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + + pruningPoint, err := tcSyncer.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(nextPruningPoint) { + t.Fatalf("Unexpected pruning point %s", pruningPoint) + } + + pruningPointUTXOSet, err := tcSyncer.GetPruningPointUTXOSet(pruningPoint) + if err != nil { + t.Fatalf("GetPruningPointUTXOSet: %+v", err) + } + + // Check that ValidateAndInsertPruningPoint works. + pruningPointBlock, err := tcSyncer.GetBlock(pruningPoint) + if err != nil { + t.Fatalf("GetBlock: %+v", err) + } + err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, pruningPointUTXOSet) + if err != nil { + t.Fatalf("ValidateAndInsertPruningPoint: %+v", err) + } + + // Insert the rest of the blocks atop pruning point + virtualSelectedParent, err := tcSyncer.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("GetVirtualSelectedParent: %+v", err) + } + + missingBlockBodyHashes, err := tcSyncee.GetMissingBlockBodyHashes(virtualSelectedParent) + if err != nil { + t.Fatalf("GetMissingBlockBodyHashes: %+v", err) + } + + for _, missingHash := range missingBlockBodyHashes { + block, err := tcSyncer.GetBlock(missingHash) + if err != nil { + t.Fatalf("GetBlock: %+v", err) + } + + _, err = tcSyncee.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + } + + // Verify that syncee and syncer tips are equal + synceeTips, err := tcSyncee.Tips() + if err != nil { + t.Fatalf("Tips: %+v", err) + } + + syncerTips, err := tcSyncer.Tips() + if err != nil { + t.Fatalf("Tips: %+v", err) + } + + if !externalapi.HashesEqual(synceeTips, syncerTips) { + t.Fatalf("Syncee's tips are %s while syncer's are %s", synceeTips, syncerTips) + } + + // Verify that syncee and syncer pruning points are equal + synceePruningPoint, err := tcSyncee.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !synceePruningPoint.Equal(pruningPoint) { + t.Fatalf("The syncee pruning point has not changed as exepcted") + } + + pruningPointOld := pruningPoint + + // Add blocks until the pruning point moves, and verify it moved to the same point on both syncer and syncee + for { + block, _, err := tcSyncer.BuildBlockWithParents([]*externalapi.DomainHash{tipHash}, nil, nil) + if err != nil { + t.Fatalf("BuildBlockWithParents: %+v", err) + } + + _, err = tcSyncer.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + _, err = tcSyncee.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("ValidateAndInsertBlock: %+v", err) + } + + tipHash = consensushashing.BlockHash(block) + + pruningPoint, err = tcSyncer.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !pruningPoint.Equal(pruningPointOld) { + break + } + } + + synceePruningPoint, err = tcSyncee.PruningPoint() + if err != nil { + t.Fatalf("PruningPoint: %+v", err) + } + + if !synceePruningPoint.Equal(pruningPoint) { + t.Fatalf("The syncee pruning point(%s) is not equal to syncer pruning point (%s) after it moved. "+ + "pruning point before move: %s", synceePruningPoint, pruningPoint, pruningPointOld) + } + }) +} + type fakeUTXOSetIterator struct { nextCalled bool } diff --git a/domain/consensus/processes/finalitymanager/finality_manager.go b/domain/consensus/processes/finalitymanager/finality_manager.go index c383dcf20..7ba1dfe79 100644 --- a/domain/consensus/processes/finalitymanager/finality_manager.go +++ b/domain/consensus/processes/finalitymanager/finality_manager.go @@ -3,9 +3,9 @@ package finalitymanager import ( "errors" + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/infrastructure/db/database" ) type finalityManager struct { diff --git a/domain/consensus/processes/reachabilitymanager/fetch.go b/domain/consensus/processes/reachabilitymanager/fetch.go index 561105eed..77ec8220f 100644 --- a/domain/consensus/processes/reachabilitymanager/fetch.go +++ b/domain/consensus/processes/reachabilitymanager/fetch.go @@ -1,10 +1,10 @@ package reachabilitymanager import ( + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/reachabilitydata" - "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" ) diff --git a/domain/consensus/processes/syncmanager/blocklocator.go b/domain/consensus/processes/syncmanager/blocklocator.go index aaa205fad..dac5abe64 100644 --- a/domain/consensus/processes/syncmanager/blocklocator.go +++ b/domain/consensus/processes/syncmanager/blocklocator.go @@ -1,9 +1,9 @@ package syncmanager import ( + "github.com/kaspanet/kaspad/domain/consensus/database" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" ) diff --git a/domain/consensus/utils/dbkeys/dbkeys.go b/domain/consensus/utils/dbkeys/dbkeys.go deleted file mode 100644 index b78a602ba..000000000 --- a/domain/consensus/utils/dbkeys/dbkeys.go +++ /dev/null @@ -1,86 +0,0 @@ -package dbkeys - -import ( - "bytes" - "encoding/hex" - "github.com/kaspanet/kaspad/domain/consensus/model" -) - -var bucketSeparator = []byte("/") - -// Key is a helper type meant to combine prefix -// and suffix into a single database key. -type Key struct { - bucket *Bucket - suffix []byte -} - -// Bytes returns the full key bytes that are consisted -// from the bucket path concatenated to the suffix. -func (k *Key) Bytes() []byte { - bucketPath := k.bucket.Path() - keyBytes := make([]byte, len(bucketPath)+len(k.suffix)) - copy(keyBytes, bucketPath) - copy(keyBytes[len(bucketPath):], k.suffix) - return keyBytes -} - -func (k *Key) String() string { - return hex.EncodeToString(k.Bytes()) -} - -// Bucket returns the key bucket. -func (k *Key) Bucket() model.DBBucket { - return k.bucket -} - -// Suffix returns the key suffix. -func (k *Key) Suffix() []byte { - return k.suffix -} - -// newKey returns a new key composed -// of the given bucket and suffix -func newKey(bucket *Bucket, suffix []byte) model.DBKey { - return &Key{bucket: bucket, suffix: suffix} -} - -// Bucket is a helper type meant to combine buckets -// and sub-buckets that can be used to create database -// keys and prefix-based cursors. -type Bucket struct { - path [][]byte -} - -// MakeBucket creates a new Bucket using the given path -// of buckets. -func MakeBucket(path ...[]byte) model.DBBucket { - return &Bucket{path: path} -} - -// Bucket returns the sub-bucket of the current bucket -// defined by bucketBytes. -func (b *Bucket) Bucket(bucketBytes []byte) model.DBBucket { - newPath := make([][]byte, len(b.path)+1) - copy(newPath, b.path) - copy(newPath[len(b.path):], [][]byte{bucketBytes}) - - return MakeBucket(newPath...) -} - -// Key returns a key in the current bucket with the -// given suffix. -func (b *Bucket) Key(suffix []byte) model.DBKey { - return newKey(b, suffix) -} - -// Path returns the full path of the current bucket. -func (b *Bucket) Path() []byte { - bucketPath := bytes.Join(b.path, bucketSeparator) - - bucketPathWithFinalSeparator := make([]byte, len(bucketPath)+len(bucketSeparator)) - copy(bucketPathWithFinalSeparator, bucketPath) - copy(bucketPathWithFinalSeparator[len(bucketPath):], bucketSeparator) - - return bucketPathWithFinalSeparator -} diff --git a/infrastructure/db/database/common_test.go b/infrastructure/db/database/common_test.go index 06ce3b159..2b16f9b39 100644 --- a/infrastructure/db/database/common_test.go +++ b/infrastructure/db/database/common_test.go @@ -67,7 +67,7 @@ func populateDatabaseForTest(t *testing.T, db database.Database, testName string // Prepare a list of key/value pairs entries := make([]keyValuePair, 10) for i := 0; i < 10; i++ { - key := database.MakeBucket().Key([]byte(fmt.Sprintf("key%d", i))) + key := database.MakeBucket(nil).Key([]byte(fmt.Sprintf("key%d", i))) value := []byte("value") entries[i] = keyValuePair{key: key, value: value} } diff --git a/infrastructure/db/database/cursor_test.go b/infrastructure/db/database/cursor_test.go index c0082d94b..65e908f76 100644 --- a/infrastructure/db/database/cursor_test.go +++ b/infrastructure/db/database/cursor_test.go @@ -15,7 +15,7 @@ import ( ) func prepareCursorForTest(t *testing.T, db database.Database, testName string) database.Cursor { - cursor, err := db.Cursor(database.MakeBucket()) + cursor, err := db.Cursor(database.MakeBucket(nil)) if err != nil { t.Fatalf("%s: Cursor unexpectedly "+ "failed: %s", testName, err) @@ -241,7 +241,7 @@ func testCursorSeek(t *testing.T, db database.Database, testName string) { // Seek to a value that doesn't exist and make sure that // the returned error is ErrNotFound - err = cursor.Seek(database.MakeBucket().Key([]byte("doesn't exist"))) + err = cursor.Seek(database.MakeBucket(nil).Key([]byte("doesn't exist"))) if err == nil { t.Fatalf("%s: Seek unexpectedly "+ "succeeded", testName) @@ -274,7 +274,7 @@ func testCursorCloseErrors(t *testing.T, db database.Database, testName string) { name: "Seek", function: func() error { - return cursor.Seek(database.MakeBucket().Key([]byte{})) + return cursor.Seek(database.MakeBucket(nil).Key([]byte{})) }, }, { diff --git a/infrastructure/db/database/database_test.go b/infrastructure/db/database/database_test.go index 55c4b88e1..2f7f3d990 100644 --- a/infrastructure/db/database/database_test.go +++ b/infrastructure/db/database/database_test.go @@ -18,7 +18,7 @@ func TestDatabasePut(t *testing.T) { func testDatabasePut(t *testing.T, db database.Database, testName string) { // Put value1 into the database - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value1 := []byte("value1") err := db.Put(key, value1) if err != nil { @@ -65,7 +65,7 @@ func TestDatabaseGet(t *testing.T) { func testDatabaseGet(t *testing.T, db database.Database, testName string) { // Put a value into the database - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err := db.Put(key, value) if err != nil { @@ -87,7 +87,7 @@ func testDatabaseGet(t *testing.T, db database.Database, testName string) { // Try getting a non-existent value and make sure // the returned error is ErrNotFound - _, err = db.Get(database.MakeBucket().Key([]byte("doesn't exist"))) + _, err = db.Get(database.MakeBucket(nil).Key([]byte("doesn't exist"))) if err == nil { t.Fatalf("%s: Get "+ "unexpectedly succeeded", testName) @@ -104,7 +104,7 @@ func TestDatabaseHas(t *testing.T) { func testDatabaseHas(t *testing.T, db database.Database, testName string) { // Put a value into the database - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err := db.Put(key, value) if err != nil { @@ -124,7 +124,7 @@ func testDatabaseHas(t *testing.T, db database.Database, testName string) { } // Make sure that Has returns false for a non-existent value - exists, err = db.Has(database.MakeBucket().Key([]byte("doesn't exist"))) + exists, err = db.Has(database.MakeBucket(nil).Key([]byte("doesn't exist"))) if err != nil { t.Fatalf("%s: Has "+ "unexpectedly failed: %s", testName, err) @@ -141,7 +141,7 @@ func TestDatabaseDelete(t *testing.T) { func testDatabaseDelete(t *testing.T, db database.Database, testName string) { // Put a value into the database - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err := db.Put(key, value) if err != nil { diff --git a/infrastructure/db/database/keys.go b/infrastructure/db/database/keys.go index 6b9aabdb8..e7450a275 100644 --- a/infrastructure/db/database/keys.go +++ b/infrastructure/db/database/keys.go @@ -1,11 +1,10 @@ package database import ( - "bytes" "encoding/hex" ) -var bucketSeparator = []byte("/") +var bucketSeparator = byte('/') // Key is a helper type meant to combine prefix // and suffix into a single database key. @@ -48,23 +47,25 @@ func newKey(bucket *Bucket, suffix []byte) *Key { // and sub-buckets that can be used to create database // keys and prefix-based cursors. type Bucket struct { - path [][]byte + path []byte } // MakeBucket creates a new Bucket using the given path // of buckets. -func MakeBucket(path ...[]byte) *Bucket { +func MakeBucket(path []byte) *Bucket { + if len(path) > 0 && path[len(path)-1] != bucketSeparator { + path = append(path, bucketSeparator) + } return &Bucket{path: path} } // Bucket returns the sub-bucket of the current bucket // defined by bucketBytes. func (b *Bucket) Bucket(bucketBytes []byte) *Bucket { - newPath := make([][]byte, len(b.path)+1) - copy(newPath, b.path) - copy(newPath[len(b.path):], [][]byte{bucketBytes}) - - return MakeBucket(newPath...) + newPath := make([]byte, 0, len(b.path)+len(bucketBytes)+1) // +1 for the separator in MakeBucket + newPath = append(newPath, b.path...) + newPath = append(newPath, bucketBytes...) + return MakeBucket(newPath) } // Key returns a key in the current bucket with the @@ -75,11 +76,5 @@ func (b *Bucket) Key(suffix []byte) *Key { // Path returns the full path of the current bucket. func (b *Bucket) Path() []byte { - bucketPath := bytes.Join(b.path, bucketSeparator) - - bucketPathWithFinalSeparator := make([]byte, len(bucketPath)+len(bucketSeparator)) - copy(bucketPathWithFinalSeparator, bucketPath) - copy(bucketPathWithFinalSeparator[len(bucketPath):], bucketSeparator) - - return bucketPathWithFinalSeparator + return b.path } diff --git a/infrastructure/db/database/keys_test.go b/infrastructure/db/database/keys_test.go index 4c0e8b360..87f9566bc 100644 --- a/infrastructure/db/database/keys_test.go +++ b/infrastructure/db/database/keys_test.go @@ -6,6 +6,10 @@ import ( "testing" ) +func makeBucketJoin(path ...[]byte) *Bucket { + return MakeBucket(bytes.Join(path, []byte{bucketSeparator})) +} + func TestBucketPath(t *testing.T) { tests := []struct { bucketByteSlices [][]byte @@ -23,14 +27,14 @@ func TestBucketPath(t *testing.T) { for _, test := range tests { // Build a result using the MakeBucket function alone - resultKey := MakeBucket(test.bucketByteSlices...).Path() + resultKey := makeBucketJoin(test.bucketByteSlices...).Path() if !reflect.DeepEqual(resultKey, test.expectedPath) { t.Errorf("TestBucketPath: got wrong path using MakeBucket. "+ "Want: %s, got: %s", string(test.expectedPath), string(resultKey)) } // Build a result using sub-Bucket calls - bucket := MakeBucket() + bucket := MakeBucket(nil) for _, bucketBytes := range test.bucketByteSlices { bucket = bucket.Bucket(bucketBytes) } @@ -63,14 +67,14 @@ func TestBucketKey(t *testing.T) { key: []byte("test"), expectedKeyBytes: []byte("hello/world/test"), expectedKey: &Key{ - bucket: MakeBucket([]byte("hello"), []byte("world")), + bucket: makeBucketJoin([]byte("hello"), []byte("world")), suffix: []byte("test"), }, }, } for _, test := range tests { - resultKey := MakeBucket(test.bucketByteSlices...).Key(test.key) + resultKey := makeBucketJoin(test.bucketByteSlices...).Key(test.key) if !reflect.DeepEqual(resultKey, test.expectedKey) { t.Errorf("TestBucketKey: got wrong key. Want: %s, got: %s", test.expectedKeyBytes, resultKey) diff --git a/infrastructure/db/database/ldb/cursor_test.go b/infrastructure/db/database/ldb/cursor_test.go index f9232daf9..ae410b067 100644 --- a/infrastructure/db/database/ldb/cursor_test.go +++ b/infrastructure/db/database/ldb/cursor_test.go @@ -95,7 +95,7 @@ func TestCursorSanity(t *testing.T) { validateCurrentCursorKeyAndValue(t, "TestCursorSanity", cursor, expectedKey, expectedValue) // Seek to a non-existant key - err = cursor.Seek(database.MakeBucket().Key([]byte("doesn't exist"))) + err = cursor.Seek(database.MakeBucket(nil).Key([]byte("doesn't exist"))) if err == nil { t.Fatalf("TestCursorSanity: Seek " + "unexpectedly succeeded") @@ -155,7 +155,7 @@ func TestCursorCloseErrors(t *testing.T) { { name: "Seek", function: func(cursor database.Cursor) error { - return cursor.Seek(database.MakeBucket().Key([]byte{})) + return cursor.Seek(database.MakeBucket(nil).Key([]byte{})) }, }, { @@ -186,7 +186,7 @@ func TestCursorCloseErrors(t *testing.T) { defer teardownFunc() // Open a new cursor - cursor, err := ldb.Cursor(database.MakeBucket()) + cursor, err := ldb.Cursor(database.MakeBucket(nil)) if err != nil { t.Fatalf("TestCursorCloseErrors: ldb.Cursor "+ "unexpectedly failed: %s", err) diff --git a/infrastructure/db/database/ldb/leveldb_test.go b/infrastructure/db/database/ldb/leveldb_test.go index cc91639ae..51f3aab32 100644 --- a/infrastructure/db/database/ldb/leveldb_test.go +++ b/infrastructure/db/database/ldb/leveldb_test.go @@ -35,7 +35,7 @@ func TestLevelDBSanity(t *testing.T) { defer teardownFunc() // Put something into the db - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) putData := []byte("Hello world!") err := ldb.Put(key, putData) if err != nil { @@ -71,7 +71,7 @@ func TestLevelDBTransactionSanity(t *testing.T) { } // Put something into the transaction - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) putData := []byte("Hello world!") err = tx.Put(key, putData) if err != nil { @@ -115,7 +115,7 @@ func TestLevelDBTransactionSanity(t *testing.T) { // Case 2. Write directly to the DB and then read from a tx // Put something into the db - key = database.MakeBucket().Key([]byte("key2")) + key = database.MakeBucket(nil).Key([]byte("key2")) putData = []byte("Goodbye world!") err = ldb.Put(key, putData) if err != nil { diff --git a/infrastructure/db/database/ldb/transaction_test.go b/infrastructure/db/database/ldb/transaction_test.go index 3b81b0ae7..bf2c9a7a1 100644 --- a/infrastructure/db/database/ldb/transaction_test.go +++ b/infrastructure/db/database/ldb/transaction_test.go @@ -20,14 +20,14 @@ func TestTransactionCloseErrors(t *testing.T) { { name: "Put", function: func(dbTx *LevelDBTransaction) error { - return dbTx.Put(database.MakeBucket().Key([]byte("key")), []byte("value")) + return dbTx.Put(database.MakeBucket(nil).Key([]byte("key")), []byte("value")) }, shouldReturnError: true, }, { name: "Get", function: func(dbTx *LevelDBTransaction) error { - _, err := dbTx.Get(database.MakeBucket().Key([]byte("key"))) + _, err := dbTx.Get(database.MakeBucket(nil).Key([]byte("key"))) return err }, shouldReturnError: true, @@ -35,7 +35,7 @@ func TestTransactionCloseErrors(t *testing.T) { { name: "Has", function: func(dbTx *LevelDBTransaction) error { - _, err := dbTx.Has(database.MakeBucket().Key([]byte("key"))) + _, err := dbTx.Has(database.MakeBucket(nil).Key([]byte("key"))) return err }, shouldReturnError: true, @@ -43,7 +43,7 @@ func TestTransactionCloseErrors(t *testing.T) { { name: "Delete", function: func(dbTx *LevelDBTransaction) error { - return dbTx.Delete(database.MakeBucket().Key([]byte("key"))) + return dbTx.Delete(database.MakeBucket(nil).Key([]byte("key"))) }, shouldReturnError: true, }, diff --git a/infrastructure/db/database/transaction_test.go b/infrastructure/db/database/transaction_test.go index eda5b137e..e8a44170c 100644 --- a/infrastructure/db/database/transaction_test.go +++ b/infrastructure/db/database/transaction_test.go @@ -33,7 +33,7 @@ func testTransactionPut(t *testing.T, db database.Database, testName string) { }() // Put value1 into the transaction - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value1 := []byte("value1") err = dbTx.Put(key, value1) if err != nil { @@ -75,7 +75,7 @@ func TestTransactionGet(t *testing.T) { func testTransactionGet(t *testing.T, db database.Database, testName string) { // Put a value into the database - key1 := database.MakeBucket().Key([]byte("key1")) + key1 := database.MakeBucket(nil).Key([]byte("key1")) value1 := []byte("value1") err := db.Put(key1, value1) if err != nil { @@ -111,7 +111,7 @@ func testTransactionGet(t *testing.T, db database.Database, testName string) { // Try getting a non-existent value and make sure // the returned error is ErrNotFound - _, err = dbTx.Get(database.MakeBucket().Key([]byte("doesn't exist"))) + _, err = dbTx.Get(database.MakeBucket(nil).Key([]byte("doesn't exist"))) if err == nil { t.Fatalf("%s: Get "+ "unexpectedly succeeded", testName) @@ -122,7 +122,7 @@ func testTransactionGet(t *testing.T, db database.Database, testName string) { } // Put a new value into the database outside of the transaction - key2 := database.MakeBucket().Key([]byte("key2")) + key2 := database.MakeBucket(nil).Key([]byte("key2")) value2 := []byte("value2") err = db.Put(key2, value2) if err != nil { @@ -141,7 +141,7 @@ func testTransactionGet(t *testing.T, db database.Database, testName string) { } // Put a new value into the transaction - key3 := database.MakeBucket().Key([]byte("key3")) + key3 := database.MakeBucket(nil).Key([]byte("key3")) value3 := []byte("value3") err = dbTx.Put(key3, value3) if err != nil { @@ -167,7 +167,7 @@ func TestTransactionHas(t *testing.T) { func testTransactionHas(t *testing.T, db database.Database, testName string) { // Put a value into the database - key1 := database.MakeBucket().Key([]byte("key1")) + key1 := database.MakeBucket(nil).Key([]byte("key1")) value1 := []byte("value1") err := db.Put(key1, value1) if err != nil { @@ -201,7 +201,7 @@ func testTransactionHas(t *testing.T, db database.Database, testName string) { } // Make sure that Has returns false for a non-existent value - exists, err = dbTx.Has(database.MakeBucket().Key([]byte("doesn't exist"))) + exists, err = dbTx.Has(database.MakeBucket(nil).Key([]byte("doesn't exist"))) if err != nil { t.Fatalf("%s: Has "+ "unexpectedly failed: %s", testName, err) @@ -212,7 +212,7 @@ func testTransactionHas(t *testing.T, db database.Database, testName string) { } // Put a new value into the database outside of the transaction - key2 := database.MakeBucket().Key([]byte("key2")) + key2 := database.MakeBucket(nil).Key([]byte("key2")) value2 := []byte("value2") err = db.Put(key2, value2) if err != nil { @@ -238,7 +238,7 @@ func TestTransactionDelete(t *testing.T) { func testTransactionDelete(t *testing.T, db database.Database, testName string) { // Put a value into the database - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err := db.Put(key, value) if err != nil { @@ -327,7 +327,7 @@ func testTransactionCommit(t *testing.T, db database.Database, testName string) }() // Put a value into the transaction - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err = dbTx.Put(key, value) if err != nil { @@ -388,7 +388,7 @@ func testTransactionRollback(t *testing.T, db database.Database, testName string }() // Put a value into the transaction - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err = dbTx.Put(key, value) if err != nil { @@ -448,7 +448,7 @@ func testTransactionRollbackUnlessClosed(t *testing.T, db database.Database, tes }() // Put a value into the transaction - key := database.MakeBucket().Key([]byte("key")) + key := database.MakeBucket(nil).Key([]byte("key")) value := []byte("value") err = dbTx.Put(key, value) if err != nil { From effb545d20747ff1139f5295140c3cad48fe84cd Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 19 Jan 2021 17:20:25 +0200 Subject: [PATCH 265/351] Fix wrong condition and add logs (#1435) --- app/protocol/flows/handshake/handshake.go | 2 +- app/protocol/protocol.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/protocol/flows/handshake/handshake.go b/app/protocol/flows/handshake/handshake.go index ff2ce6d3b..aa6c5f686 100644 --- a/app/protocol/flows/handshake/handshake.go +++ b/app/protocol/flows/handshake/handshake.go @@ -82,7 +82,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N err := context.AddToPeers(peer) if err != nil { - if errors.As(err, &common.ErrPeerWithSameIDExists) { + if errors.Is(err, common.ErrPeerWithSameIDExists) { return nil, protocolerrors.Wrap(false, err, "peer already exists") } return nil, err diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 6ce09a3d7..89601a087 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -44,6 +44,7 @@ func (m *Manager) routerInitializer(router *routerpkg.Router, netConnection *net panic(err) } if isBanned { + log.Infof("Peer %s is banned. Disconnecting...", netConnection) netConnection.Disconnect() return } @@ -87,6 +88,7 @@ func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection panic(err) } } + log.Debugf("Disconnecting from %s (reason: %s)", netConnection, protocolErr.Cause) netConnection.Disconnect() return } From acf5423c63071c2853e9dc370b856edc8349eecf Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 19 Jan 2021 17:30:24 +0200 Subject: [PATCH 266/351] Remove docker test parallelism (#1434) * Remove docker parallelism * Remove redundant dash --- build_and_test.sh | 7 ++++++- docker/Dockerfile | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build_and_test.sh b/build_and_test.sh index 2e6d5c856..5153fd6eb 100755 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -19,4 +19,9 @@ go vet -composites=false $FLAGS ./... go build $FLAGS -o kaspad . -go test $FLAGS ./... \ No newline at end of file +if [ -n "${NO_PARALLEL}" ] +then + go test -parallel=1 $FLAGS ./... +else + go test $FLAGS ./... +fi \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index ab64a07e9..7a152738b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -18,7 +18,7 @@ COPY go.sum . COPY . . -RUN ./build_and_test.sh +RUN NO_PARALLEL=1 ./build_and_test.sh # --- multistage docker build: stage #2: runtime image FROM alpine From 2e0bc0f8c492318167f471aa47109b9f60097647 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 20 Jan 2021 09:48:48 +0200 Subject: [PATCH 267/351] Increase P2P connections' dial timeouts to 5 seconds (#1437) Co-authored-by: Elichai Turkel --- infrastructure/network/rpcclient/grpcclient/grpcclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/network/rpcclient/grpcclient/grpcclient.go b/infrastructure/network/rpcclient/grpcclient/grpcclient.go index 27652254d..1ded402ee 100644 --- a/infrastructure/network/rpcclient/grpcclient/grpcclient.go +++ b/infrastructure/network/rpcclient/grpcclient/grpcclient.go @@ -24,7 +24,7 @@ type GRPCClient struct { // Connect connects to the RPC server with the given address func Connect(address string) (*GRPCClient, error) { - const dialTimeout = 1 * time.Second + const dialTimeout = 5 * time.Second ctx, cancel := context.WithTimeout(context.Background(), dialTimeout) defer cancel() From abef96e3de320c6ca2a5a6dd80b8b3b92f73c571 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 20 Jan 2021 10:07:32 +0200 Subject: [PATCH 268/351] Add TestIBDWithPruning (#1425) * Add TestIBDWithPruning * Test block count * Fix a typo Co-authored-by: Elichai Turkel Co-authored-by: Mike Zak --- testing/integration/config_test.go | 4 ++ testing/integration/ibd_test.go | 105 +++++++++++++++++++++++++++++ testing/integration/setup_test.go | 4 ++ 3 files changed, 113 insertions(+) diff --git a/testing/integration/config_test.go b/testing/integration/config_test.go index 5309f6a23..251e94ab0 100644 --- a/testing/integration/config_test.go +++ b/testing/integration/config_test.go @@ -36,6 +36,10 @@ func setConfig(t *testing.T, harness *appHarness) { harness.config.Listeners = []string{harness.p2pAddress} harness.config.RPCListeners = []string{harness.rpcAddress} harness.config.UTXOIndex = harness.utxoIndex + + if harness.overrideDAGParams != nil { + harness.config.ActiveNetParams = harness.overrideDAGParams + } } func commonConfig() *config.Config { diff --git a/testing/integration/ibd_test.go b/testing/integration/ibd_test.go index 1a3b97803..04e8a8000 100644 --- a/testing/integration/ibd_test.go +++ b/testing/integration/ibd_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/app/appmessage" ) @@ -50,3 +52,106 @@ func TestIBD(t *testing.T) { t.Errorf("Tips of syncer: '%s' and syncee '%s' are not equal", tip1Hash.SelectedTipHash, tip2Hash.SelectedTipHash) } } + +// TestIBDWithPruning checks the IBD from a node with +// already pruned blocks. +func TestIBDWithPruning(t *testing.T) { + const numBlocks = 100 + + overrideDAGParams := dagconfig.SimnetParams + + // This is done to make a pruning depth of 6 blocks + overrideDAGParams.FinalityDuration = 2 * overrideDAGParams.TargetTimePerBlock + overrideDAGParams.K = 0 + harnesses, teardown := setupHarnesses(t, []*harnessParams{ + { + p2pAddress: p2pAddress1, + rpcAddress: rpcAddress1, + miningAddress: miningAddress1, + miningAddressPrivateKey: miningAddress1PrivateKey, + overrideDAGParams: &overrideDAGParams, + }, + { + p2pAddress: p2pAddress2, + rpcAddress: rpcAddress2, + miningAddress: miningAddress2, + miningAddressPrivateKey: miningAddress2PrivateKey, + overrideDAGParams: &overrideDAGParams, + }, + }) + defer teardown() + + syncer, syncee := harnesses[0], harnesses[1] + + // Let the syncee have two blocks that the syncer + // doesn't have to test a situation where + // the block locator will need more than one + // iteration to find the highest shared chain + // block. + const synceeOnlyBlocks = 2 + for i := 0; i < synceeOnlyBlocks; i++ { + mineNextBlock(t, syncee) + } + + for i := 0; i < numBlocks-1; i++ { + mineNextBlock(t, syncer) + } + + connect(t, syncer, syncee) + + // We expect this to trigger IBD + mineNextBlock(t, syncer) + + syncerBlockCountResponse, err := syncer.rpcClient.GetBlockCount() + if err != nil { + t.Fatalf("GetBlockCount: %+v", err) + } + + if syncerBlockCountResponse.BlockCount == syncerBlockCountResponse.HeaderCount { + t.Fatalf("Expected some pruned blocks but found none") + } + + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + start := time.Now() + for range ticker.C { + if time.Since(start) > defaultTimeout { + t.Fatalf("Timeout waiting for IBD to finish.") + } + + tip1Hash, err := syncer.rpcClient.GetSelectedTipHash() + if err != nil { + t.Fatalf("Error getting tip for syncer") + } + tip2Hash, err := syncee.rpcClient.GetSelectedTipHash() + if err != nil { + t.Fatalf("Error getting tip for syncee") + } + + if tip1Hash.SelectedTipHash == tip2Hash.SelectedTipHash { + break + } + } + + synceeBlockCountResponse, err := syncee.rpcClient.GetBlockCount() + if err != nil { + t.Fatalf("GetBlockCount: %+v", err) + } + + if synceeBlockCountResponse.BlockCount != syncerBlockCountResponse.BlockCount+synceeOnlyBlocks+1 { + t.Fatalf("Because the syncee haven't pruned any of its old blocks, its expected "+ + "block count is expected to be greater than the syncer by synceeOnlyBlocks(%d)+genesis, but instead "+ + "we got syncer block count of %d and syncee block count of %d", synceeOnlyBlocks, + syncerBlockCountResponse.BlockCount, + synceeBlockCountResponse.BlockCount) + } + + if synceeBlockCountResponse.HeaderCount != syncerBlockCountResponse.HeaderCount+synceeOnlyBlocks { + t.Fatalf("Because the syncer haven't synced from the syncee, its expected "+ + "block count is expected to be smaller by synceeOnlyBlocks(%d), but instead "+ + "we got syncer headers count of %d and syncee headers count of %d", synceeOnlyBlocks, + syncerBlockCountResponse.HeaderCount, + synceeBlockCountResponse.HeaderCount) + } +} diff --git a/testing/integration/setup_test.go b/testing/integration/setup_test.go index e0e2a17d9..c1bbab12a 100644 --- a/testing/integration/setup_test.go +++ b/testing/integration/setup_test.go @@ -1,6 +1,7 @@ package integration import ( + "github.com/kaspanet/kaspad/domain/dagconfig" "path/filepath" "testing" @@ -22,6 +23,7 @@ type appHarness struct { config *config.Config database database.Database utxoIndex bool + overrideDAGParams *dagconfig.Params } type harnessParams struct { @@ -30,6 +32,7 @@ type harnessParams struct { miningAddress string miningAddressPrivateKey string utxoIndex bool + overrideDAGParams *dagconfig.Params } // setupHarness creates a single appHarness with given parameters @@ -40,6 +43,7 @@ func setupHarness(t *testing.T, params *harnessParams) (harness *appHarness, tea miningAddress: params.miningAddress, miningAddressPrivateKey: params.miningAddressPrivateKey, utxoIndex: params.utxoIndex, + overrideDAGParams: params.overrideDAGParams, } setConfig(t, harness) From 319ab6cfcd5bdc521b9e27392a3bdc23638c71eb Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 20 Jan 2021 10:58:45 +0200 Subject: [PATCH 269/351] Always request orphan roots, even when you get an inv of a known orphan (#1436) Co-authored-by: Svarog --- app/protocol/flowcontext/orphans.go | 48 +++++++++++++++++++ .../flows/blockrelay/handle_relay_invs.go | 44 ++++++++++++----- .../add_block_to_virtual.go | 3 +- 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index 4ef23eb28..b0f4ffe2c 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -4,6 +4,8 @@ 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/domain/consensus/utils/hashset" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" ) @@ -160,3 +162,49 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) (*externa log.Infof("Unorphaned block %s", orphanHash) return blockInsertionResult, true, nil } + +// GetOrphanRoots returns the roots of the missing ancestors DAG of the given orphan +func (f *FlowContext) GetOrphanRoots(orphan *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "GetOrphanRoots") + defer onEnd() + + f.orphansMutex.RLock() + defer f.orphansMutex.RUnlock() + + _, ok := f.orphans[*orphan] + if !ok { + return nil, false, nil + } + + queue := []*externalapi.DomainHash{orphan} + addedToQueueSet := hashset.New() + addedToQueueSet.Add(orphan) + + roots := []*externalapi.DomainHash{} + for len(queue) > 0 { + var current *externalapi.DomainHash + current, queue = queue[0], queue[1:] + + block, ok := f.orphans[*current] + if !ok { + blockInfo, err := f.domain.Consensus().GetBlockInfo(current) + if err != nil { + return nil, false, err + } + + if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly { + roots = append(roots, current) + } + continue + } + + for _, parent := range block.Header.ParentHashes() { + if !addedToQueueSet.Contains(parent) { + queue = append(queue, parent) + addedToQueueSet.Add(parent) + } + } + } + + return roots, true, nil +} diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 3c383d5db..ae1005688 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -29,6 +29,7 @@ type RelayInvsContext interface { SharedRequestedBlocks() *SharedRequestedBlocks Broadcast(message appmessage.Message) error AddOrphan(orphanBlock *externalapi.DomainBlock) + GetOrphanRoots(orphanHash *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error) IsOrphan(blockHash *externalapi.DomainHash) bool IsIBDRunning() bool TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool @@ -71,7 +72,7 @@ func (flow *handleRelayInvsFlow) start() error { if err != nil { return err } - if blockInfo.Exists { + if blockInfo.Exists && blockInfo.BlockStatus != externalapi.StatusHeaderOnly { if blockInfo.BlockStatus == externalapi.StatusInvalid { return protocolerrors.Errorf(true, "sent inv of an invalid block %s", inv.Hash) @@ -81,7 +82,11 @@ func (flow *handleRelayInvsFlow) start() error { } if flow.IsOrphan(inv.Hash) { - log.Debugf("Block %s is a known orphan. continuing...", inv.Hash) + log.Debugf("Block %s is a known orphan. Requesting its missing ancestors", inv.Hash) + err := flow.AddOrphanRootsToQueue(inv.Hash) + if err != nil { + return err + } continue } @@ -107,7 +112,7 @@ func (flow *handleRelayInvsFlow) start() error { return err } if len(missingParents) > 0 { - log.Debugf("Block %s contains orphans: %s", inv.Hash, missingParents) + log.Debugf("Block %s is orphan and has missing parents: %s", inv.Hash, missingParents) err := flow.processOrphan(block, missingParents) if err != nil { return err @@ -238,9 +243,10 @@ func (flow *handleRelayInvsFlow) processOrphan(block *externalapi.DomainBlock, m } if isBlockInOrphanResolutionRange { log.Debugf("Block %s is within orphan resolution range. "+ - "Adding it to the orphan set and requesting its missing parents", blockHash) - flow.addToOrphanSetAndRequestMissingParents(block, missingParents) - return nil + "Adding it to the orphan set", blockHash) + flow.AddOrphan(block) + log.Debugf("Requesting block %s missing ancestors", blockHash) + return flow.AddOrphanRootsToQueue(blockHash) } // Start IBD unless we already are in IBD @@ -277,13 +283,25 @@ func (flow *handleRelayInvsFlow) isBlockInOrphanResolutionRange(blockHash *exter return false, nil } -func (flow *handleRelayInvsFlow) addToOrphanSetAndRequestMissingParents( - block *externalapi.DomainBlock, missingParents []*externalapi.DomainHash) { - - flow.AddOrphan(block) - invMessages := make([]*appmessage.MsgInvRelayBlock, len(missingParents)) - for i, missingParent := range missingParents { - invMessages[i] = appmessage.NewMsgInvBlock(missingParent) +func (flow *handleRelayInvsFlow) AddOrphanRootsToQueue(orphan *externalapi.DomainHash) error { + orphanRoots, orphanExists, err := flow.GetOrphanRoots(orphan) + if err != nil { + return err } + + if !orphanExists { + log.Infof("Orphan block %s was missing from the orphan pool while requesting for its roots. This "+ + "probably happened because it was randomly evicted immediately after it was added.", orphan) + } + + log.Infof("Block %s has %d missing ancestors. Adding them to the invs queue...", orphan, len(orphanRoots)) + + invMessages := make([]*appmessage.MsgInvRelayBlock, len(orphanRoots)) + for i, root := range orphanRoots { + log.Debugf("Adding block %s missing ancestor %s to the invs queue", orphan, root) + invMessages[i] = appmessage.NewMsgInvBlock(root) + } + flow.invsQueue = append(invMessages, flow.invsQueue...) + return nil } diff --git a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go index 104c3d101..3e1eaafb9 100644 --- a/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/add_block_to_virtual.go @@ -10,7 +10,8 @@ import ( // current virtual. This process may result in a new virtual block // getting created func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { - logger.LogAndMeasureExecutionTime(log, "csm.AddBlock") + onEnd := logger.LogAndMeasureExecutionTime(log, "csm.AddBlock") + defer onEnd() log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash) isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash) From 6a03d31f98692a66edb1e8fb2485ca733100fc90 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 21 Jan 2021 12:14:52 +0200 Subject: [PATCH 270/351] Remove accidental pointer indirection in dbKey (#1441) --- domain/consensus/database/key.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/domain/consensus/database/key.go b/domain/consensus/database/key.go index 5f75471f6..42b22a977 100644 --- a/domain/consensus/database/key.go +++ b/domain/consensus/database/key.go @@ -9,6 +9,9 @@ func dbKeyToDatabaseKey(key model.DBKey) *database.Key { if key, ok := key.(dbKey); ok { return key.key } + if key, ok := key.(*dbKey); ok { + return key.key + } return dbBucketToDatabaseBucket(key.Bucket()).Key(key.Suffix()) } @@ -29,5 +32,5 @@ func (d dbKey) Suffix() []byte { } func newDBKey(key *database.Key) model.DBKey { - return &dbKey{key: key} + return dbKey{key: key} } From 756f40c59aceee71a66e079eade4720ef3854d84 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 21 Jan 2021 17:24:52 +0200 Subject: [PATCH 271/351] Sync pruning point UTXO sets incrementally instead of all at once (#1431) * Replaced the content of MsgIBDRootUTXOSetChunk with pairs of outpoint-utxo entry pairs. * Rename utxoIter to utxoIterator. * Add a big stinky TODO on an assert. * Replace pruningStore staging with a UTXO set iterator. * Reimplement receiveAndInsertIBDRootUTXOSet. * Extract OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs into domainconverters.go. * Pass the outpoint and utxy entry pairs to the pruning store. * Implement InsertCandidatePruningPointUTXOs. * Implement ClearCandidatePruningPointUTXOs. * Implement UpdateCandidatePruningPointMultiset. * Use the candidate pruning point multiset in updatePruningPoint. * Implement CandidatePruningPointUTXOIterator. * Use the pruning point utxo set iterator for StageVirtualUTXOSet. * Defer ClearCandidatePruningPointUTXOs. * Implement OverwriteVirtualUTXOSet. * Implement CommitCandidatePruningPointUTXOSet. * Implement BeginOverwritingVirtualUTXOSet and FinishOverwritingVirtualUTXOSet. * Implement overwriteVirtualUTXOSetAndCommitPruningPointUTXOSet. * Rename ClearCandidatePruningPointUTXOs to ClearCandidatePruningPointData. * Add missing methods to dbManager. * Implement PruningPointUTXOs. * Implement RecoverUTXOIfRequired. * Delete the utxoserialization package. * Fix compilation errors in TestValidateAndInsertPruningPoint. * Switch order of operations in the if statements in PruningPointUTXOs so that Next() wouldn't be unnecessarily called. * Fix missing pruning point utxo set staging and bad slice length. * Fix no default multiset in InsertCandidatePruningPointUTXOs. * Make go vet happy. * Rename candidateXXX to importedXXX. * Do some more renaming. * Rename some more. * Fix bad MsgIBDRootNotFound logic. * Fix an error message. * Simplify receiveIBDRootBlock. * Fix error message in receiveAndInsertIBDRootUTXOSet. * Do some more renaming. * Fix merge errors. * Fix a bug caused by calling iterator.First() unnecessarily. * Remove databaseContext from stores and don't use a transaction in ClearXXX functions. * Simplify receiveAndInsertIBDRootUTXOSet. * Fix offset count in PruningPointUTXOs(). * Fix readOnlyUTXOIteratorWithDiff.First(). * Split handleRequestIBDRootUTXOSetAndBlockFlow into smaller methods. * Rename IbdRootNotFound to UnexpectedPruningPoint. * Rename requestIBDRootHash to requestPruningPointHash. * Rename IBDRootHash to PruningPointHash. * Rename RequestIBDRootUTXOSetAndBlock to RequestPruningPointUTXOSetAndBlock. * Rename IBDRootUTXOSetChunk to PruningPointUTXOSetChunk. * Rename RequestNextIBDRootUTXOSetChunk to RequestNextPruningPointUTXOSetChunk. * Rename DoneIBDRootUTXOSetChunks to DonePruningPointUTXOSetChunks. * Rename remaining references to IBD root. * Fix an error message. * Add a check for HadStartedImportingPruningPointUTXOSet in commitVirtualUTXODiff. * Add a check for HadStartedImportingPruningPointUTXOSet in ImportPruningPointUTXOSetIntoVirtualUTXOSet. * Move FinishImportingPruningPointUTXOSet closer to HadStartedImportingPruningPointUTXOSet. * Remove reference to pruningStore in utxoSetIterator. * Pointerify utxoSetIterator receivers. * Fix bad insert in CommitImportedPruningPointUTXOSet. * Rename commitImportedPruningPointUTXOSetAll to applyImportedPruningPointUTXOSet. * Simplify PruningPointUTXOs. * Add populateTransactionWithUTXOEntriesFromUTXOSet. * Fix a TODO comment. * Rename InsertImportedPruningPointUTXOs to AppendImportedPruningPointUTXOs. * Extract handleRequestPruningPointUTXOSetAndBlockMessage to a separate method. * Rename stuff in readOnlyUTXOIteratorWithDiff.First(). * Address toAddIterator in readOnlyUTXOIteratorWithDiff.First(). * Call First() before any full iteration on ReadOnlyUTXOSetIterator. * Call First() before any full iteration on a database Cursor. * Put StartImportingPruningPointUTXOSet inside the pruning point transaction. * Make serializeOutpoint and serializeUTXOEntry free functions in pruningStore. * Fix readOnlyUTXOIteratorWithDiff.First(). * Fix bad validations in importPruningPoint. * Remove superfluous call to validateBlockTransactionsAgainstPastUTXO. --- app/appmessage/domainconverters.go | 47 + app/appmessage/message.go | 78 +- app/appmessage/p2p_ibdrootnotfound.go | 22 - .../p2p_msgdoneibdrootutxosetchunks.go | 16 - .../p2p_msgdonepruningpointutxosetchunks.go | 16 + app/appmessage/p2p_msgibdroothash.go | 26 - app/appmessage/p2p_msgibdrootutxosetchunk.go | 19 - app/appmessage/p2p_msgpruningpointhash.go | 23 + .../p2p_msgpruningpointutxosetchunk.go | 36 + .../p2p_msgrequestibdrootutxosetandblock.go | 26 - .../p2p_msgrequestnextibdrootutxosetchunk.go | 16 - ..._msgrequestnextpruningpointutxosetchunk.go | 16 + ...p_msgrequestpruningpointutxosetandblock.go | 23 + app/appmessage/p2p_requestibdroothash.go | 22 - app/appmessage/p2p_requestpruningpointhash.go | 16 + app/appmessage/p2p_unexpectedpruningpoint.go | 16 + .../handle_ibd_root_hash_requests.go | 51 - .../handle_pruning_point_hash_requests.go | 51 + ...dle_request_ibd_root_utxo_set_and_block.go | 117 -- ...equest_pruning_point_utxo_set_and_block.go | 143 +++ app/protocol/flows/blockrelay/ibd.go | 139 ++- app/protocol/protocol.go | 20 +- domain/consensus/consensus.go | 26 +- domain/consensus/database/dbmanager.go | 8 + .../database/serialization/utxo_collection.go | 2 +- .../consensusstatestore.go | 7 - .../consensusstatestore/utxo.go | 116 +- .../consensusstatestore/virtual_utxo_set.go | 81 ++ .../pruningstore/imported_pruning_point.go | 213 ++++ .../pruningstore/pruningstore.go | 114 +- domain/consensus/factory.go | 9 + domain/consensus/model/database.go | 5 +- .../consensus/model/externalapi/consensus.go | 6 +- .../consensus/model/externalapi/utxoentry.go | 7 + ...face_datastructures_consensusstatestore.go | 8 +- .../interface_datastructures_pruningstore.go | 12 +- .../interface_processes_blockprocessor.go | 2 +- ...terface_processes_consensusstatemanager.go | 3 +- .../interface_processes_pruningmanager.go | 2 + domain/consensus/model/readonlyutxoset.go | 1 + .../blockprocessor/blockprocessor.go | 6 +- .../blockprocessor/validateandinsertblock.go | 2 +- ... validateandinsertimportedpruningpoint.go} | 4 +- ...dateandinsertimportedpruningpoint_test.go} | 122 +- .../calculate_past_utxo_test.go | 2 +- .../import_pruning_utxo_set.go | 218 ++++ .../populate_tx_with_utxo_entries.go | 46 + .../update_pruning_utxo_set.go | 174 --- .../consensusstatemanager/update_virtual.go | 5 +- .../pruningmanager/pruningmanager.go | 99 +- domain/consensus/utils/utxo/utxo_iterator.go | 5 + .../utils/utxo/utxo_iterator_with_diff.go | 23 +- .../utils/utxoserialization/generate.go | 3 - .../utils/utxoserialization/multiset.go | 15 - .../consensus/utils/utxoserialization/utxo.go | 30 - .../utils/utxoserialization/utxo.pb.go | 217 ---- .../utils/utxoserialization/utxo.proto | 12 - .../grpcserver/protowire/messages.pb.go | 1091 +++++++++-------- .../grpcserver/protowire/messages.proto | 14 +- .../server/grpcserver/protowire/p2p.pb.go | 680 ++++++---- .../server/grpcserver/protowire/p2p.proto | 30 +- .../p2p_done_ibd_root_utxo_set_chunks.go | 12 - .../p2p_done_pruning_point_utxo_set_chunks.go | 12 + .../grpcserver/protowire/p2p_ibd_root_hash.go | 19 - .../protowire/p2p_ibd_root_not_found.go | 11 - .../protowire/p2p_ibd_root_utxo_set_chunk.go | 16 - .../protowire/p2p_pruning_point_hash.go | 19 + .../p2p_pruning_point_utxo_set_chunk.go | 71 ++ .../protowire/p2p_request_ibd_root_hash.go | 11 - ...p2p_request_ibd_root_utxo_set_and_block.go | 20 - ...2p_request_next_ibd_root_utxo_set_chunk.go | 12 - ...quest_next_pruning_point_utxo_set_chunk.go | 12 + .../p2p_request_pruning_point_hash.go | 11 + ...equest_pruning_point_utxo_set_and_block.go | 19 + .../protowire/p2p_unexpected_pruning_point.go | 11 + .../server/grpcserver/protowire/wire.go | 28 +- 76 files changed, 2599 insertions(+), 2044 deletions(-) delete mode 100644 app/appmessage/p2p_ibdrootnotfound.go delete mode 100644 app/appmessage/p2p_msgdoneibdrootutxosetchunks.go create mode 100644 app/appmessage/p2p_msgdonepruningpointutxosetchunks.go delete mode 100644 app/appmessage/p2p_msgibdroothash.go delete mode 100644 app/appmessage/p2p_msgibdrootutxosetchunk.go create mode 100644 app/appmessage/p2p_msgpruningpointhash.go create mode 100644 app/appmessage/p2p_msgpruningpointutxosetchunk.go delete mode 100644 app/appmessage/p2p_msgrequestibdrootutxosetandblock.go delete mode 100644 app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go create mode 100644 app/appmessage/p2p_msgrequestnextpruningpointutxosetchunk.go create mode 100644 app/appmessage/p2p_msgrequestpruningpointutxosetandblock.go delete mode 100644 app/appmessage/p2p_requestibdroothash.go create mode 100644 app/appmessage/p2p_requestpruningpointhash.go create mode 100644 app/appmessage/p2p_unexpectedpruningpoint.go delete mode 100644 app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go create mode 100644 app/protocol/flows/blockrelay/handle_pruning_point_hash_requests.go delete mode 100644 app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go create mode 100644 app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go create mode 100644 domain/consensus/datastructures/consensusstatestore/virtual_utxo_set.go create mode 100644 domain/consensus/datastructures/pruningstore/imported_pruning_point.go rename domain/consensus/processes/blockprocessor/{validateandinsertpruningpoint.go => validateandinsertimportedpruningpoint.go} (88%) rename domain/consensus/processes/blockprocessor/{validateandinsertpruningpoint_test.go => validateandinsertimportedpruningpoint_test.go} (79%) create mode 100644 domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go delete mode 100644 domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go delete mode 100644 domain/consensus/utils/utxoserialization/generate.go delete mode 100644 domain/consensus/utils/utxoserialization/multiset.go delete mode 100644 domain/consensus/utils/utxoserialization/utxo.go delete mode 100644 domain/consensus/utils/utxoserialization/utxo.pb.go delete mode 100644 domain/consensus/utils/utxoserialization/utxo.proto delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_pruning_point_utxo_set_chunks.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_hash.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_utxo_set_chunk.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go delete mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_pruning_point_utxo_set_chunk.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_hash.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_utxo_set_and_block.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_unexpected_pruning_point.go diff --git a/app/appmessage/domainconverters.go b/app/appmessage/domainconverters.go index 0c8cc88e0..3ba70139a 100644 --- a/app/appmessage/domainconverters.go +++ b/app/appmessage/domainconverters.go @@ -3,6 +3,7 @@ package appmessage import ( "encoding/hex" "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" @@ -268,3 +269,49 @@ func DomainTransactionToRPCTransaction(transaction *externalapi.DomainTransactio Payload: payload, } } + +// OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs converts +// OutpointAndUTXOEntryPairs to domain OutpointAndUTXOEntryPairs +func OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs( + outpointAndUTXOEntryPairs []*OutpointAndUTXOEntryPair) []*externalapi.OutpointAndUTXOEntryPair { + + domainOutpointAndUTXOEntryPairs := make([]*externalapi.OutpointAndUTXOEntryPair, len(outpointAndUTXOEntryPairs)) + for i, outpointAndUTXOEntryPair := range outpointAndUTXOEntryPairs { + domainOutpointAndUTXOEntryPairs[i] = &externalapi.OutpointAndUTXOEntryPair{ + Outpoint: &externalapi.DomainOutpoint{ + TransactionID: outpointAndUTXOEntryPair.Outpoint.TxID, + Index: outpointAndUTXOEntryPair.Outpoint.Index, + }, + UTXOEntry: utxo.NewUTXOEntry( + outpointAndUTXOEntryPair.UTXOEntry.Amount, + outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey, + outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase, + outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore, + ), + } + } + return domainOutpointAndUTXOEntryPairs +} + +// DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs converts +// domain OutpointAndUTXOEntryPairs to OutpointAndUTXOEntryPairs +func DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs( + outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) []*OutpointAndUTXOEntryPair { + + domainOutpointAndUTXOEntryPairs := make([]*OutpointAndUTXOEntryPair, len(outpointAndUTXOEntryPairs)) + for i, outpointAndUTXOEntryPair := range outpointAndUTXOEntryPairs { + domainOutpointAndUTXOEntryPairs[i] = &OutpointAndUTXOEntryPair{ + Outpoint: &Outpoint{ + TxID: outpointAndUTXOEntryPair.Outpoint.TransactionID, + Index: outpointAndUTXOEntryPair.Outpoint.Index, + }, + UTXOEntry: &UTXOEntry{ + Amount: outpointAndUTXOEntryPair.UTXOEntry.Amount(), + ScriptPublicKey: outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey(), + IsCoinbase: outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase(), + BlockBlueScore: outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore(), + }, + } + } + return domainOutpointAndUTXOEntryPairs +} diff --git a/app/appmessage/message.go b/app/appmessage/message.go index de92b3fe7..9f609f30a 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -51,17 +51,17 @@ const ( CmdReject CmdHeader CmdRequestNextHeaders - CmdRequestIBDRootUTXOSetAndBlock - CmdIBDRootUTXOSetChunk + CmdRequestPruningPointUTXOSetAndBlock + CmdPruningPointUTXOSetChunk CmdRequestIBDBlocks - CmdIBDRootNotFound - CmdRequestIBDRootHash - CmdIBDRootHash + CmdUnexpectedPruningPoint + CmdRequestPruningPointHash + CmdPruningPointHash CmdIBDBlockLocator CmdIBDBlockLocatorHighestHash CmdBlockHeaders - CmdRequestNextIBDRootUTXOSetChunk - CmdDoneIBDRootUTXOSetChunks + CmdRequestNextPruningPointUTXOSetChunk + CmdDonePruningPointUTXOSetChunks // rpc CmdGetCurrentNetworkRequestMessage @@ -127,38 +127,38 @@ const ( // ProtocolMessageCommandToString maps all MessageCommands to their string representation var ProtocolMessageCommandToString = map[MessageCommand]string{ - CmdVersion: "Version", - CmdVerAck: "VerAck", - CmdRequestAddresses: "RequestAddresses", - CmdAddresses: "Addresses", - CmdRequestHeaders: "RequestHeaders", - CmdBlock: "Block", - CmdTx: "Tx", - CmdPing: "Ping", - CmdPong: "Pong", - CmdRequestBlockLocator: "RequestBlockLocator", - CmdBlockLocator: "BlockLocator", - CmdInvRelayBlock: "InvRelayBlock", - CmdRequestRelayBlocks: "RequestRelayBlocks", - CmdInvTransaction: "InvTransaction", - CmdRequestTransactions: "RequestTransactions", - CmdIBDBlock: "IBDBlock", - CmdDoneHeaders: "DoneHeaders", - CmdTransactionNotFound: "TransactionNotFound", - CmdReject: "Reject", - CmdHeader: "Header", - CmdRequestNextHeaders: "RequestNextHeaders", - CmdRequestIBDRootUTXOSetAndBlock: "RequestPruningUTXOSetAndBlock", - CmdIBDRootUTXOSetChunk: "IBDRootUTXOSetChunk", - CmdRequestIBDBlocks: "RequestIBDBlocks", - CmdIBDRootNotFound: "IBDRootNotFound", - CmdRequestIBDRootHash: "IBDRequestIBDRootHash", - CmdIBDRootHash: "IBDIBDRootHash", - CmdIBDBlockLocator: "IBDBlockLocator", - CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", - CmdBlockHeaders: "BlockHeaders", - CmdRequestNextIBDRootUTXOSetChunk: "RequestNextIBDRootUTXOSetChunk", - CmdDoneIBDRootUTXOSetChunks: "DoneIBDRootUTXOSetChunks", + CmdVersion: "Version", + CmdVerAck: "VerAck", + CmdRequestAddresses: "RequestAddresses", + CmdAddresses: "Addresses", + CmdRequestHeaders: "RequestHeaders", + CmdBlock: "Block", + CmdTx: "Tx", + CmdPing: "Ping", + CmdPong: "Pong", + CmdRequestBlockLocator: "RequestBlockLocator", + CmdBlockLocator: "BlockLocator", + CmdInvRelayBlock: "InvRelayBlock", + CmdRequestRelayBlocks: "RequestRelayBlocks", + CmdInvTransaction: "InvTransaction", + CmdRequestTransactions: "RequestTransactions", + CmdIBDBlock: "IBDBlock", + CmdDoneHeaders: "DoneHeaders", + CmdTransactionNotFound: "TransactionNotFound", + CmdReject: "Reject", + CmdHeader: "Header", + CmdRequestNextHeaders: "RequestNextHeaders", + CmdRequestPruningPointUTXOSetAndBlock: "RequestPruningPointUTXOSetAndBlock", + CmdPruningPointUTXOSetChunk: "PruningPointUTXOSetChunk", + CmdRequestIBDBlocks: "RequestIBDBlocks", + CmdUnexpectedPruningPoint: "UnexpectedPruningPoint", + CmdRequestPruningPointHash: "RequestPruningPointHashHash", + CmdPruningPointHash: "PruningPointHash", + CmdIBDBlockLocator: "IBDBlockLocator", + CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", + CmdBlockHeaders: "BlockHeaders", + CmdRequestNextPruningPointUTXOSetChunk: "RequestNextPruningPointUTXOSetChunk", + CmdDonePruningPointUTXOSetChunks: "DonePruningPointUTXOSetChunks", } // RPCMessageCommandToString maps all MessageCommands to their string representation diff --git a/app/appmessage/p2p_ibdrootnotfound.go b/app/appmessage/p2p_ibdrootnotfound.go deleted file mode 100644 index 2e7adf8dc..000000000 --- a/app/appmessage/p2p_ibdrootnotfound.go +++ /dev/null @@ -1,22 +0,0 @@ -package appmessage - -// MsgIBDRootNotFound implements the Message interface and represents a kaspa -// IBDRootNotFound message. It is used to notify the IBD root that was requested -// by other peer was not found. -// -// This message has no payload. -type MsgIBDRootNotFound struct { - baseMessage -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgIBDRootNotFound) Command() MessageCommand { - return CmdIBDRootNotFound -} - -// NewMsgIBDRootNotFound returns a new kaspa IBDRootNotFound message that conforms to the -// Message interface. -func NewMsgIBDRootNotFound() *MsgIBDRootNotFound { - return &MsgIBDRootNotFound{} -} diff --git a/app/appmessage/p2p_msgdoneibdrootutxosetchunks.go b/app/appmessage/p2p_msgdoneibdrootutxosetchunks.go deleted file mode 100644 index 32760c48a..000000000 --- a/app/appmessage/p2p_msgdoneibdrootutxosetchunks.go +++ /dev/null @@ -1,16 +0,0 @@ -package appmessage - -// MsgDoneIBDRootUTXOSetChunks represents a kaspa DoneIBDRootUTXOSetChunks message -type MsgDoneIBDRootUTXOSetChunks struct { - baseMessage -} - -// Command returns the protocol command string for the message -func (msg *MsgDoneIBDRootUTXOSetChunks) Command() MessageCommand { - return CmdDoneIBDRootUTXOSetChunks -} - -// NewMsgDoneIBDRootUTXOSetChunks returns a new MsgDoneIBDRootUTXOSetChunks. -func NewMsgDoneIBDRootUTXOSetChunks() *MsgDoneIBDRootUTXOSetChunks { - return &MsgDoneIBDRootUTXOSetChunks{} -} diff --git a/app/appmessage/p2p_msgdonepruningpointutxosetchunks.go b/app/appmessage/p2p_msgdonepruningpointutxosetchunks.go new file mode 100644 index 000000000..ba2fdca63 --- /dev/null +++ b/app/appmessage/p2p_msgdonepruningpointutxosetchunks.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgDonePruningPointUTXOSetChunks represents a kaspa DonePruningPointUTXOSetChunks message +type MsgDonePruningPointUTXOSetChunks struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgDonePruningPointUTXOSetChunks) Command() MessageCommand { + return CmdDonePruningPointUTXOSetChunks +} + +// NewMsgDonePruningPointUTXOSetChunks returns a new MsgDonePruningPointUTXOSetChunks. +func NewMsgDonePruningPointUTXOSetChunks() *MsgDonePruningPointUTXOSetChunks { + return &MsgDonePruningPointUTXOSetChunks{} +} diff --git a/app/appmessage/p2p_msgibdroothash.go b/app/appmessage/p2p_msgibdroothash.go deleted file mode 100644 index 2ed8568bb..000000000 --- a/app/appmessage/p2p_msgibdroothash.go +++ /dev/null @@ -1,26 +0,0 @@ -package appmessage - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// MsgIBDRootHashMessage implements the Message interface and represents a kaspa -// IBDRootHash message. It is used as a reply to IBD root hash requests. -type MsgIBDRootHashMessage struct { - baseMessage - Hash *externalapi.DomainHash -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgIBDRootHashMessage) Command() MessageCommand { - return CmdIBDRootHash -} - -// NewMsgIBDRootHashMessage returns a new kaspa IBDRootHash message that conforms to -// the Message interface. See MsgIBDRootHashMessage for details. -func NewMsgIBDRootHashMessage(hash *externalapi.DomainHash) *MsgIBDRootHashMessage { - return &MsgIBDRootHashMessage{ - Hash: hash, - } -} diff --git a/app/appmessage/p2p_msgibdrootutxosetchunk.go b/app/appmessage/p2p_msgibdrootutxosetchunk.go deleted file mode 100644 index d1a1e0574..000000000 --- a/app/appmessage/p2p_msgibdrootutxosetchunk.go +++ /dev/null @@ -1,19 +0,0 @@ -package appmessage - -// MsgIBDRootUTXOSetChunk represents a kaspa IBDRootUTXOSetChunk message -type MsgIBDRootUTXOSetChunk struct { - baseMessage - Chunk []byte -} - -// Command returns the protocol command string for the message -func (msg *MsgIBDRootUTXOSetChunk) Command() MessageCommand { - return CmdIBDRootUTXOSetChunk -} - -// NewMsgIBDRootUTXOSetChunk returns a new MsgIBDRootUTXOSetChunk. -func NewMsgIBDRootUTXOSetChunk(chunk []byte) *MsgIBDRootUTXOSetChunk { - return &MsgIBDRootUTXOSetChunk{ - Chunk: chunk, - } -} diff --git a/app/appmessage/p2p_msgpruningpointhash.go b/app/appmessage/p2p_msgpruningpointhash.go new file mode 100644 index 000000000..0b0a808a0 --- /dev/null +++ b/app/appmessage/p2p_msgpruningpointhash.go @@ -0,0 +1,23 @@ +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgPruningPointHashMessage represents a kaspa PruningPointHash message +type MsgPruningPointHashMessage struct { + baseMessage + Hash *externalapi.DomainHash +} + +// Command returns the protocol command string for the message +func (msg *MsgPruningPointHashMessage) Command() MessageCommand { + return CmdPruningPointHash +} + +// NewPruningPointHashMessage returns a new kaspa PruningPointHash message +func NewPruningPointHashMessage(hash *externalapi.DomainHash) *MsgPruningPointHashMessage { + return &MsgPruningPointHashMessage{ + Hash: hash, + } +} diff --git a/app/appmessage/p2p_msgpruningpointutxosetchunk.go b/app/appmessage/p2p_msgpruningpointutxosetchunk.go new file mode 100644 index 000000000..d0d3f4291 --- /dev/null +++ b/app/appmessage/p2p_msgpruningpointutxosetchunk.go @@ -0,0 +1,36 @@ +package appmessage + +import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + +// MsgPruningPointUTXOSetChunk represents a kaspa PruningPointUTXOSetChunk message +type MsgPruningPointUTXOSetChunk struct { + baseMessage + OutpointAndUTXOEntryPairs []*OutpointAndUTXOEntryPair +} + +// Command returns the protocol command string for the message +func (msg *MsgPruningPointUTXOSetChunk) Command() MessageCommand { + return CmdPruningPointUTXOSetChunk +} + +// NewMsgPruningPointUTXOSetChunk returns a new MsgPruningPointUTXOSetChunk. +func NewMsgPruningPointUTXOSetChunk(outpointAndUTXOEntryPairs []*OutpointAndUTXOEntryPair) *MsgPruningPointUTXOSetChunk { + return &MsgPruningPointUTXOSetChunk{ + OutpointAndUTXOEntryPairs: outpointAndUTXOEntryPairs, + } +} + +// OutpointAndUTXOEntryPair is an outpoint along with its +// respective UTXO entry +type OutpointAndUTXOEntryPair struct { + Outpoint *Outpoint + UTXOEntry *UTXOEntry +} + +// UTXOEntry houses details about an individual transaction output in a UTXO +type UTXOEntry struct { + Amount uint64 + ScriptPublicKey *externalapi.ScriptPublicKey + BlockBlueScore uint64 + IsCoinbase bool +} diff --git a/app/appmessage/p2p_msgrequestibdrootutxosetandblock.go b/app/appmessage/p2p_msgrequestibdrootutxosetandblock.go deleted file mode 100644 index 1a828775b..000000000 --- a/app/appmessage/p2p_msgrequestibdrootutxosetandblock.go +++ /dev/null @@ -1,26 +0,0 @@ -package appmessage - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// MsgRequestIBDRootUTXOSetAndBlock implements the Message interface and represents a kaspa -// RequestIBDRootUTXOSetAndBlock message. It is used to request the UTXO set and block body -// of the IBD root block. -type MsgRequestIBDRootUTXOSetAndBlock struct { - baseMessage - IBDRoot *externalapi.DomainHash -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgRequestIBDRootUTXOSetAndBlock) Command() MessageCommand { - return CmdRequestIBDRootUTXOSetAndBlock -} - -// NewMsgRequestIBDRootUTXOSetAndBlock returns a new MsgRequestIBDRootUTXOSetAndBlock. -func NewMsgRequestIBDRootUTXOSetAndBlock(ibdRoot *externalapi.DomainHash) *MsgRequestIBDRootUTXOSetAndBlock { - return &MsgRequestIBDRootUTXOSetAndBlock{ - IBDRoot: ibdRoot, - } -} diff --git a/app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go b/app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go deleted file mode 100644 index 34689237e..000000000 --- a/app/appmessage/p2p_msgrequestnextibdrootutxosetchunk.go +++ /dev/null @@ -1,16 +0,0 @@ -package appmessage - -// MsgRequestNextIBDRootUTXOSetChunk represents a kaspa RequestNextIBDRootUTXOSetChunk message -type MsgRequestNextIBDRootUTXOSetChunk struct { - baseMessage -} - -// Command returns the protocol command string for the message -func (msg *MsgRequestNextIBDRootUTXOSetChunk) Command() MessageCommand { - return CmdRequestNextIBDRootUTXOSetChunk -} - -// NewMsgRequestNextIBDRootUTXOSetChunk returns a new MsgRequestNextIBDRootUTXOSetChunk. -func NewMsgRequestNextIBDRootUTXOSetChunk() *MsgRequestNextIBDRootUTXOSetChunk { - return &MsgRequestNextIBDRootUTXOSetChunk{} -} diff --git a/app/appmessage/p2p_msgrequestnextpruningpointutxosetchunk.go b/app/appmessage/p2p_msgrequestnextpruningpointutxosetchunk.go new file mode 100644 index 000000000..356e7c814 --- /dev/null +++ b/app/appmessage/p2p_msgrequestnextpruningpointutxosetchunk.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgRequestNextPruningPointUTXOSetChunk represents a kaspa RequestNextPruningPointUTXOSetChunk message +type MsgRequestNextPruningPointUTXOSetChunk struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgRequestNextPruningPointUTXOSetChunk) Command() MessageCommand { + return CmdRequestNextPruningPointUTXOSetChunk +} + +// NewMsgRequestNextPruningPointUTXOSetChunk returns a new MsgRequestNextPruningPointUTXOSetChunk. +func NewMsgRequestNextPruningPointUTXOSetChunk() *MsgRequestNextPruningPointUTXOSetChunk { + return &MsgRequestNextPruningPointUTXOSetChunk{} +} diff --git a/app/appmessage/p2p_msgrequestpruningpointutxosetandblock.go b/app/appmessage/p2p_msgrequestpruningpointutxosetandblock.go new file mode 100644 index 000000000..4ad00a909 --- /dev/null +++ b/app/appmessage/p2p_msgrequestpruningpointutxosetandblock.go @@ -0,0 +1,23 @@ +package appmessage + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +// MsgRequestPruningPointUTXOSetAndBlock represents a kaspa RequestPruningPointUTXOSetAndBlock message +type MsgRequestPruningPointUTXOSetAndBlock struct { + baseMessage + PruningPointHash *externalapi.DomainHash +} + +// Command returns the protocol command string for the message +func (msg *MsgRequestPruningPointUTXOSetAndBlock) Command() MessageCommand { + return CmdRequestPruningPointUTXOSetAndBlock +} + +// NewMsgRequestPruningPointUTXOSetAndBlock returns a new MsgRequestPruningPointUTXOSetAndBlock +func NewMsgRequestPruningPointUTXOSetAndBlock(pruningPointHash *externalapi.DomainHash) *MsgRequestPruningPointUTXOSetAndBlock { + return &MsgRequestPruningPointUTXOSetAndBlock{ + PruningPointHash: pruningPointHash, + } +} diff --git a/app/appmessage/p2p_requestibdroothash.go b/app/appmessage/p2p_requestibdroothash.go deleted file mode 100644 index ce30225fc..000000000 --- a/app/appmessage/p2p_requestibdroothash.go +++ /dev/null @@ -1,22 +0,0 @@ -package appmessage - -// MsgRequestIBDRootHashMessage implements the Message interface and represents a kaspa -// MsgRequestIBDRootHashMessage message. It is used to request the IBD root hash -// from a peer during IBD. -// -// This message has no payload. -type MsgRequestIBDRootHashMessage struct { - baseMessage -} - -// Command returns the protocol command string for the message. This is part -// of the Message interface implementation. -func (msg *MsgRequestIBDRootHashMessage) Command() MessageCommand { - return CmdRequestIBDRootHash -} - -// NewMsgRequestIBDRootHashMessage returns a new kaspa RequestIBDRootHash message that conforms to the -// Message interface. -func NewMsgRequestIBDRootHashMessage() *MsgRequestIBDRootHashMessage { - return &MsgRequestIBDRootHashMessage{} -} diff --git a/app/appmessage/p2p_requestpruningpointhash.go b/app/appmessage/p2p_requestpruningpointhash.go new file mode 100644 index 000000000..c91642e4b --- /dev/null +++ b/app/appmessage/p2p_requestpruningpointhash.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgRequestPruningPointHashMessage represents a kaspa RequestPruningPointHashMessage message +type MsgRequestPruningPointHashMessage struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgRequestPruningPointHashMessage) Command() MessageCommand { + return CmdRequestPruningPointHash +} + +// NewMsgRequestPruningPointHashMessage returns a new kaspa RequestPruningPointHash message +func NewMsgRequestPruningPointHashMessage() *MsgRequestPruningPointHashMessage { + return &MsgRequestPruningPointHashMessage{} +} diff --git a/app/appmessage/p2p_unexpectedpruningpoint.go b/app/appmessage/p2p_unexpectedpruningpoint.go new file mode 100644 index 000000000..0546ea1be --- /dev/null +++ b/app/appmessage/p2p_unexpectedpruningpoint.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgUnexpectedPruningPoint represents a kaspa UnexpectedPruningPoint message +type MsgUnexpectedPruningPoint struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgUnexpectedPruningPoint) Command() MessageCommand { + return CmdUnexpectedPruningPoint +} + +// NewMsgUnexpectedPruningPoint returns a new kaspa UnexpectedPruningPoint message +func NewMsgUnexpectedPruningPoint() *MsgUnexpectedPruningPoint { + return &MsgUnexpectedPruningPoint{} +} diff --git a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go b/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go deleted file mode 100644 index 1250560f7..000000000 --- a/app/protocol/flows/blockrelay/handle_ibd_root_hash_requests.go +++ /dev/null @@ -1,51 +0,0 @@ -package blockrelay - -import ( - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/domain" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" -) - -// HandleIBDRootHashRequestsFlowContext is the interface for the context needed for the handleIBDRootHashRequestsFlow flow. -type HandleIBDRootHashRequestsFlowContext interface { - Domain() domain.Domain -} - -type handleIBDRootHashRequestsFlow struct { - HandleIBDRootHashRequestsFlowContext - incomingRoute, outgoingRoute *router.Route -} - -// HandleIBDRootHashRequests listens to appmessage.MsgRequestIBDRootHashMessage messages and sends -// the IBD root hash as response. -func HandleIBDRootHashRequests(context HandleIBDRootHashRequestsFlowContext, incomingRoute, - outgoingRoute *router.Route) error { - flow := &handleIBDRootHashRequestsFlow{ - HandleIBDRootHashRequestsFlowContext: context, - incomingRoute: incomingRoute, - outgoingRoute: outgoingRoute, - } - - return flow.start() -} - -func (flow *handleIBDRootHashRequestsFlow) start() error { - for { - _, err := flow.incomingRoute.Dequeue() - if err != nil { - return err - } - log.Debugf("Got request for IBD root hash") - - pruningPoint, err := flow.Domain().Consensus().PruningPoint() - if err != nil { - return err - } - - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootHashMessage(pruningPoint)) - if err != nil { - return err - } - log.Debugf("Sent IBD root hash %s", pruningPoint) - } -} diff --git a/app/protocol/flows/blockrelay/handle_pruning_point_hash_requests.go b/app/protocol/flows/blockrelay/handle_pruning_point_hash_requests.go new file mode 100644 index 000000000..7352b765d --- /dev/null +++ b/app/protocol/flows/blockrelay/handle_pruning_point_hash_requests.go @@ -0,0 +1,51 @@ +package blockrelay + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandlePruningPointHashRequestsFlowContext is the interface for the context needed for the handlePruningPointHashRequestsFlow flow. +type HandlePruningPointHashRequestsFlowContext interface { + Domain() domain.Domain +} + +type handlePruningPointHashRequestsFlow struct { + HandlePruningPointHashRequestsFlowContext + incomingRoute, outgoingRoute *router.Route +} + +// HandlePruningPointHashRequests listens to appmessage.MsgRequestPruningPointHashMessage messages and sends +// the pruning point hash as response. +func HandlePruningPointHashRequests(context HandlePruningPointHashRequestsFlowContext, incomingRoute, + outgoingRoute *router.Route) error { + flow := &handlePruningPointHashRequestsFlow{ + HandlePruningPointHashRequestsFlowContext: context, + incomingRoute: incomingRoute, + outgoingRoute: outgoingRoute, + } + + return flow.start() +} + +func (flow *handlePruningPointHashRequestsFlow) start() error { + for { + _, err := flow.incomingRoute.Dequeue() + if err != nil { + return err + } + log.Debugf("Got request for a pruning point hash") + + pruningPoint, err := flow.Domain().Consensus().PruningPoint() + if err != nil { + return err + } + + err = flow.outgoingRoute.Enqueue(appmessage.NewPruningPointHashMessage(pruningPoint)) + if err != nil { + return err + } + log.Debugf("Sent pruning point hash %s", pruningPoint) + } +} diff --git a/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go b/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go deleted file mode 100644 index 9a4003597..000000000 --- a/app/protocol/flows/blockrelay/handle_request_ibd_root_utxo_set_and_block.go +++ /dev/null @@ -1,117 +0,0 @@ -package blockrelay - -import ( - "errors" - "github.com/kaspanet/kaspad/app/appmessage" - "github.com/kaspanet/kaspad/app/protocol/common" - "github.com/kaspanet/kaspad/app/protocol/protocolerrors" - "github.com/kaspanet/kaspad/domain" - "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" - "github.com/kaspanet/kaspad/infrastructure/logger" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" -) - -// HandleRequestIBDRootUTXOSetAndBlockContext is the interface for the context needed for the HandleRequestIBDRootUTXOSetAndBlock flow. -type HandleRequestIBDRootUTXOSetAndBlockContext interface { - Domain() domain.Domain -} - -type handleRequestIBDRootUTXOSetAndBlockFlow struct { - HandleRequestIBDRootUTXOSetAndBlockContext - incomingRoute, outgoingRoute *router.Route -} - -// HandleRequestIBDRootUTXOSetAndBlock listens to appmessage.MsgRequestIBDRootUTXOSetAndBlock messages and sends -// the IBD root UTXO set and block body. -func HandleRequestIBDRootUTXOSetAndBlock(context HandleRequestIBDRootUTXOSetAndBlockContext, incomingRoute, - outgoingRoute *router.Route) error { - flow := &handleRequestIBDRootUTXOSetAndBlockFlow{ - HandleRequestIBDRootUTXOSetAndBlockContext: context, - incomingRoute: incomingRoute, - outgoingRoute: outgoingRoute, - } - - return flow.start() -} - -func (flow *handleRequestIBDRootUTXOSetAndBlockFlow) start() error { - for { - message, err := flow.incomingRoute.Dequeue() - if err != nil { - return err - } - msgRequestIBDRootUTXOSetAndBlock, ok := message.(*appmessage.MsgRequestIBDRootUTXOSetAndBlock) - if !ok { - return protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdRequestIBDRootUTXOSetAndBlock, message.Command()) - } - - finishMeasuring := logger.LogAndMeasureExecutionTime(log, "handleRequestIBDRootUTXOSetAndBlockFlow") - log.Debugf("Got request for IBDRoot UTXOSet and Block") - - serializedUTXOSet, err := flow.Domain().Consensus().GetPruningPointUTXOSet(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - if err != nil { - if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) { - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootNotFound()) - if err != nil { - return err - } - - continue - } - } - log.Debugf("Retrieved utxo set for pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - - block, err := flow.Domain().Consensus().GetBlock(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - if err != nil { - return err - } - log.Debugf("Retrieved pruning block %s", msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(block))) - if err != nil { - return err - } - - // Send the UTXO set in `step`-sized chunks - const step = 1024 * 1024 // 1MB - offset := 0 - chunksSent := 0 - for offset < len(serializedUTXOSet) { - var chunk []byte - if offset+step < len(serializedUTXOSet) { - chunk = serializedUTXOSet[offset : offset+step] - } else { - chunk = serializedUTXOSet[offset:] - } - - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDRootUTXOSetChunk(chunk)) - if err != nil { - return err - } - - offset += step - chunksSent++ - - // Wait for the peer to request more chunks every `ibdBatchSize` chunks - if chunksSent%ibdBatchSize == 0 { - message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) - if err != nil { - return err - } - _, ok := message.(*appmessage.MsgRequestNextIBDRootUTXOSetChunk) - if !ok { - return protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdRequestNextIBDRootUTXOSetChunk, message.Command()) - } - } - } - - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneIBDRootUTXOSetChunks()) - if err != nil { - return err - } - - finishMeasuring() - } -} diff --git a/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go b/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go new file mode 100644 index 000000000..bb4bc1452 --- /dev/null +++ b/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go @@ -0,0 +1,143 @@ +package blockrelay + +import ( + "errors" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/common" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleRequestPruningPointUTXOSetAndBlockContext is the interface for the context needed for the HandleRequestPruningPointUTXOSetAndBlock flow. +type HandleRequestPruningPointUTXOSetAndBlockContext interface { + Domain() domain.Domain +} + +type handleRequestPruningPointUTXOSetAndBlockFlow struct { + HandleRequestPruningPointUTXOSetAndBlockContext + incomingRoute, outgoingRoute *router.Route +} + +// HandleRequestPruningPointUTXOSetAndBlock listens to appmessage.MsgRequestPruningPointUTXOSetAndBlock messages and sends +// the pruning point UTXO set and block body. +func HandleRequestPruningPointUTXOSetAndBlock(context HandleRequestPruningPointUTXOSetAndBlockContext, incomingRoute, + outgoingRoute *router.Route) error { + flow := &handleRequestPruningPointUTXOSetAndBlockFlow{ + HandleRequestPruningPointUTXOSetAndBlockContext: context, + incomingRoute: incomingRoute, + outgoingRoute: outgoingRoute, + } + + return flow.start() +} + +func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) start() error { + for { + msgRequestPruningPointUTXOSetAndBlock, err := flow.waitForRequestPruningPointUTXOSetAndBlockMessages() + if err != nil { + return err + } + + err = flow.handleRequestPruningPointUTXOSetAndBlockMessage(msgRequestPruningPointUTXOSetAndBlock) + if err != nil { + return err + } + } +} + +func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) handleRequestPruningPointUTXOSetAndBlockMessage( + msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error { + + onEnd := logger.LogAndMeasureExecutionTime(log, "handleRequestPruningPointUTXOSetAndBlockFlow") + defer onEnd() + + log.Debugf("Got request for PruningPointHash UTXOSet and Block") + + err := flow.sendPruningPointBlock(msgRequestPruningPointUTXOSetAndBlock) + if err != nil { + return err + } + + return flow.sendPruningPointUTXOSet(msgRequestPruningPointUTXOSetAndBlock) +} + +func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) waitForRequestPruningPointUTXOSetAndBlockMessages() ( + *appmessage.MsgRequestPruningPointUTXOSetAndBlock, error) { + + message, err := flow.incomingRoute.Dequeue() + if err != nil { + return nil, err + } + msgRequestPruningPointUTXOSetAndBlock, ok := message.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + if !ok { + return nil, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdRequestPruningPointUTXOSetAndBlock, message.Command()) + } + return msgRequestPruningPointUTXOSetAndBlock, nil +} + +func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) sendPruningPointBlock( + msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error { + + block, err := flow.Domain().Consensus().GetBlock(msgRequestPruningPointUTXOSetAndBlock.PruningPointHash) + if err != nil { + return err + } + log.Debugf("Retrieved pruning block %s", msgRequestPruningPointUTXOSetAndBlock.PruningPointHash) + + return flow.outgoingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(block))) +} + +func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) sendPruningPointUTXOSet( + msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error { + + // Send the UTXO set in `step`-sized chunks + const step = 1000 + offset := 0 + chunksSent := 0 + for { + pruningPointUTXOs, err := flow.Domain().Consensus().GetPruningPointUTXOs( + msgRequestPruningPointUTXOSetAndBlock.PruningPointHash, offset, step) + if err != nil { + if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) { + return flow.outgoingRoute.Enqueue(appmessage.NewMsgUnexpectedPruningPoint()) + } + } + + log.Debugf("Retrieved %d UTXOs for pruning block %s", + len(pruningPointUTXOs), msgRequestPruningPointUTXOSetAndBlock.PruningPointHash) + + outpointAndUTXOEntryPairs := + appmessage.DomainOutpointAndUTXOEntryPairsToOutpointAndUTXOEntryPairs(pruningPointUTXOs) + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgPruningPointUTXOSetChunk(outpointAndUTXOEntryPairs)) + if err != nil { + return err + } + + if len(pruningPointUTXOs) < step { + log.Debugf("Finished sending UTXOs for pruning block %s", + msgRequestPruningPointUTXOSetAndBlock.PruningPointHash) + + return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) + } + + offset += step + chunksSent++ + + // Wait for the peer to request more chunks every `ibdBatchSize` chunks + if chunksSent%ibdBatchSize == 0 { + message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout) + if err != nil { + return err + } + _, ok := message.(*appmessage.MsgRequestNextPruningPointUTXOSetChunk) + if !ok { + return protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdRequestNextPruningPointUTXOSetChunk, message.Command()) + } + } + } +} diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index d3ab5f9c5..75a36212f 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -1,6 +1,7 @@ package blockrelay import ( + "fmt" "github.com/kaspanet/kaspad/infrastructure/logger" "time" @@ -288,7 +289,7 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) { log.Debugf("Checking if a new pruning point is available") - err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootHashMessage()) + err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointHashMessage()) if err != nil { return false, err } @@ -296,36 +297,36 @@ func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) { if err != nil { return false, err } - msgIBDRootHash, ok := message.(*appmessage.MsgIBDRootHashMessage) + msgPruningPointHash, ok := message.(*appmessage.MsgPruningPointHashMessage) if !ok { return false, protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s, got: %s", appmessage.CmdIBDRootHash, message.Command()) + "expected: %s, got: %s", appmessage.CmdPruningPointHash, message.Command()) } - blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgIBDRootHash.Hash) + blockInfo, err := flow.Domain().Consensus().GetBlockInfo(msgPruningPointHash.Hash) if err != nil { return false, err } if blockInfo.BlockStatus != externalapi.StatusHeaderOnly { - log.Debugf("Already has the block data of the new suggested pruning point %s", msgIBDRootHash.Hash) + log.Debugf("Already has the block data of the new suggested pruning point %s", msgPruningPointHash.Hash) return true, nil } - log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", msgIBDRootHash.Hash) - isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgIBDRootHash.Hash) + log.Infof("Checking if the suggested pruning point %s is compatible to the node DAG", msgPruningPointHash.Hash) + isValid, err := flow.Domain().Consensus().IsValidPruningPoint(msgPruningPointHash.Hash) if err != nil { return false, err } if !isValid { log.Infof("The suggested pruning point %s is incompatible to this node DAG, so stopping IBD with this"+ - " peer", msgIBDRootHash.Hash) + " peer", msgPruningPointHash.Hash) return false, nil } log.Info("Fetching the pruning point UTXO set") - succeed, err := flow.fetchMissingUTXOSet(msgIBDRootHash.Hash) + succeed, err := flow.fetchMissingUTXOSet(msgPruningPointHash.Hash) if err != nil { return false, err } @@ -339,94 +340,118 @@ func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) { return true, nil } -func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (succeed bool, err error) { - err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash)) +func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(pruningPointHash *externalapi.DomainHash) (succeed bool, err error) { + defer func() { + err := flow.Domain().Consensus().ClearImportedPruningPointData() + if err != nil { + panic(fmt.Sprintf("failed to clear imported pruning point data: %s", err)) + } + }() + + err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestPruningPointUTXOSetAndBlock(pruningPointHash)) if err != nil { return false, err } - utxoSet, block, found, err := flow.receiveIBDRootUTXOSetAndBlock() + block, err := flow.receivePruningPointBlock() if err != nil { return false, err } - if !found { + receivedAll, err := flow.receiveAndInsertPruningPointUTXOSet(pruningPointHash) + if err != nil { + return false, err + } + if !receivedAll { return false, nil } - err = flow.Domain().Consensus().ValidateAndInsertPruningPoint(block, utxoSet) + err = flow.Domain().Consensus().ValidateAndInsertImportedPruningPoint(block) if err != nil { // TODO: Find a better way to deal with finality conflicts. if errors.Is(err, ruleerrors.ErrSuggestedPruningViolatesFinality) { return false, nil } - return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set") + return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with pruning point UTXO set") } return true, nil } -func (flow *handleRelayInvsFlow) receiveIBDRootUTXOSetAndBlock() ([]byte, *externalapi.DomainBlock, bool, error) { - onEnd := logger.LogAndMeasureExecutionTime(log, "receiveIBDRootUTXOSetAndBlock") +func (flow *handleRelayInvsFlow) receivePruningPointBlock() (*externalapi.DomainBlock, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "receivePruningPointBlock") defer onEnd() message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) if err != nil { - return nil, nil, false, err + return nil, err } - var block *externalapi.DomainBlock - switch message := message.(type) { - case *appmessage.MsgIBDBlock: - block = appmessage.MsgBlockToDomainBlock(message.MsgBlock) - case *appmessage.MsgIBDRootNotFound: - return nil, nil, false, nil - default: - return nil, nil, false, - protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s or %s, got: %s", - appmessage.CmdIBDBlock, appmessage.CmdIBDRootNotFound, message.Command(), - ) + ibdBlockMessage, ok := message.(*appmessage.MsgIBDBlock) + if !ok { + return nil, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s, got: %s", appmessage.CmdIBDBlock, message.Command()) } - log.Debugf("Received IBD root block %s", consensushashing.BlockHash(block)) + block := appmessage.MsgBlockToDomainBlock(ibdBlockMessage.MsgBlock) + + log.Debugf("Received pruning point block %s", consensushashing.BlockHash(block)) + + return block, nil +} + +func (flow *handleRelayInvsFlow) receiveAndInsertPruningPointUTXOSet( + pruningPointHash *externalapi.DomainHash) (bool, error) { + + onEnd := logger.LogAndMeasureExecutionTime(log, "receiveAndInsertPruningPointUTXOSet") + defer onEnd() - serializedUTXOSet := []byte{} - receivedAllChunks := false receivedChunkCount := 0 - for !receivedAllChunks { + receivedUTXOCount := 0 + for { message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) if err != nil { - return nil, nil, false, err + return false, err } switch message := message.(type) { - case *appmessage.MsgIBDRootUTXOSetChunk: - serializedUTXOSet = append(serializedUTXOSet, message.Chunk...) - case *appmessage.MsgDoneIBDRootUTXOSetChunks: - receivedAllChunks = true - default: - return nil, nil, false, - protocolerrors.Errorf(true, "received unexpected message type. "+ - "expected: %s or %s, got: %s", - appmessage.CmdIBDRootUTXOSetChunk, appmessage.CmdDoneIBDRootUTXOSetChunks, message.Command(), - ) - } + case *appmessage.MsgPruningPointUTXOSetChunk: + receivedUTXOCount += len(message.OutpointAndUTXOEntryPairs) + domainOutpointAndUTXOEntryPairs := + appmessage.OutpointAndUTXOEntryPairsToDomainOutpointAndUTXOEntryPairs(message.OutpointAndUTXOEntryPairs) - receivedChunkCount++ - if !receivedAllChunks && receivedChunkCount%ibdBatchSize == 0 { - log.Debugf("Received %d UTXO set chunks so far, totaling in %d bytes", - receivedChunkCount, len(serializedUTXOSet)) - - requestNextIBDRootUTXOSetChunkMessage := appmessage.NewMsgRequestNextIBDRootUTXOSetChunk() - err := flow.outgoingRoute.Enqueue(requestNextIBDRootUTXOSetChunkMessage) + err := flow.Domain().Consensus().AppendImportedPruningPointUTXOs(domainOutpointAndUTXOEntryPairs) if err != nil { - return nil, nil, false, err + return false, err } + + receivedChunkCount++ + if receivedChunkCount%ibdBatchSize == 0 { + log.Debugf("Received %d UTXO set chunks so far, totaling in %d UTXOs", + receivedChunkCount, receivedUTXOCount) + + requestNextPruningPointUTXOSetChunkMessage := appmessage.NewMsgRequestNextPruningPointUTXOSetChunk() + err := flow.outgoingRoute.Enqueue(requestNextPruningPointUTXOSetChunkMessage) + if err != nil { + return false, err + } + } + + case *appmessage.MsgDonePruningPointUTXOSetChunks: + log.Debugf("Finished receiving the UTXO set. Total UTXOs: %d", receivedUTXOCount) + return true, nil + + case *appmessage.MsgUnexpectedPruningPoint: + log.Debugf("Could not receive the next UTXO chunk because the pruning point %s "+ + "is no longer the pruning point of peer %s", pruningPointHash, flow.peer) + return false, nil + + default: + return false, protocolerrors.Errorf(true, "received unexpected message type. "+ + "expected: %s or %s or %s, got: %s", appmessage.CmdPruningPointUTXOSetChunk, + appmessage.CmdDonePruningPointUTXOSetChunks, appmessage.CmdUnexpectedPruningPoint, message.Command(), + ) } } - log.Debugf("Finished receiving the UTXO set. Total bytes: %d", len(serializedUTXOSet)) - - return serializedUTXOSet, block, true, nil } func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.DomainHash) error { diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 89601a087..2678aff5d 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -137,9 +137,9 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * return []*flow{ m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, - appmessage.CmdDoneHeaders, appmessage.CmdIBDRootNotFound, appmessage.CmdIBDRootUTXOSetChunk, - appmessage.CmdBlockHeaders, appmessage.CmdIBDRootHash, appmessage.CmdIBDBlockLocatorHighestHash, - appmessage.CmdDoneIBDRootUTXOSetChunks}, + appmessage.CmdDoneHeaders, appmessage.CmdUnexpectedPruningPoint, appmessage.CmdPruningPointUTXOSetChunk, + appmessage.CmdBlockHeaders, appmessage.CmdPruningPointHash, appmessage.CmdIBDBlockLocatorHighestHash, + appmessage.CmdDonePruningPointUTXOSetChunks}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) @@ -166,11 +166,11 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * }, ), - m.registerFlow("HandleRequestIBDRootUTXOSetAndBlock", router, - []appmessage.MessageCommand{appmessage.CmdRequestIBDRootUTXOSetAndBlock, - appmessage.CmdRequestNextIBDRootUTXOSetChunk}, isStopping, errChan, + m.registerFlow("HandleRequestPruningPointUTXOSetAndBlock", router, + []appmessage.MessageCommand{appmessage.CmdRequestPruningPointUTXOSetAndBlock, + appmessage.CmdRequestNextPruningPointUTXOSetChunk}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return blockrelay.HandleRequestIBDRootUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute) + return blockrelay.HandleRequestPruningPointUTXOSetAndBlock(m.context, incomingRoute, outgoingRoute) }, ), @@ -181,10 +181,10 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * }, ), - m.registerFlow("HandleIBDRootHashRequests", router, - []appmessage.MessageCommand{appmessage.CmdRequestIBDRootHash}, isStopping, errChan, + m.registerFlow("HandlePruningPointHashRequests", router, + []appmessage.MessageCommand{appmessage.CmdRequestPruningPointHash}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { - return blockrelay.HandleIBDRootHashRequests(m.context, incomingRoute, outgoingRoute) + return blockrelay.HandlePruningPointHashRequests(m.context, incomingRoute, outgoingRoute) }, ), diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index fbd50e501..d66b71be1 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -199,7 +199,9 @@ func (s *consensus) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) return s.syncManager.GetMissingBlockBodyHashes(highHash) } -func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi.DomainHash) ([]byte, error) { +func (s *consensus) GetPruningPointUTXOs(expectedPruningPointHash *externalapi.DomainHash, + offset int, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { + s.lock.Lock() defer s.lock.Unlock() @@ -214,11 +216,11 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi pruningPointHash) } - serializedUTXOSet, err := s.pruningStore.PruningPointSerializedUTXOSet(s.databaseContext) + pruningPointUTXOs, err := s.pruningStore.PruningPointUTXOs(s.databaseContext, offset, limit) if err != nil { return nil, err } - return serializedUTXOSet, nil + return pruningPointUTXOs, nil } func (s *consensus) PruningPoint() (*externalapi.DomainHash, error) { @@ -228,11 +230,25 @@ func (s *consensus) PruningPoint() (*externalapi.DomainHash, error) { return s.pruningStore.PruningPoint(s.databaseContext) } -func (s *consensus) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { +func (s *consensus) ClearImportedPruningPointData() error { s.lock.Lock() defer s.lock.Unlock() - return s.blockProcessor.ValidateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet) + return s.pruningManager.ClearImportedPruningPointData() +} + +func (s *consensus) AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error { + s.lock.Lock() + defer s.lock.Unlock() + + return s.pruningManager.AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs) +} + +func (s *consensus) ValidateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error { + s.lock.Lock() + defer s.lock.Unlock() + + return s.blockProcessor.ValidateAndInsertImportedPruningPoint(newPruningPoint) } func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainHash, error) { diff --git a/domain/consensus/database/dbmanager.go b/domain/consensus/database/dbmanager.go index 3474bcaf4..273b540a9 100644 --- a/domain/consensus/database/dbmanager.go +++ b/domain/consensus/database/dbmanager.go @@ -17,6 +17,14 @@ func (dbw *dbManager) Has(key model.DBKey) (bool, error) { return dbw.db.Has(dbKeyToDatabaseKey(key)) } +func (dbw *dbManager) Put(key model.DBKey, value []byte) error { + return dbw.db.Put(dbKeyToDatabaseKey(key), value) +} + +func (dbw *dbManager) Delete(key model.DBKey) error { + return dbw.db.Delete(dbKeyToDatabaseKey(key)) +} + func (dbw *dbManager) Cursor(bucket model.DBBucket) (model.DBCursor, error) { cursor, err := dbw.db.Cursor(dbBucketToDatabaseBucket(bucket)) if err != nil { diff --git a/domain/consensus/database/serialization/utxo_collection.go b/domain/consensus/database/serialization/utxo_collection.go index 71a272d9b..3021f71c8 100644 --- a/domain/consensus/database/serialization/utxo_collection.go +++ b/domain/consensus/database/serialization/utxo_collection.go @@ -10,7 +10,7 @@ func utxoCollectionToDBUTXOCollection(utxoCollection model.UTXOCollection) ([]*D items := make([]*DbUtxoCollectionItem, utxoCollection.Len()) i := 0 utxoIterator := utxoCollection.Iterator() - for utxoIterator.Next() { + for ok := utxoIterator.First(); ok; ok = utxoIterator.Next() { outpoint, entry, err := utxoIterator.Get() if err != nil { return nil, err diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go index cc2d14b82..424906873 100644 --- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go +++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go @@ -11,7 +11,6 @@ type consensusStateStore struct { tipsStaging []*externalapi.DomainHash virtualDiffParentsStaging []*externalapi.DomainHash virtualUTXODiffStaging model.UTXODiff - virtualUTXOSetStaging model.UTXOCollection virtualUTXOSetCache *utxolrucache.LRUCache @@ -30,7 +29,6 @@ func (css *consensusStateStore) Discard() { css.tipsStaging = nil css.virtualUTXODiffStaging = nil css.virtualDiffParentsStaging = nil - css.virtualUTXOSetStaging = nil } func (css *consensusStateStore) Commit(dbTx model.DBTransaction) error { @@ -48,11 +46,6 @@ func (css *consensusStateStore) Commit(dbTx model.DBTransaction) error { return err } - err = css.commitVirtualUTXOSet(dbTx) - if err != nil { - return err - } - css.Discard() return nil diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index f25de5fd5..15ee75756 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -19,22 +19,25 @@ func utxoKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) { return utxoSetBucket.Key(serializedOutpoint), nil } -func (css *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff model.UTXODiff) error { - if css.virtualUTXOSetStaging != nil { - return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged") - } - +func (css *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff model.UTXODiff) { css.virtualUTXODiffStaging = virtualUTXODiff - return nil } func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error { + hadStartedImportingPruningPointUTXOSet, err := css.HadStartedImportingPruningPointUTXOSet(dbTx) + if err != nil { + return err + } + if hadStartedImportingPruningPointUTXOSet { + return errors.New("cannot commit virtual UTXO diff after starting to import the pruning point UTXO set") + } + if css.virtualUTXODiffStaging == nil { return nil } toRemoveIterator := css.virtualUTXODiffStaging.ToRemove().Iterator() - for toRemoveIterator.Next() { + for ok := toRemoveIterator.First(); ok; ok = toRemoveIterator.Next() { toRemoveOutpoint, _, err := toRemoveIterator.Get() if err != nil { return err @@ -53,7 +56,7 @@ func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) } toAddIterator := css.virtualUTXODiffStaging.ToAdd().Iterator() - for toAddIterator.Next() { + for ok := toAddIterator.First(); ok; ok = toAddIterator.Next() { toAddOutpoint, toAddEntry, err := toAddIterator.Get() if err != nil { return err @@ -80,63 +83,9 @@ func (css *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) return nil } -func (css *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error { - if css.virtualUTXOSetStaging == nil { - return nil - } - - // Clear the existing virtual utxo set in database before adding the new one - cursor, err := dbTx.Cursor(utxoSetBucket) - if err != nil { - return err - } - for cursor.Next() { - key, err := cursor.Key() - if err != nil { - return err - } - err = dbTx.Delete(key) - if err != nil { - return err - } - } - - // Now put the new virtualUTXOSet into the database - css.virtualUTXOSetCache.Clear() - iterator := css.virtualUTXOSetStaging.Iterator() - for iterator.Next() { - outpoint, utxoEntry, err := iterator.Get() - if err != nil { - return err - } - - css.virtualUTXOSetCache.Add(outpoint, utxoEntry) - dbKey, err := utxoKey(outpoint) - if err != nil { - return err - } - serializedEntry, err := serializeUTXOEntry(utxoEntry) - if err != nil { - return err - } - err = dbTx.Put(dbKey, serializedEntry) - if err != nil { - return err - } - } - - // Note: we don't discard the staging here since that's - // being done at the end of Commit() - return nil -} - func (css *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( externalapi.UTXOEntry, error) { - if css.virtualUTXOSetStaging != nil { - return css.utxoByOutpointFromStagedVirtualUTXOSet(outpoint) - } - return css.utxoByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) } @@ -176,20 +125,7 @@ func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContex return entry, nil } -func (css *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( - externalapi.UTXOEntry, error) { - if utxoEntry, ok := css.virtualUTXOSetStaging.Get(outpoint); ok { - return utxoEntry, nil - } - - return nil, errors.Errorf("outpoint was not found") -} - func (css *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { - if css.virtualUTXOSetStaging != nil { - return css.hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint), nil - } - return css.hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) } @@ -213,10 +149,6 @@ func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbCon return dbContext.Has(key) } -func (css *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool { - return css.virtualUTXOSetStaging.Contains(outpoint) -} - func (css *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { cursor, err := dbContext.Cursor(utxoSetBucket) if err != nil { @@ -239,6 +171,10 @@ func newCursorUTXOSetIterator(cursor model.DBCursor) model.ReadOnlyUTXOSetIterat return &utxoSetIterator{cursor: cursor} } +func (u utxoSetIterator) First() bool { + return u.cursor.First() +} + func (u utxoSetIterator) Next() bool { return u.cursor.Next() } @@ -266,25 +202,3 @@ func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry return outpoint, utxoEntry, nil } - -func (css *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error { - if css.virtualUTXODiffStaging != nil { - return errors.New("cannot stage virtual UTXO set while virtual UTXO diff is staged") - } - - utxoMap := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry) - for virtualUTXOSetIterator.Next() { - outpoint, entry, err := virtualUTXOSetIterator.Get() - if err != nil { - return err - } - - if _, exists := utxoMap[*outpoint]; exists { - return errors.Errorf("outpoint %s is found more than once in the given iterator", outpoint) - } - utxoMap[*outpoint] = entry - } - css.virtualUTXOSetStaging = utxo.NewUTXOCollection(utxoMap) - - return nil -} diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_utxo_set.go b/domain/consensus/datastructures/consensusstatestore/virtual_utxo_set.go new file mode 100644 index 000000000..515530f50 --- /dev/null +++ b/domain/consensus/datastructures/consensusstatestore/virtual_utxo_set.go @@ -0,0 +1,81 @@ +package consensusstatestore + +import ( + "github.com/kaspanet/kaspad/domain/consensus/database" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/pkg/errors" +) + +var importingPruningPointUTXOSetKey = database.MakeBucket(nil).Key([]byte("importing-pruning-point-utxo-set")) + +func (css *consensusStateStore) StartImportingPruningPointUTXOSet(dbContext model.DBWriter) error { + return dbContext.Put(importingPruningPointUTXOSetKey, []byte{0}) +} + +func (css *consensusStateStore) HadStartedImportingPruningPointUTXOSet(dbContext model.DBWriter) (bool, error) { + return dbContext.Has(importingPruningPointUTXOSetKey) +} + +func (css *consensusStateStore) FinishImportingPruningPointUTXOSet(dbContext model.DBWriter) error { + return dbContext.Delete(importingPruningPointUTXOSetKey) +} + +func (css *consensusStateStore) ImportPruningPointUTXOSetIntoVirtualUTXOSet(dbContext model.DBWriter, + pruningPointUTXOSetIterator model.ReadOnlyUTXOSetIterator) error { + + if css.virtualUTXODiffStaging != nil { + return errors.New("cannot import virtual UTXO set while virtual UTXO diff is staged") + } + + hadStartedImportingPruningPointUTXOSet, err := css.HadStartedImportingPruningPointUTXOSet(dbContext) + if err != nil { + return err + } + if !hadStartedImportingPruningPointUTXOSet { + return errors.New("cannot import pruning point UTXO set " + + "without calling StartImportingPruningPointUTXOSet first") + } + + // Clear the cache + css.virtualUTXOSetCache.Clear() + + // Delete all the old UTXOs from the database + deleteCursor, err := dbContext.Cursor(utxoSetBucket) + if err != nil { + return err + } + for ok := deleteCursor.First(); ok; ok = deleteCursor.Next() { + key, err := deleteCursor.Key() + if err != nil { + return err + } + err = dbContext.Delete(key) + if err != nil { + return err + } + } + + // Insert all the new UTXOs into the database + for ok := pruningPointUTXOSetIterator.First(); ok; ok = pruningPointUTXOSetIterator.Next() { + outpoint, entry, err := pruningPointUTXOSetIterator.Get() + if err != nil { + return err + } + + key, err := utxoKey(outpoint) + if err != nil { + return err + } + serializedUTXOEntry, err := serializeUTXOEntry(entry) + if err != nil { + return err + } + + err = dbContext.Put(key, serializedUTXOEntry) + if err != nil { + return err + } + } + + return nil +} diff --git a/domain/consensus/datastructures/pruningstore/imported_pruning_point.go b/domain/consensus/datastructures/pruningstore/imported_pruning_point.go new file mode 100644 index 000000000..52d3daa8c --- /dev/null +++ b/domain/consensus/datastructures/pruningstore/imported_pruning_point.go @@ -0,0 +1,213 @@ +package pruningstore + +import ( + "github.com/golang/protobuf/proto" + "github.com/kaspanet/kaspad/domain/consensus/database" + "github.com/kaspanet/kaspad/domain/consensus/database/serialization" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) + +var importedPruningPointUTXOsBucket = database.MakeBucket([]byte("imported-pruning-point-utxos")) +var importedPruningPointMultiset = database.MakeBucket(nil).Key([]byte("imported-pruning-point-multiset")) + +func (ps *pruningStore) ClearImportedPruningPointUTXOs(dbContext model.DBWriter) error { + cursor, err := dbContext.Cursor(importedPruningPointUTXOsBucket) + if err != nil { + return err + } + + for ok := cursor.First(); ok; ok = cursor.Next() { + key, err := cursor.Key() + if err != nil { + return err + } + err = dbContext.Delete(key) + if err != nil { + return err + } + } + return nil +} + +func (ps *pruningStore) AppendImportedPruningPointUTXOs(dbTx model.DBTransaction, + outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error { + + for _, outpointAndUTXOEntryPair := range outpointAndUTXOEntryPairs { + key, err := ps.importedPruningPointUTXOKey(outpointAndUTXOEntryPair.Outpoint) + if err != nil { + return err + } + serializedUTXOEntry, err := serializeUTXOEntry(outpointAndUTXOEntryPair.UTXOEntry) + if err != nil { + return err + } + err = dbTx.Put(key, serializedUTXOEntry) + if err != nil { + return err + } + } + + return nil +} + +func (ps *pruningStore) ImportedPruningPointUTXOIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { + cursor, err := dbContext.Cursor(importedPruningPointUTXOsBucket) + if err != nil { + return nil, err + } + return ps.newCursorUTXOSetIterator(cursor), nil +} + +type utxoSetIterator struct { + cursor model.DBCursor +} + +func (ps *pruningStore) newCursorUTXOSetIterator(cursor model.DBCursor) model.ReadOnlyUTXOSetIterator { + return &utxoSetIterator{cursor: cursor} +} + +func (u *utxoSetIterator) First() bool { + return u.cursor.First() +} + +func (u *utxoSetIterator) Next() bool { + return u.cursor.Next() +} + +func (u *utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) { + key, err := u.cursor.Key() + if err != nil { + panic(err) + } + + utxoEntryBytes, err := u.cursor.Value() + if err != nil { + return nil, nil, err + } + + outpoint, err = deserializeOutpoint(key.Suffix()) + if err != nil { + return nil, nil, err + } + + utxoEntry, err = deserializeUTXOEntry(utxoEntryBytes) + if err != nil { + return nil, nil, err + } + + return outpoint, utxoEntry, nil +} + +func (ps *pruningStore) importedPruningPointUTXOKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) { + serializedOutpoint, err := serializeOutpoint(outpoint) + if err != nil { + return nil, err + } + + return importedPruningPointUTXOsBucket.Key(serializedOutpoint), nil +} + +func serializeOutpoint(outpoint *externalapi.DomainOutpoint) ([]byte, error) { + return proto.Marshal(serialization.DomainOutpointToDbOutpoint(outpoint)) +} + +func serializeUTXOEntry(entry externalapi.UTXOEntry) ([]byte, error) { + return proto.Marshal(serialization.UTXOEntryToDBUTXOEntry(entry)) +} + +func deserializeOutpoint(outpointBytes []byte) (*externalapi.DomainOutpoint, error) { + dbOutpoint := &serialization.DbOutpoint{} + err := proto.Unmarshal(outpointBytes, dbOutpoint) + if err != nil { + return nil, err + } + + return serialization.DbOutpointToDomainOutpoint(dbOutpoint) +} + +func deserializeUTXOEntry(entryBytes []byte) (externalapi.UTXOEntry, error) { + dbEntry := &serialization.DbUtxoEntry{} + err := proto.Unmarshal(entryBytes, dbEntry) + if err != nil { + return nil, err + } + return serialization.DBUTXOEntryToUTXOEntry(dbEntry) +} + +func (ps *pruningStore) ClearImportedPruningPointMultiset(dbContext model.DBWriter) error { + return dbContext.Delete(importedPruningPointMultiset) +} + +func (ps *pruningStore) ImportedPruningPointMultiset(dbContext model.DBReader) (model.Multiset, error) { + multisetBytes, err := dbContext.Get(importedPruningPointMultiset) + if err != nil { + return nil, err + } + return ps.deserializeMultiset(multisetBytes) +} + +func (ps *pruningStore) UpdateImportedPruningPointMultiset(dbTx model.DBTransaction, multiset model.Multiset) error { + multisetBytes, err := ps.serializeMultiset(multiset) + if err != nil { + return err + } + return dbTx.Put(importedPruningPointMultiset, multisetBytes) +} + +func (ps *pruningStore) serializeMultiset(multiset model.Multiset) ([]byte, error) { + return proto.Marshal(serialization.MultisetToDBMultiset(multiset)) +} + +func (ps *pruningStore) deserializeMultiset(multisetBytes []byte) (model.Multiset, error) { + dbMultiset := &serialization.DbMultiset{} + err := proto.Unmarshal(multisetBytes, dbMultiset) + if err != nil { + return nil, err + } + + return serialization.DBMultisetToMultiset(dbMultiset) +} + +func (ps *pruningStore) CommitImportedPruningPointUTXOSet(dbContext model.DBWriter) error { + // Delete all the old UTXOs from the database + deleteCursor, err := dbContext.Cursor(pruningPointUTXOSetBucket) + if err != nil { + return err + } + for ok := deleteCursor.First(); ok; ok = deleteCursor.Next() { + key, err := deleteCursor.Key() + if err != nil { + return err + } + err = dbContext.Delete(key) + if err != nil { + return err + } + } + + // Insert all the new UTXOs into the database + insertCursor, err := dbContext.Cursor(importedPruningPointUTXOsBucket) + if err != nil { + return err + } + for ok := insertCursor.First(); ok; ok = insertCursor.Next() { + importedPruningPointUTXOSetKey, err := insertCursor.Key() + if err != nil { + return err + } + pruningPointUTXOSetKey := pruningPointUTXOSetBucket.Key(importedPruningPointUTXOSetKey.Suffix()) + + serializedUTXOEntry, err := insertCursor.Value() + if err != nil { + return err + } + + err = dbContext.Put(pruningPointUTXOSetKey, serializedUTXOEntry) + if err != nil { + return err + } + } + + return nil +} diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index 31eefdc9a..aa0e1367f 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -10,15 +10,21 @@ import ( var pruningBlockHashKey = database.MakeBucket(nil).Key([]byte("pruning-block-hash")) var candidatePruningPointHashKey = database.MakeBucket(nil).Key([]byte("candidate-pruning-point-hash")) -var pruningSerializedUTXOSetKey = database.MakeBucket(nil).Key([]byte("pruning-utxo-set")) +var pruningPointUTXOSetBucket = database.MakeBucket([]byte("pruning-point-utxo-set")) // pruningStore represents a store for the current pruning state type pruningStore struct { pruningPointStaging *externalapi.DomainHash - pruningPointCandidateStaging *externalapi.DomainHash - serializedUTXOSetStaging []byte - pruningPointCandidateCache *externalapi.DomainHash pruningPointCache *externalapi.DomainHash + pruningPointCandidateStaging *externalapi.DomainHash + pruningPointCandidateCache *externalapi.DomainHash + + pruningPointUTXOSetStaging model.ReadOnlyUTXOSetIterator +} + +// New instantiates a new PruningStore +func New() model.PruningStore { + return &pruningStore{} } func (ps *pruningStore) StagePruningPointCandidate(candidate *externalapi.DomainHash) { @@ -59,24 +65,22 @@ func (ps *pruningStore) HasPruningPointCandidate(dbContext model.DBReader) (bool return dbContext.Has(candidatePruningPointHashKey) } -// New instantiates a new PruningStore -func New() model.PruningStore { - return &pruningStore{} +// Stage stages the pruning state +func (ps *pruningStore) StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash) { + ps.pruningPointStaging = pruningPointBlockHash } -// Stage stages the pruning state -func (ps *pruningStore) StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) { - ps.pruningPointStaging = pruningPointBlockHash - ps.serializedUTXOSetStaging = pruningPointUTXOSetBytes +func (ps *pruningStore) StagePruningPointUTXOSet(pruningPointUTXOSetIterator model.ReadOnlyUTXOSetIterator) { + ps.pruningPointUTXOSetStaging = pruningPointUTXOSetIterator } func (ps *pruningStore) IsStaged() bool { - return ps.pruningPointStaging != nil || ps.serializedUTXOSetStaging != nil + return ps.pruningPointStaging != nil || ps.pruningPointUTXOSetStaging != nil } func (ps *pruningStore) Discard() { ps.pruningPointStaging = nil - ps.serializedUTXOSetStaging = nil + ps.pruningPointUTXOSetStaging = nil } func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { @@ -104,14 +108,42 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { ps.pruningPointCandidateCache = ps.pruningPointCandidateStaging } - if ps.serializedUTXOSetStaging != nil { - utxoSetBytes, err := ps.serializeUTXOSetBytes(ps.serializedUTXOSetStaging) + if ps.pruningPointUTXOSetStaging != nil { + // Delete all the old UTXOs from the database + deleteCursor, err := dbTx.Cursor(pruningPointUTXOSetBucket) if err != nil { return err } - err = dbTx.Put(pruningSerializedUTXOSetKey, utxoSetBytes) - if err != nil { - return err + for ok := deleteCursor.First(); ok; ok = deleteCursor.Next() { + key, err := deleteCursor.Key() + if err != nil { + return err + } + err = dbTx.Delete(key) + if err != nil { + return err + } + } + + // Insert all the new UTXOs into the database + for ok := ps.pruningPointUTXOSetStaging.First(); ok; ok = ps.pruningPointUTXOSetStaging.Next() { + outpoint, entry, err := ps.pruningPointUTXOSetStaging.Get() + if err != nil { + return err + } + serializedOutpoint, err := serializeOutpoint(outpoint) + if err != nil { + return err + } + key := pruningPointUTXOSetBucket.Key(serializedOutpoint) + serializedUTXOEntry, err := serializeUTXOEntry(entry) + if err != nil { + return err + } + err = dbTx.Put(key, serializedUTXOEntry) + if err != nil { + return err + } } } @@ -142,24 +174,6 @@ func (ps *pruningStore) PruningPoint(dbContext model.DBReader) (*externalapi.Dom return pruningPoint, nil } -// PruningPointSerializedUTXOSet returns the serialized UTXO set of the current pruning point -func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader) ([]byte, error) { - if ps.serializedUTXOSetStaging != nil { - return ps.serializedUTXOSetStaging, nil - } - - dbPruningPointUTXOSetBytes, err := dbContext.Get(pruningSerializedUTXOSetKey) - if err != nil { - return nil, err - } - - pruningPointUTXOSet, err := ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes) - if err != nil { - return nil, err - } - return pruningPointUTXOSet, nil -} - func (ps *pruningStore) serializeHash(hash *externalapi.DomainHash) ([]byte, error) { return proto.Marshal(serialization.DomainHashToDbHash(hash)) } @@ -199,3 +213,31 @@ func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader) (bool, error) return dbContext.Has(pruningBlockHashKey) } + +func (ps *pruningStore) PruningPointUTXOs(dbContext model.DBReader, + offset int, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { + + cursor, err := dbContext.Cursor(pruningPointUTXOSetBucket) + if err != nil { + return nil, err + } + pruningPointUTXOIterator := ps.newCursorUTXOSetIterator(cursor) + + offsetIndex := 0 + for offsetIndex < offset && pruningPointUTXOIterator.Next() { + offsetIndex++ + } + + outpointAndUTXOEntryPairs := make([]*externalapi.OutpointAndUTXOEntryPair, 0, limit) + for len(outpointAndUTXOEntryPairs) < limit && pruningPointUTXOIterator.Next() { + outpoint, utxoEntry, err := pruningPointUTXOIterator.Get() + if err != nil { + return nil, err + } + outpointAndUTXOEntryPairs = append(outpointAndUTXOEntryPairs, &externalapi.OutpointAndUTXOEntryPair{ + Outpoint: outpoint, + UTXOEntry: utxoEntry, + }) + } + return outpointAndUTXOEntryPairs, nil +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index b9da722ee..993464989 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -357,6 +357,15 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat } } + err = consensusStateManager.RecoverUTXOIfRequired() + if err != nil { + return nil, err + } + err = pruningManager.ClearImportedPruningPointData() + if err != nil { + return nil, err + } + return c, nil } diff --git a/domain/consensus/model/database.go b/domain/consensus/model/database.go index 7133d99e2..7911de922 100644 --- a/domain/consensus/model/database.go +++ b/domain/consensus/model/database.go @@ -45,6 +45,8 @@ type DBReader interface { // DBWriter is an interface to write to the database type DBWriter interface { + DBReader + // Put sets the value for the given key. It overwrites // any previous value for that key. Put(key DBKey, value []byte) error @@ -58,7 +60,6 @@ type DBWriter interface { // access that requires an open database transaction type DBTransaction interface { DBWriter - DBReader // Rollback rolls back whatever changes were made to the // database within this transaction. @@ -77,7 +78,7 @@ type DBTransaction interface { // DBManager defines the interface of a database that can begin // transactions and read data. type DBManager interface { - DBReader + DBWriter // Begin begins a new database transaction. Begin() (DBTransaction, error) diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index b4696a7d8..e832d6aff 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -13,9 +13,11 @@ type Consensus interface { GetHashesBetween(lowHash, highHash *DomainHash, maxBlueScoreDifference uint64) ([]*DomainHash, error) GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) - GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error) + GetPruningPointUTXOs(expectedPruningPointHash *DomainHash, offset int, limit int) ([]*OutpointAndUTXOEntryPair, error) PruningPoint() (*DomainHash, error) - ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error + ClearImportedPruningPointData() error + AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*OutpointAndUTXOEntryPair) error + ValidateAndInsertImportedPruningPoint(newPruningPoint *DomainBlock) error GetVirtualSelectedParent() (*DomainHash, error) CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error) diff --git a/domain/consensus/model/externalapi/utxoentry.go b/domain/consensus/model/externalapi/utxoentry.go index d3a83843e..bc76e03be 100644 --- a/domain/consensus/model/externalapi/utxoentry.go +++ b/domain/consensus/model/externalapi/utxoentry.go @@ -11,3 +11,10 @@ type UTXOEntry interface { IsCoinbase() bool Equal(other UTXOEntry) bool } + +// OutpointAndUTXOEntryPair is an outpoint along with its +// respective UTXO entry +type OutpointAndUTXOEntryPair struct { + Outpoint *DomainOutpoint + UTXOEntry UTXOEntry +} diff --git a/domain/consensus/model/interface_datastructures_consensusstatestore.go b/domain/consensus/model/interface_datastructures_consensusstatestore.go index df8fd2153..86b9e1b93 100644 --- a/domain/consensus/model/interface_datastructures_consensusstatestore.go +++ b/domain/consensus/model/interface_datastructures_consensusstatestore.go @@ -7,8 +7,7 @@ type ConsensusStateStore interface { Store IsStaged() bool - StageVirtualUTXODiff(virtualUTXODiff UTXODiff) error - StageVirtualUTXOSet(virtualUTXOSetIterator ReadOnlyUTXOSetIterator) error + StageVirtualUTXODiff(virtualUTXODiff UTXODiff) UTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (externalapi.UTXOEntry, error) HasUTXOByOutpoint(dbContext DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) VirtualUTXOSetIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error) @@ -18,4 +17,9 @@ type ConsensusStateStore interface { StageTips(tipHashes []*externalapi.DomainHash) Tips(dbContext DBReader) ([]*externalapi.DomainHash, error) + + StartImportingPruningPointUTXOSet(dbContext DBWriter) error + HadStartedImportingPruningPointUTXOSet(dbContext DBWriter) (bool, error) + ImportPruningPointUTXOSetIntoVirtualUTXOSet(dbContext DBWriter, pruningPointUTXOSetIterator ReadOnlyUTXOSetIterator) error + FinishImportingPruningPointUTXOSet(dbContext DBWriter) error } diff --git a/domain/consensus/model/interface_datastructures_pruningstore.go b/domain/consensus/model/interface_datastructures_pruningstore.go index da8c47fdf..e8149e975 100644 --- a/domain/consensus/model/interface_datastructures_pruningstore.go +++ b/domain/consensus/model/interface_datastructures_pruningstore.go @@ -5,12 +5,20 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // PruningStore represents a store for the current pruning state type PruningStore interface { Store - StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash, pruningPointUTXOSetBytes []byte) + StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash) + StagePruningPointUTXOSet(pruningPointUTXOSetIterator ReadOnlyUTXOSetIterator) StagePruningPointCandidate(candidate *externalapi.DomainHash) IsStaged() bool PruningPointCandidate(dbContext DBReader) (*externalapi.DomainHash, error) HasPruningPointCandidate(dbContext DBReader) (bool, error) PruningPoint(dbContext DBReader) (*externalapi.DomainHash, error) HasPruningPoint(dbContext DBReader) (bool, error) - PruningPointSerializedUTXOSet(dbContext DBReader) ([]byte, error) + ClearImportedPruningPointUTXOs(dbContext DBWriter) error + AppendImportedPruningPointUTXOs(dbTx DBTransaction, outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error + ImportedPruningPointUTXOIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error) + ClearImportedPruningPointMultiset(dbContext DBWriter) error + ImportedPruningPointMultiset(dbContext DBReader) (Multiset, error) + UpdateImportedPruningPointMultiset(dbTx DBTransaction, multiset Multiset) error + CommitImportedPruningPointUTXOSet(dbContext DBWriter) error + PruningPointUTXOs(dbContext DBReader, offset int, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) } diff --git a/domain/consensus/model/interface_processes_blockprocessor.go b/domain/consensus/model/interface_processes_blockprocessor.go index 49752a513..22dc92f85 100644 --- a/domain/consensus/model/interface_processes_blockprocessor.go +++ b/domain/consensus/model/interface_processes_blockprocessor.go @@ -5,5 +5,5 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockProcessor is responsible for processing incoming blocks type BlockProcessor interface { ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) - ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error + ValidateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error } diff --git a/domain/consensus/model/interface_processes_consensusstatemanager.go b/domain/consensus/model/interface_processes_consensusstatemanager.go index d9a74b1ee..f24623c4a 100644 --- a/domain/consensus/model/interface_processes_consensusstatemanager.go +++ b/domain/consensus/model/interface_processes_consensusstatemanager.go @@ -6,8 +6,9 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type ConsensusStateManager interface { AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error - UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error + ImportPruningPoint(newPruningPoint *externalapi.DomainBlock) error RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, externalapi.AcceptanceData, Multiset, error) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) + RecoverUTXOIfRequired() error } diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index de060f3fa..effefcbfe 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -6,4 +6,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type PruningManager interface { UpdatePruningPointByVirtual() error IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) + ClearImportedPruningPointData() error + AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error } diff --git a/domain/consensus/model/readonlyutxoset.go b/domain/consensus/model/readonlyutxoset.go index 17f8c293e..c1033fd81 100644 --- a/domain/consensus/model/readonlyutxoset.go +++ b/domain/consensus/model/readonlyutxoset.go @@ -11,6 +11,7 @@ type ReadOnlyUTXOSet interface { // ReadOnlyUTXOSetIterator is an iterator over all entries in a // ReadOnlyUTXOSet type ReadOnlyUTXOSetIterator interface { + First() bool Next() bool Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) } diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index 4d6985c8b..100874ce3 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -137,9 +137,9 @@ func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) return bp.validateAndInsertBlock(block, false) } -func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { - onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertPruningPoint") +func (bp *blockProcessor) ValidateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertImportedPruningPoint") defer onEnd() - return bp.validateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet) + return bp.validateAndInsertImportedPruningPoint(newPruningPoint) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 6c49db0a5..7b232e43b 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -87,7 +87,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, if !isHeaderOnlyBlock { // There's no need to update the consensus state manager when // processing the pruning point since it was already handled - // in consensusStateManager.UpdatePruningPoint + // in consensusStateManager.ImportPruningPoint if !isPruningPoint { // Attempt to add the block to the virtual selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go similarity index 88% rename from domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go rename to domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go index b09e1ea81..0b5cddf70 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go @@ -7,7 +7,7 @@ import ( "github.com/pkg/errors" ) -func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { +func (bp *blockProcessor) validateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error { log.Info("Checking that the given pruning point is the expected pruning point") newPruningPointHash := consensushashing.BlockHash(newPruningPoint) @@ -29,7 +29,7 @@ func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externa } log.Infof("Updating consensus state manager according to the new pruning point %s", newPruningPointHash) - err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet) + err = bp.consensusStateManager.ImportPruningPoint(newPruningPoint) if err != nil { return err } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go similarity index 79% rename from domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go rename to domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go index 059112dde..70fade737 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertpruningpoint_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go @@ -1,9 +1,6 @@ package blockprocessor_test import ( - "testing" - "time" - "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" @@ -11,10 +8,10 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" - "google.golang.org/protobuf/proto" + "testing" + "time" ) func addBlock(tcSyncer, tcSyncee testapi.TestConsensus, parentHashes []*externalapi.DomainHash, t *testing.T) *externalapi.DomainHash { @@ -39,7 +36,7 @@ func addBlock(tcSyncer, tcSyncee testapi.TestConsensus, parentHashes []*external return consensushashing.BlockHash(block) } -func TestValidateAndInsertPruningPoint(t *testing.T) { +func TestValidateAndInsertImportedPruningPoint(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { // This is done to reduce the pruning depth to 6 blocks finalityDepth := 3 @@ -95,9 +92,13 @@ func TestValidateAndInsertPruningPoint(t *testing.T) { t.Fatalf("Unexpected pruning point %s", pruningPoint) } - pruningPointUTXOSet, err := tcSyncer.GetPruningPointUTXOSet(pruningPoint) + pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, 0, 1000) if err != nil { - t.Fatalf("GetPruningPointUTXOSet: %+v", err) + t.Fatalf("GetPruningPointUTXOs: %+v", err) + } + err = tcSyncee.AppendImportedPruningPointUTXOs(pruningPointUTXOs) + if err != nil { + t.Fatalf("AppendImportedPruningPointUTXOs: %+v", err) } tip, err := tcSyncer.GetBlock(tipHash) @@ -105,8 +106,8 @@ func TestValidateAndInsertPruningPoint(t *testing.T) { t.Fatalf("GetBlock: %+v", err) } - // Check that ValidateAndInsertPruningPoint fails for invalid pruning point - err = tcSyncee.ValidateAndInsertPruningPoint(tip, pruningPointUTXOSet) + // Check that ValidateAndInsertImportedPruningPoint fails for invalid pruning point + err = tcSyncee.ValidateAndInsertImportedPruningPoint(tip) if !errors.Is(err, ruleerrors.ErrUnexpectedPruningPoint) { t.Fatalf("Unexpected error: %+v", err) } @@ -119,27 +120,40 @@ func TestValidateAndInsertPruningPoint(t *testing.T) { invalidPruningPointBlock := pruningPointBlock.Clone() invalidPruningPointBlock.Transactions[0].Version += 1 - // Check that ValidateAndInsertPruningPoint fails for invalid block - err = tcSyncee.ValidateAndInsertPruningPoint(invalidPruningPointBlock, pruningPointUTXOSet) + // Check that ValidateAndInsertImportedPruningPoint fails for invalid block + err = tcSyncee.ValidateAndInsertImportedPruningPoint(invalidPruningPointBlock) if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) { t.Fatalf("Unexpected error: %+v", err) } - serializedFakeUTXOSet, err := makeSerializedFakeUTXOSet() + err = tcSyncee.ClearImportedPruningPointData() if err != nil { - t.Fatalf("makeSerializedFakeUTXOSet: %+v", err) + t.Fatalf("ClearImportedPruningPointData: %+v", err) + } + err = tcSyncee.AppendImportedPruningPointUTXOs(makeFakeUTXOs()) + if err != nil { + t.Fatalf("AppendImportedPruningPointUTXOs: %+v", err) } - // Check that ValidateAndInsertPruningPoint fails if the UTXO commitment doesn't fit the provided UTXO set. - err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, serializedFakeUTXOSet) + // Check that ValidateAndInsertImportedPruningPoint fails if the UTXO commitment doesn't fit the provided UTXO set. + err = tcSyncee.ValidateAndInsertImportedPruningPoint(pruningPointBlock) if !errors.Is(err, ruleerrors.ErrBadPruningPointUTXOSet) { t.Fatalf("Unexpected error: %+v", err) } - // Check that ValidateAndInsertPruningPoint works given the right arguments. - err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, pruningPointUTXOSet) + err = tcSyncee.ClearImportedPruningPointData() if err != nil { - t.Fatalf("ValidateAndInsertPruningPoint: %+v", err) + t.Fatalf("ClearImportedPruningPointData: %+v", err) + } + err = tcSyncee.AppendImportedPruningPointUTXOs(pruningPointUTXOs) + if err != nil { + t.Fatalf("AppendImportedPruningPointUTXOs: %+v", err) + } + + // Check that ValidateAndInsertImportedPruningPoint works given the right arguments. + err = tcSyncee.ValidateAndInsertImportedPruningPoint(pruningPointBlock) + if err != nil { + t.Fatalf("ValidateAndInsertImportedPruningPoint: %+v", err) } virtualSelectedParent, err := tcSyncer.GetVirtualSelectedParent() @@ -256,9 +270,13 @@ func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) { t.Fatalf("Unexpected pruning point %s", pruningPoint) } - pruningPointUTXOSet, err := tcSyncer.GetPruningPointUTXOSet(pruningPoint) + pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, 0, 1000) if err != nil { - t.Fatalf("GetPruningPointUTXOSet: %+v", err) + t.Fatalf("GetPruningPointUTXOs: %+v", err) + } + err = tcSyncee.AppendImportedPruningPointUTXOs(pruningPointUTXOs) + if err != nil { + t.Fatalf("AppendImportedPruningPointUTXOs: %+v", err) } // Check that ValidateAndInsertPruningPoint works. @@ -266,7 +284,7 @@ func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) { if err != nil { t.Fatalf("GetBlock: %+v", err) } - err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, pruningPointUTXOSet) + err = tcSyncee.ValidateAndInsertImportedPruningPoint(pruningPointBlock) if err != nil { t.Fatalf("ValidateAndInsertPruningPoint: %+v", err) } @@ -362,33 +380,37 @@ func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) { }) } -type fakeUTXOSetIterator struct { - nextCalled bool -} - -func (f *fakeUTXOSetIterator) Next() bool { - if f.nextCalled { - return false +func makeFakeUTXOs() []*externalapi.OutpointAndUTXOEntryPair { + return []*externalapi.OutpointAndUTXOEntryPair{ + { + Outpoint: &externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: 0, + }, + UTXOEntry: utxo.NewUTXOEntry( + 0, + &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + false, + 0, + ), + }, + { + Outpoint: &externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, + Index: 1, + }, + UTXOEntry: utxo.NewUTXOEntry( + 2, + &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + true, + 3, + ), + }, } - f.nextCalled = true - return true -} - -func (f *fakeUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) { - return &externalapi.DomainOutpoint{ - TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}), - Index: 0, - }, utxo.NewUTXOEntry(1000, &externalapi.ScriptPublicKey{ - Script: []byte{1, 2, 3}, - Version: 0, - }, false, 2000), nil -} - -func makeSerializedFakeUTXOSet() ([]byte, error) { - serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(&fakeUTXOSetIterator{}) - if err != nil { - return nil, err - } - - return proto.Marshal(serializedUtxo) } diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go index ad94de971..82989d961 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo_test.go @@ -89,7 +89,7 @@ func checkBlockUTXOCommitment(t *testing.T, consensus testapi.TestConsensus, blo // Build a Multiset ms := multiset.New() - for utxoSetIterator.Next() { + for ok := utxoSetIterator.First(); ok; ok = utxoSetIterator.Next() { outpoint, entry, err := utxoSetIterator.Get() if err != nil { t.Fatalf("Error getting from UTXOSet iterator: %+v", err) diff --git a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go new file mode 100644 index 000000000..f69387f13 --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go @@ -0,0 +1,218 @@ +package consensusstatemanager + +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/transactionhelper" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" +) + +func (csm *consensusStateManager) ImportPruningPoint(newPruningPoint *externalapi.DomainBlock) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "ImportPruningPoint") + defer onEnd() + + err := csm.importPruningPoint(newPruningPoint) + if err != nil { + csm.discardImportedPruningPointUTXOSetChanges() + return err + } + + return csm.applyImportedPruningPointUTXOSet() +} + +func (csm *consensusStateManager) importPruningPoint(newPruningPoint *externalapi.DomainBlock) error { + log.Debugf("importPruningPoint start") + defer log.Debugf("importPruningPoint end") + + 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 + } + + if isViolatingFinality { + log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash) + return errors.Wrapf(ruleerrors.ErrSuggestedPruningViolatesFinality, "%s cannot be a pruning point because "+ + "it violates finality", newPruningPointHash) + } + + importedPruningPointMultiset, err := csm.pruningStore.ImportedPruningPointMultiset(csm.databaseContext) + if err != nil { + return err + } + + newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash) + if err != nil { + return err + } + log.Debugf("The UTXO commitment of the pruning point: %s", + newPruningPointHeader.UTXOCommitment()) + + if !newPruningPointHeader.UTXOCommitment().Equal(importedPruningPointMultiset.Hash()) { + return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+ + "point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment(), *importedPruningPointMultiset.Hash()) + } + log.Debugf("The new pruning point UTXO commitment validation passed") + + log.Debugf("Staging the the pruning point as the only DAG tip") + newTips := []*externalapi.DomainHash{newPruningPointHash} + csm.consensusStateStore.StageTips(newTips) + + log.Debugf("Setting the pruning point as the only virtual parent") + err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newTips) + if err != nil { + return err + } + + log.Debugf("Calculating GHOSTDAG for the new virtual") + err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash) + if err != nil { + return err + } + + log.Debugf("Deleting all existing virtual diff parents") + csm.consensusStateStore.StageVirtualDiffParents(nil) + + log.Debugf("Updating the new pruning point to be the new virtual diff parent with an empty diff") + err = csm.stageDiff(newPruningPointHash, utxo.NewUTXODiff(), nil) + if err != nil { + return err + } + + log.Debugf("Staging the new pruning point") + csm.pruningStore.StagePruningPoint(newPruningPointHash) + + log.Debugf("Populating the pruning point with UTXO entries") + importedPruningPointUTXOIterator, err := csm.pruningStore.ImportedPruningPointUTXOIterator(csm.databaseContext) + if err != nil { + return err + } + + // Clone the pruningPoint block here because validateBlockTransactionsAgainstPastUTXO + // assumes that the block UTXOEntries are pre-filled during further validations + newPruningPointClone := newPruningPoint.Clone() + err = csm.populateTransactionWithUTXOEntriesFromUTXOSet(newPruningPointClone, importedPruningPointUTXOIterator) + if err != nil { + 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. + log.Debugf("Validating that the pruning point is UTXO valid") + newPruningPointSelectedParentMedianTime, err := csm.pastMedianTimeManager.PastMedianTime(newPruningPointHash) + if err != nil { + return err + } + log.Tracef("The past median time of pruning block %s is %d", + newPruningPointHash, newPruningPointSelectedParentMedianTime) + + for i, transaction := range newPruningPointClone.Transactions { + transactionID := consensushashing.TransactionID(transaction) + log.Tracef("Validating transaction %s in pruning block %s against "+ + "the pruning point's past UTXO", transactionID, newPruningPointHash) + if i == transactionhelper.CoinbaseTransactionIndex { + log.Tracef("Skipping transaction %s because it is the coinbase", transactionID) + continue + } + log.Tracef("Validating transaction %s and populating it with mass and fee", transactionID) + err = csm.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee( + transaction, newPruningPointHash, newPruningPointSelectedParentMedianTime) + if err != nil { + return err + } + log.Tracef("Validation against the pruning point's past UTXO "+ + "passed for transaction %s", transactionID) + } + + log.Debugf("Staging the new pruning point as %s", externalapi.StatusUTXOValid) + csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusUTXOValid) + + log.Debugf("Staging the new pruning point multiset") + csm.multisetStore.Stage(newPruningPointHash, importedPruningPointMultiset) + return nil +} + +func (csm *consensusStateManager) discardImportedPruningPointUTXOSetChanges() { + for _, store := range csm.stores { + store.Discard() + } +} + +func (csm *consensusStateManager) applyImportedPruningPointUTXOSet() error { + dbTx, err := csm.databaseContext.Begin() + if err != nil { + return err + } + + for _, store := range csm.stores { + err = store.Commit(dbTx) + if err != nil { + return err + } + } + + log.Debugf("Starting to import virtual UTXO set and pruning point utxo set") + err = csm.consensusStateStore.StartImportingPruningPointUTXOSet(dbTx) + if err != nil { + return err + } + + log.Debugf("Committing all staged data for imported pruning point") + err = dbTx.Commit() + if err != nil { + return err + } + + return csm.importVirtualUTXOSetAndPruningPointUTXOSet() +} + +func (csm *consensusStateManager) importVirtualUTXOSetAndPruningPointUTXOSet() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "importVirtualUTXOSetAndPruningPointUTXOSet") + defer onEnd() + + log.Debugf("Getting an iterator into the imported pruning point utxo set") + pruningPointUTXOSetIterator, err := csm.pruningStore.ImportedPruningPointUTXOIterator(csm.databaseContext) + if err != nil { + return err + } + + log.Debugf("Importing the virtual UTXO set") + err = csm.consensusStateStore.ImportPruningPointUTXOSetIntoVirtualUTXOSet(csm.databaseContext, pruningPointUTXOSetIterator) + if err != nil { + return err + } + + log.Debugf("Importing the new pruning point UTXO set") + err = csm.pruningStore.CommitImportedPruningPointUTXOSet(csm.databaseContext) + if err != nil { + return err + } + + log.Debugf("Finishing to import virtual UTXO set and pruning point UTXO set") + return csm.consensusStateStore.FinishImportingPruningPointUTXOSet(csm.databaseContext) +} + +func (csm *consensusStateManager) RecoverUTXOIfRequired() error { + hadStartedImportingPruningPointUTXOSet, err := csm.consensusStateStore.HadStartedImportingPruningPointUTXOSet(csm.databaseContext) + if err != nil { + return err + } + if !hadStartedImportingPruningPointUTXOSet { + return nil + } + + log.Warnf("Unimported pruning point UTXO set detected. Attempting to recover...") + err = csm.importVirtualUTXOSetAndPruningPointUTXOSet() + if err != nil { + return err + } + log.Warnf("Unimported UTXO set successfully recovered") + return nil +} diff --git a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go index 3b5c6ce08..2ab13fb92 100644 --- a/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go +++ b/domain/consensus/processes/consensusstatemanager/populate_tx_with_utxo_entries.go @@ -75,3 +75,49 @@ func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualO return nil } + +func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromUTXOSet( + pruningPoint *externalapi.DomainBlock, iterator model.ReadOnlyUTXOSetIterator) error { + + // Collect the required outpoints from the block + outpointsForPopulation := make(map[externalapi.DomainOutpoint]interface{}) + for _, transaction := range pruningPoint.Transactions { + for _, input := range transaction.Inputs { + outpointsForPopulation[input.PreviousOutpoint] = struct{}{} + } + } + + // Collect the UTXO entries from the iterator + outpointsToUTXOEntries := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, len(outpointsForPopulation)) + for ok := iterator.First(); ok; ok = iterator.Next() { + outpoint, utxoEntry, err := iterator.Get() + if err != nil { + return err + } + outpointValue := *outpoint + if _, ok := outpointsForPopulation[outpointValue]; ok { + outpointsToUTXOEntries[outpointValue] = utxoEntry + } + if len(outpointsForPopulation) == len(outpointsToUTXOEntries) { + break + } + } + + // Populate the block with the collected UTXO entries + var missingOutpoints []*externalapi.DomainOutpoint + for _, transaction := range pruningPoint.Transactions { + for _, input := range transaction.Inputs { + utxoEntry, ok := outpointsToUTXOEntries[input.PreviousOutpoint] + if !ok { + missingOutpoints = append(missingOutpoints, &input.PreviousOutpoint) + continue + } + input.UTXOEntry = utxoEntry + } + } + + if len(missingOutpoints) > 0 { + return ruleerrors.NewErrMissingTxOut(missingOutpoints) + } + return nil +} diff --git a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go deleted file mode 100644 index 9b66aad91..000000000 --- a/domain/consensus/processes/consensusstatemanager/update_pruning_utxo_set.go +++ /dev/null @@ -1,174 +0,0 @@ -package consensusstatemanager - -import ( - "github.com/golang/protobuf/proto" - "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" - "github.com/kaspanet/kaspad/infrastructure/logger" - "github.com/pkg/errors" -) - -func (csm *consensusStateManager) UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { - onEnd := logger.LogAndMeasureExecutionTime(log, "UpdatePruningPoint") - defer onEnd() - - err := csm.updatePruningPoint(newPruningPoint, serializedUTXOSet) - if err != nil { - csm.discardSetPruningPointUTXOSetChanges() - return err - } - - return csm.commitSetPruningPointUTXOSetAll() -} - -func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error { - log.Debugf("updatePruningPoint start") - defer log.Debugf("updatePruningPoint end") - - 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 - } - - if isViolatingFinality { - log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash) - return errors.Wrapf(ruleerrors.ErrSuggestedPruningViolatesFinality, "%s cannot be a pruning point because "+ - "it violates finality", newPruningPointHash) - } - - protoUTXOSet := &utxoserialization.ProtoUTXOSet{} - err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet) - if err != nil { - return err - } - - utxoSetMultiSet, err := utxoserialization.CalculateMultisetFromProtoUTXOSet(protoUTXOSet) - if err != nil { - return err - } - log.Debugf("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash()) - - newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash) - if err != nil { - return err - } - log.Debugf("The UTXO commitment of the pruning point: %s", - newPruningPointHeader.UTXOCommitment()) - - if !newPruningPointHeader.UTXOCommitment().Equal(utxoSetMultiSet.Hash()) { - return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+ - "point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment(), *utxoSetMultiSet.Hash()) - } - log.Debugf("The new pruning point UTXO commitment validation passed") - - newTips := []*externalapi.DomainHash{newPruningPointHash} - - log.Debugf("Staging the the pruning point as the only DAG tip") - csm.consensusStateStore.StageTips(newTips) - - log.Debugf("Setting the pruning point as the only virtual parent") - err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newTips) - if err != nil { - return err - } - - log.Debugf("Calculating GHOSTDAG for the new virtual") - err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash) - if err != nil { - return err - } - - log.Debugf("Staging the virtual UTXO set") - err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet)) - if err != nil { - return err - } - - log.Debugf("Deleting all the existing virtual diff parents") - csm.consensusStateStore.StageVirtualDiffParents(nil) - - log.Debugf("Updating the new pruning point to be the new virtual diff parent with an empty diff") - err = csm.stageDiff(newPruningPointHash, utxo.NewUTXODiff(), nil) - if err != nil { - return err - } - - log.Debugf("Staging the new pruning point and its UTXO set") - csm.pruningStore.StagePruningPoint(newPruningPointHash, serializedUTXOSet) - - // Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid - // against the provided UTXO set. - log.Debugf("Validating that the pruning point is UTXO valid") - - // validateBlockTransactionsAgainstPastUTXO pre-fills the block's transactions inputs, which - // are assumed to not be pre-filled during further validations. - // Therefore - clone newPruningPoint before passing it to validateBlockTransactionsAgainstPastUTXO - err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint.Clone(), utxo.NewUTXODiff()) - if err != nil { - return err - } - - log.Debugf("Staging the new pruning point as %s", externalapi.StatusUTXOValid) - csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusUTXOValid) - - log.Debugf("Staging the new pruning point multiset") - csm.multisetStore.Stage(newPruningPointHash, utxoSetMultiSet) - return nil -} - -func (csm *consensusStateManager) discardSetPruningPointUTXOSetChanges() { - for _, store := range csm.stores { - store.Discard() - } -} - -func (csm *consensusStateManager) commitSetPruningPointUTXOSetAll() error { - dbTx, err := csm.databaseContext.Begin() - if err != nil { - return err - } - - for _, store := range csm.stores { - err = store.Commit(dbTx) - if err != nil { - return err - } - } - - return dbTx.Commit() -} - -type protoUTXOSetIterator struct { - utxoSet *utxoserialization.ProtoUTXOSet - index int -} - -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) { - entry, outpoint, err := utxo.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair) - if err != nil { - if serialization.IsMalformedError(err) { - return nil, nil, errors.Wrapf(ruleerrors.ErrMalformedUTXO, "malformed utxo: %s", err) - } - return nil, nil, err - } - - return outpoint, entry, nil -} - -func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator { - return &protoUTXOSetIterator{utxoSet: protoUTXOSet, index: -1} -} diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index 503f667c5..c1f3eb13a 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -52,10 +52,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain csm.multisetStore.Stage(model.VirtualBlockHash, virtualMultiset) log.Debugf("Staging new UTXO diff for the virtual block") - err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) - if err != nil { - return nil, err - } + csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff) log.Debugf("Updating the virtual diff parents after adding %s to the DAG", newBlockHash) err = csm.updateVirtualDiffParents(virtualUTXODiff) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 5f5c4a308..6479a2810 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -1,17 +1,18 @@ package pruningmanager import ( - "github.com/golang/protobuf/proto" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization" + "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" ) // pruningManager resolves and manages the current pruning point type pruningManager struct { - databaseContext model.DBReader + databaseContext model.DBManager dagTraversalManager model.DAGTraversalManager dagTopologyManager model.DAGTopologyManager @@ -36,7 +37,7 @@ type pruningManager struct { // New instantiates a new PruningManager func New( - databaseContext model.DBReader, + databaseContext model.DBManager, dagTraversalManager model.DAGTraversalManager, dagTopologyManager model.DAGTopologyManager, @@ -310,16 +311,20 @@ func (pm *pruningManager) savePruningPoint(pruningPointHash *externalapi.DomainH onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.savePruningPoint") defer onEnd() - utxoIter, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPointHash) + utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPointHash) if err != nil { return err } - serializedUtxo, err := pm.calculateAndValidateSerializedUTXOSet(utxoIter, pruningPointHash) + // TODO: This is an assert that takes ~30 seconds to run + // It must be removed or optimized before launching testnet + err = pm.validateUTXOSetFitsCommitment(utxoSetIterator, pruningPointHash) if err != nil { return err } - pm.pruningStore.StagePruningPoint(pruningPointHash, serializedUtxo) + + pm.pruningStore.StagePruningPoint(pruningPointHash) + pm.pruningStore.StagePruningPointUTXOSet(utxoSetIterator) return nil } @@ -410,32 +415,24 @@ func (pm *pruningManager) pruningPointCandidate() (*externalapi.DomainHash, erro return pm.pruningStore.PruningPointCandidate(pm.databaseContext) } -func (pm *pruningManager) calculateAndValidateSerializedUTXOSet( - iter model.ReadOnlyUTXOSetIterator, pruningPointHash *externalapi.DomainHash) ([]byte, error) { - - serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter) - if err != nil { - return nil, err - } - - err = pm.validateUTXOSetFitsCommitment(serializedUtxo, pruningPointHash) - if err != nil { - return nil, err - } - - return proto.Marshal(serializedUtxo) -} - // validateUTXOSetFitsCommitment makes sure that the calculated UTXOSet of the new pruning point fits the commitment. // This is a sanity test, to make sure that kaspad doesn't store, and subsequently sends syncing peers the wrong UTXOSet. -func (pm *pruningManager) validateUTXOSetFitsCommitment( - serializedUtxo *utxoserialization.ProtoUTXOSet, pruningPointHash *externalapi.DomainHash) error { +func (pm *pruningManager) validateUTXOSetFitsCommitment(utxoSetIterator model.ReadOnlyUTXOSetIterator, + pruningPointHash *externalapi.DomainHash) error { - utxoSetMultiSet, err := utxoserialization.CalculateMultisetFromProtoUTXOSet(serializedUtxo) - if err != nil { - return err + utxoSetMultiset := multiset.New() + for ok := utxoSetIterator.First(); ok; ok = utxoSetIterator.Next() { + outpoint, entry, err := utxoSetIterator.Get() + if err != nil { + return err + } + serializedUTXO, err := utxo.SerializeUTXO(entry, outpoint) + if err != nil { + return err + } + utxoSetMultiset.Add(serializedUTXO) } - utxoSetHash := utxoSetMultiSet.Hash() + utxoSetHash := utxoSetMultiset.Hash() header, err := pm.blockHeaderStore.BlockHeader(pm.databaseContext, pruningPointHash) if err != nil { @@ -459,3 +456,47 @@ func (pm *pruningManager) validateUTXOSetFitsCommitment( func (pm *pruningManager) finalityScore(blueScore uint64) uint64 { return blueScore / pm.finalityInterval } + +func (pm *pruningManager) ClearImportedPruningPointData() error { + err := pm.pruningStore.ClearImportedPruningPointMultiset(pm.databaseContext) + if err != nil { + return err + } + return pm.pruningStore.ClearImportedPruningPointUTXOs(pm.databaseContext) +} + +func (pm *pruningManager) AppendImportedPruningPointUTXOs( + outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error { + + dbTx, err := pm.databaseContext.Begin() + if err != nil { + return err + } + defer dbTx.RollbackUnlessClosed() + + importedMultiset, err := pm.pruningStore.ImportedPruningPointMultiset(dbTx) + if err != nil { + if !database.IsNotFoundError(err) { + return err + } + importedMultiset = multiset.New() + } + for _, outpointAndUTXOEntryPair := range outpointAndUTXOEntryPairs { + serializedUTXO, err := utxo.SerializeUTXO(outpointAndUTXOEntryPair.UTXOEntry, outpointAndUTXOEntryPair.Outpoint) + if err != nil { + return err + } + importedMultiset.Add(serializedUTXO) + } + err = pm.pruningStore.UpdateImportedPruningPointMultiset(dbTx, importedMultiset) + if err != nil { + return err + } + + err = pm.pruningStore.AppendImportedPruningPointUTXOs(dbTx, outpointAndUTXOEntryPairs) + if err != nil { + return err + } + + return dbTx.Commit() +} diff --git a/domain/consensus/utils/utxo/utxo_iterator.go b/domain/consensus/utils/utxo/utxo_iterator.go index b78154ba2..4548087d0 100644 --- a/domain/consensus/utils/utxo/utxo_iterator.go +++ b/domain/consensus/utils/utxo/utxo_iterator.go @@ -29,6 +29,11 @@ func (uc utxoCollection) Iterator() model.ReadOnlyUTXOSetIterator { return &utxoCollectionIterator{index: -1, pairs: pairs} } +func (uci *utxoCollectionIterator) First() bool { + uci.index = 0 + return len(uci.pairs) > 0 +} + func (uci *utxoCollectionIterator) Next() bool { uci.index++ return uci.index < len(uci.pairs) diff --git a/domain/consensus/utils/utxo/utxo_iterator_with_diff.go b/domain/consensus/utils/utxo/utxo_iterator_with_diff.go index 1a92aea08..acd33a809 100644 --- a/domain/consensus/utils/utxo/utxo_iterator_with_diff.go +++ b/domain/consensus/utils/utxo/utxo_iterator_with_diff.go @@ -36,10 +36,31 @@ func IteratorWithDiff(iterator model.ReadOnlyUTXOSetIterator, diff model.UTXODif return &readOnlyUTXOIteratorWithDiff{ baseIterator: iterator, diff: d, - toAddIterator: d.mutableUTXODiff.toAdd.Iterator(), + toAddIterator: d.ToAdd().Iterator(), }, nil } +func (r *readOnlyUTXOIteratorWithDiff) First() bool { + baseNotEmpty := r.baseIterator.First() + baseEmpty := !baseNotEmpty + + r.toAddIterator = r.diff.ToAdd().Iterator() + toAddEmpty := r.diff.ToAdd().Len() == 0 + + if baseEmpty { + if toAddEmpty { + return false + } + return r.Next() + } + + r.currentOutpoint, r.currentUTXOEntry, r.currentErr = r.baseIterator.Get() + if r.diff.mutableUTXODiff.toRemove.containsWithBlueScore(r.currentOutpoint, r.currentUTXOEntry.BlockBlueScore()) { + return r.Next() + } + return true +} + func (r *readOnlyUTXOIteratorWithDiff) Next() bool { for r.baseIterator.Next() { // keep looping until we reach an outpoint/entry pair that is not in r.diff.toRemove r.currentOutpoint, r.currentUTXOEntry, r.currentErr = r.baseIterator.Get() diff --git a/domain/consensus/utils/utxoserialization/generate.go b/domain/consensus/utils/utxoserialization/generate.go deleted file mode 100644 index f58bfc473..000000000 --- a/domain/consensus/utils/utxoserialization/generate.go +++ /dev/null @@ -1,3 +0,0 @@ -//go:generate protoc --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative utxo.proto - -package utxoserialization diff --git a/domain/consensus/utils/utxoserialization/multiset.go b/domain/consensus/utils/utxoserialization/multiset.go deleted file mode 100644 index 6e62cd0f7..000000000 --- a/domain/consensus/utils/utxoserialization/multiset.go +++ /dev/null @@ -1,15 +0,0 @@ -package utxoserialization - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" -) - -// CalculateMultisetFromProtoUTXOSet calculates the Multiset corresponding to the given ProtuUTXOSet -func CalculateMultisetFromProtoUTXOSet(protoUTXOSet *ProtoUTXOSet) (model.Multiset, error) { - ms := multiset.New() - for _, utxo := range protoUTXOSet.Utxos { - ms.Add(utxo.EntryOutpointPair) - } - return ms, nil -} diff --git a/domain/consensus/utils/utxoserialization/utxo.go b/domain/consensus/utils/utxoserialization/utxo.go deleted file mode 100644 index 3d3b89e31..000000000 --- a/domain/consensus/utils/utxoserialization/utxo.go +++ /dev/null @@ -1,30 +0,0 @@ -package utxoserialization - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model" - "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" -) - -// ReadOnlyUTXOSetToProtoUTXOSet converts ReadOnlyUTXOSetIterator to ProtoUTXOSet -func ReadOnlyUTXOSetToProtoUTXOSet(iter model.ReadOnlyUTXOSetIterator) (*ProtoUTXOSet, error) { - protoUTXOSet := &ProtoUTXOSet{ - Utxos: []*ProtoUTXO{}, - } - - for iter.Next() { - outpoint, entry, err := iter.Get() - if err != nil { - return nil, err - } - - serializedUTXOBytes, err := utxo.SerializeUTXO(entry, outpoint) - if err != nil { - return nil, err - } - - protoUTXOSet.Utxos = append(protoUTXOSet.Utxos, &ProtoUTXO{ - EntryOutpointPair: serializedUTXOBytes, - }) - } - return protoUTXOSet, nil -} diff --git a/domain/consensus/utils/utxoserialization/utxo.pb.go b/domain/consensus/utils/utxoserialization/utxo.pb.go deleted file mode 100644 index faa28b24b..000000000 --- a/domain/consensus/utils/utxoserialization/utxo.pb.go +++ /dev/null @@ -1,217 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.25.0 -// protoc v3.12.3 -// source: utxo.proto - -package utxoserialization - -import ( - proto "github.com/golang/protobuf/proto" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type ProtoUTXO struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EntryOutpointPair []byte `protobuf:"bytes,1,opt,name=entryOutpointPair,proto3" json:"entryOutpointPair,omitempty"` -} - -func (x *ProtoUTXO) Reset() { - *x = ProtoUTXO{} - if protoimpl.UnsafeEnabled { - mi := &file_utxo_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProtoUTXO) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProtoUTXO) ProtoMessage() {} - -func (x *ProtoUTXO) ProtoReflect() protoreflect.Message { - mi := &file_utxo_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ProtoUTXO.ProtoReflect.Descriptor instead. -func (*ProtoUTXO) Descriptor() ([]byte, []int) { - return file_utxo_proto_rawDescGZIP(), []int{0} -} - -func (x *ProtoUTXO) GetEntryOutpointPair() []byte { - if x != nil { - return x.EntryOutpointPair - } - return nil -} - -type ProtoUTXOSet struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Utxos []*ProtoUTXO `protobuf:"bytes,1,rep,name=utxos,proto3" json:"utxos,omitempty"` -} - -func (x *ProtoUTXOSet) Reset() { - *x = ProtoUTXOSet{} - if protoimpl.UnsafeEnabled { - mi := &file_utxo_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProtoUTXOSet) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProtoUTXOSet) ProtoMessage() {} - -func (x *ProtoUTXOSet) ProtoReflect() protoreflect.Message { - mi := &file_utxo_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ProtoUTXOSet.ProtoReflect.Descriptor instead. -func (*ProtoUTXOSet) Descriptor() ([]byte, []int) { - return file_utxo_proto_rawDescGZIP(), []int{1} -} - -func (x *ProtoUTXOSet) GetUtxos() []*ProtoUTXO { - if x != nil { - return x.Utxos - } - return nil -} - -var File_utxo_proto protoreflect.FileDescriptor - -var file_utxo_proto_rawDesc = []byte{ - 0x0a, 0x0a, 0x75, 0x74, 0x78, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x75, 0x74, - 0x78, 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x39, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x12, 0x2c, 0x0a, 0x11, - 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x61, 0x69, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x61, 0x69, 0x72, 0x22, 0x42, 0x0a, 0x0c, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x75, 0x74, - 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x75, 0x74, 0x78, 0x6f, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x55, 0x54, 0x58, 0x4f, 0x52, 0x05, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x45, - 0x5a, 0x43, 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, 0x64, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2f, 0x75, 0x74, - 0x69, 0x6c, 0x73, 0x2f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_utxo_proto_rawDescOnce sync.Once - file_utxo_proto_rawDescData = file_utxo_proto_rawDesc -) - -func file_utxo_proto_rawDescGZIP() []byte { - file_utxo_proto_rawDescOnce.Do(func() { - file_utxo_proto_rawDescData = protoimpl.X.CompressGZIP(file_utxo_proto_rawDescData) - }) - return file_utxo_proto_rawDescData -} - -var file_utxo_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_utxo_proto_goTypes = []interface{}{ - (*ProtoUTXO)(nil), // 0: utxoserialization.ProtoUTXO - (*ProtoUTXOSet)(nil), // 1: utxoserialization.ProtoUTXOSet -} -var file_utxo_proto_depIdxs = []int32{ - 0, // 0: utxoserialization.ProtoUTXOSet.utxos:type_name -> utxoserialization.ProtoUTXO - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_utxo_proto_init() } -func file_utxo_proto_init() { - if File_utxo_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_utxo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProtoUTXO); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_utxo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProtoUTXOSet); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_utxo_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_utxo_proto_goTypes, - DependencyIndexes: file_utxo_proto_depIdxs, - MessageInfos: file_utxo_proto_msgTypes, - }.Build() - File_utxo_proto = out.File - file_utxo_proto_rawDesc = nil - file_utxo_proto_goTypes = nil - file_utxo_proto_depIdxs = nil -} diff --git a/domain/consensus/utils/utxoserialization/utxo.proto b/domain/consensus/utils/utxoserialization/utxo.proto deleted file mode 100644 index 01bbebe00..000000000 --- a/domain/consensus/utils/utxoserialization/utxo.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; -package utxoserialization; - -option go_package = "github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"; - -message ProtoUTXO { - bytes entryOutpointPair = 1; -} - -message ProtoUTXOSet { - repeated ProtoUTXO utxos = 1; -} \ No newline at end of file diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 6185c7945..0811df1bb 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -51,17 +51,17 @@ type KaspadMessage struct { // *KaspadMessage_Version // *KaspadMessage_TransactionNotFound // *KaspadMessage_Reject - // *KaspadMessage_RequestIBDRootUTXOSetAndBlock - // *KaspadMessage_IbdRootUtxoSetChunk + // *KaspadMessage_RequestPruningPointUTXOSetAndBlock + // *KaspadMessage_PruningPointUtxoSetChunk // *KaspadMessage_RequestIBDBlocks - // *KaspadMessage_IbdRootNotFound - // *KaspadMessage_RequestIBDRootHash - // *KaspadMessage_IbdRootHash + // *KaspadMessage_UnexpectedPruningPoint + // *KaspadMessage_RequestPruningPointHash + // *KaspadMessage_PruningPointHash // *KaspadMessage_IbdBlockLocator // *KaspadMessage_IbdBlockLocatorHighestHash // *KaspadMessage_BlockHeaders - // *KaspadMessage_RequestNextIbdRootUtxoSetChunk - // *KaspadMessage_DoneIbdRootUtxoSetChunks + // *KaspadMessage_RequestNextPruningPointUtxoSetChunk + // *KaspadMessage_DonePruningPointUtxoSetChunks // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -302,16 +302,16 @@ func (x *KaspadMessage) GetReject() *RejectMessage { return nil } -func (x *KaspadMessage) GetRequestIBDRootUTXOSetAndBlock() *RequestIBDRootUTXOSetAndBlockMessage { - if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDRootUTXOSetAndBlock); ok { - return x.RequestIBDRootUTXOSetAndBlock +func (x *KaspadMessage) GetRequestPruningPointUTXOSetAndBlock() *RequestPruningPointUTXOSetAndBlockMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestPruningPointUTXOSetAndBlock); ok { + return x.RequestPruningPointUTXOSetAndBlock } return nil } -func (x *KaspadMessage) GetIbdRootUtxoSetChunk() *IbdRootUtxoSetChunkMessage { - if x, ok := x.GetPayload().(*KaspadMessage_IbdRootUtxoSetChunk); ok { - return x.IbdRootUtxoSetChunk +func (x *KaspadMessage) GetPruningPointUtxoSetChunk() *PruningPointUtxoSetChunkMessage { + if x, ok := x.GetPayload().(*KaspadMessage_PruningPointUtxoSetChunk); ok { + return x.PruningPointUtxoSetChunk } return nil } @@ -323,23 +323,23 @@ func (x *KaspadMessage) GetRequestIBDBlocks() *RequestIBDBlocksMessage { return nil } -func (x *KaspadMessage) GetIbdRootNotFound() *IBDRootNotFoundMessage { - if x, ok := x.GetPayload().(*KaspadMessage_IbdRootNotFound); ok { - return x.IbdRootNotFound +func (x *KaspadMessage) GetUnexpectedPruningPoint() *UnexpectedPruningPointMessage { + if x, ok := x.GetPayload().(*KaspadMessage_UnexpectedPruningPoint); ok { + return x.UnexpectedPruningPoint } return nil } -func (x *KaspadMessage) GetRequestIBDRootHash() *RequestIBDRootHashMessage { - if x, ok := x.GetPayload().(*KaspadMessage_RequestIBDRootHash); ok { - return x.RequestIBDRootHash +func (x *KaspadMessage) GetRequestPruningPointHash() *RequestPruningPointHashMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestPruningPointHash); ok { + return x.RequestPruningPointHash } return nil } -func (x *KaspadMessage) GetIbdRootHash() *IBDRootHashMessage { - if x, ok := x.GetPayload().(*KaspadMessage_IbdRootHash); ok { - return x.IbdRootHash +func (x *KaspadMessage) GetPruningPointHash() *PruningPointHashMessage { + if x, ok := x.GetPayload().(*KaspadMessage_PruningPointHash); ok { + return x.PruningPointHash } return nil } @@ -365,16 +365,16 @@ func (x *KaspadMessage) GetBlockHeaders() *BlockHeadersMessage { return nil } -func (x *KaspadMessage) GetRequestNextIbdRootUtxoSetChunk() *RequestNextIbdRootUtxoSetChunkMessage { - if x, ok := x.GetPayload().(*KaspadMessage_RequestNextIbdRootUtxoSetChunk); ok { - return x.RequestNextIbdRootUtxoSetChunk +func (x *KaspadMessage) GetRequestNextPruningPointUtxoSetChunk() *RequestNextPruningPointUtxoSetChunkMessage { + if x, ok := x.GetPayload().(*KaspadMessage_RequestNextPruningPointUtxoSetChunk); ok { + return x.RequestNextPruningPointUtxoSetChunk } return nil } -func (x *KaspadMessage) GetDoneIbdRootUtxoSetChunks() *DoneIbdRootUtxoSetChunksMessage { - if x, ok := x.GetPayload().(*KaspadMessage_DoneIbdRootUtxoSetChunks); ok { - return x.DoneIbdRootUtxoSetChunks +func (x *KaspadMessage) GetDonePruningPointUtxoSetChunks() *DonePruningPointUtxoSetChunksMessage { + if x, ok := x.GetPayload().(*KaspadMessage_DonePruningPointUtxoSetChunks); ok { + return x.DonePruningPointUtxoSetChunks } return nil } @@ -869,28 +869,28 @@ type KaspadMessage_Reject struct { Reject *RejectMessage `protobuf:"bytes,22,opt,name=reject,proto3,oneof"` } -type KaspadMessage_RequestIBDRootUTXOSetAndBlock struct { - RequestIBDRootUTXOSetAndBlock *RequestIBDRootUTXOSetAndBlockMessage `protobuf:"bytes,24,opt,name=requestIBDRootUTXOSetAndBlock,proto3,oneof"` +type KaspadMessage_RequestPruningPointUTXOSetAndBlock struct { + RequestPruningPointUTXOSetAndBlock *RequestPruningPointUTXOSetAndBlockMessage `protobuf:"bytes,24,opt,name=requestPruningPointUTXOSetAndBlock,proto3,oneof"` } -type KaspadMessage_IbdRootUtxoSetChunk struct { - IbdRootUtxoSetChunk *IbdRootUtxoSetChunkMessage `protobuf:"bytes,25,opt,name=ibdRootUtxoSetChunk,proto3,oneof"` +type KaspadMessage_PruningPointUtxoSetChunk struct { + PruningPointUtxoSetChunk *PruningPointUtxoSetChunkMessage `protobuf:"bytes,25,opt,name=pruningPointUtxoSetChunk,proto3,oneof"` } type KaspadMessage_RequestIBDBlocks struct { RequestIBDBlocks *RequestIBDBlocksMessage `protobuf:"bytes,26,opt,name=requestIBDBlocks,proto3,oneof"` } -type KaspadMessage_IbdRootNotFound struct { - IbdRootNotFound *IBDRootNotFoundMessage `protobuf:"bytes,27,opt,name=ibdRootNotFound,proto3,oneof"` +type KaspadMessage_UnexpectedPruningPoint struct { + UnexpectedPruningPoint *UnexpectedPruningPointMessage `protobuf:"bytes,27,opt,name=unexpectedPruningPoint,proto3,oneof"` } -type KaspadMessage_RequestIBDRootHash struct { - RequestIBDRootHash *RequestIBDRootHashMessage `protobuf:"bytes,28,opt,name=requestIBDRootHash,proto3,oneof"` +type KaspadMessage_RequestPruningPointHash struct { + RequestPruningPointHash *RequestPruningPointHashMessage `protobuf:"bytes,28,opt,name=requestPruningPointHash,proto3,oneof"` } -type KaspadMessage_IbdRootHash struct { - IbdRootHash *IBDRootHashMessage `protobuf:"bytes,29,opt,name=ibdRootHash,proto3,oneof"` +type KaspadMessage_PruningPointHash struct { + PruningPointHash *PruningPointHashMessage `protobuf:"bytes,29,opt,name=pruningPointHash,proto3,oneof"` } type KaspadMessage_IbdBlockLocator struct { @@ -905,12 +905,12 @@ type KaspadMessage_BlockHeaders struct { BlockHeaders *BlockHeadersMessage `protobuf:"bytes,32,opt,name=blockHeaders,proto3,oneof"` } -type KaspadMessage_RequestNextIbdRootUtxoSetChunk struct { - RequestNextIbdRootUtxoSetChunk *RequestNextIbdRootUtxoSetChunkMessage `protobuf:"bytes,33,opt,name=requestNextIbdRootUtxoSetChunk,proto3,oneof"` +type KaspadMessage_RequestNextPruningPointUtxoSetChunk struct { + RequestNextPruningPointUtxoSetChunk *RequestNextPruningPointUtxoSetChunkMessage `protobuf:"bytes,33,opt,name=requestNextPruningPointUtxoSetChunk,proto3,oneof"` } -type KaspadMessage_DoneIbdRootUtxoSetChunks struct { - DoneIbdRootUtxoSetChunks *DoneIbdRootUtxoSetChunksMessage `protobuf:"bytes,34,opt,name=doneIbdRootUtxoSetChunks,proto3,oneof"` +type KaspadMessage_DonePruningPointUtxoSetChunks struct { + DonePruningPointUtxoSetChunks *DonePruningPointUtxoSetChunksMessage `protobuf:"bytes,34,opt,name=donePruningPointUtxoSetChunks,proto3,oneof"` } type KaspadMessage_GetCurrentNetworkRequest struct { @@ -1185,17 +1185,17 @@ func (*KaspadMessage_TransactionNotFound) isKaspadMessage_Payload() {} func (*KaspadMessage_Reject) isKaspadMessage_Payload() {} -func (*KaspadMessage_RequestIBDRootUTXOSetAndBlock) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestPruningPointUTXOSetAndBlock) isKaspadMessage_Payload() {} -func (*KaspadMessage_IbdRootUtxoSetChunk) isKaspadMessage_Payload() {} +func (*KaspadMessage_PruningPointUtxoSetChunk) isKaspadMessage_Payload() {} func (*KaspadMessage_RequestIBDBlocks) isKaspadMessage_Payload() {} -func (*KaspadMessage_IbdRootNotFound) isKaspadMessage_Payload() {} +func (*KaspadMessage_UnexpectedPruningPoint) isKaspadMessage_Payload() {} -func (*KaspadMessage_RequestIBDRootHash) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestPruningPointHash) isKaspadMessage_Payload() {} -func (*KaspadMessage_IbdRootHash) isKaspadMessage_Payload() {} +func (*KaspadMessage_PruningPointHash) isKaspadMessage_Payload() {} func (*KaspadMessage_IbdBlockLocator) isKaspadMessage_Payload() {} @@ -1203,9 +1203,9 @@ func (*KaspadMessage_IbdBlockLocatorHighestHash) isKaspadMessage_Payload() {} func (*KaspadMessage_BlockHeaders) isKaspadMessage_Payload() {} -func (*KaspadMessage_RequestNextIbdRootUtxoSetChunk) isKaspadMessage_Payload() {} +func (*KaspadMessage_RequestNextPruningPointUtxoSetChunk) isKaspadMessage_Payload() {} -func (*KaspadMessage_DoneIbdRootUtxoSetChunks) isKaspadMessage_Payload() {} +func (*KaspadMessage_DonePruningPointUtxoSetChunks) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} @@ -1329,7 +1329,7 @@ var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xb3, 0x47, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x6f, 0x22, 0xa4, 0x48, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, @@ -1416,504 +1416,511 @@ var file_messages_proto_rawDesc = []byte{ 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, - 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x77, 0x0a, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, - 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, - 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, + 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x86, 0x01, 0x0a, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, + 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x22, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, - 0x59, 0x0a, 0x13, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, - 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, - 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, - 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x4d, 0x0a, 0x0f, - 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, - 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, - 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x52, - 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, - 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x12, 0x41, 0x0a, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x69, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, + 0x68, 0x0a, 0x18, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x72, + 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, + 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x18, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x62, 0x0a, 0x16, 0x75, + 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x75, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x65, 0x0a, 0x17, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, + 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x50, 0x0a, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, + 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x75, + 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0f, 0x69, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, + 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x7a, 0x0a, 0x1e, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, - 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x21, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, 0x64, 0x52, 0x6f, - 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, - 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x68, 0x0a, 0x18, 0x64, 0x6f, 0x6e, 0x65, 0x49, - 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, - 0x6e, 0x6b, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, - 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x64, 0x6f, 0x6e, 0x65, 0x49, 0x62, 0x64, - 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, - 0x73, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, - 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, - 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, - 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, - 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, - 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x69, 0x62, 0x64, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, + 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x44, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x89, 0x01, + 0x0a, 0x23, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x75, + 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, + 0x65, 0x78, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x23, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, + 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x77, 0x0a, 0x1d, 0x64, 0x6f, 0x6e, + 0x65, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6e, + 0x65, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x1d, 0x64, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x73, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, - 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, - 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, + 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, + 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, + 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, + 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, + 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, + 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, - 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, + 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, + 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, - 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, - 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, + 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, + 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, 0x00, - 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, + 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, + 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, - 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 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, 0x48, - 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, - 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, - 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, - 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 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, + 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, - 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, - 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, + 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, + 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, - 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, + 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, + 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, + 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, + 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, + 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, + 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, - 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, + 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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 ( @@ -1950,17 +1957,17 @@ var file_messages_proto_goTypes = []interface{}{ (*VersionMessage)(nil), // 17: protowire.VersionMessage (*TransactionNotFoundMessage)(nil), // 18: protowire.TransactionNotFoundMessage (*RejectMessage)(nil), // 19: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 20: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IbdRootUtxoSetChunkMessage)(nil), // 21: protowire.IbdRootUtxoSetChunkMessage + (*RequestPruningPointUTXOSetAndBlockMessage)(nil), // 20: protowire.RequestPruningPointUTXOSetAndBlockMessage + (*PruningPointUtxoSetChunkMessage)(nil), // 21: protowire.PruningPointUtxoSetChunkMessage (*RequestIBDBlocksMessage)(nil), // 22: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 23: protowire.IBDRootNotFoundMessage - (*RequestIBDRootHashMessage)(nil), // 24: protowire.RequestIBDRootHashMessage - (*IBDRootHashMessage)(nil), // 25: protowire.IBDRootHashMessage + (*UnexpectedPruningPointMessage)(nil), // 23: protowire.UnexpectedPruningPointMessage + (*RequestPruningPointHashMessage)(nil), // 24: protowire.RequestPruningPointHashMessage + (*PruningPointHashMessage)(nil), // 25: protowire.PruningPointHashMessage (*IbdBlockLocatorMessage)(nil), // 26: protowire.IbdBlockLocatorMessage (*IbdBlockLocatorHighestHashMessage)(nil), // 27: protowire.IbdBlockLocatorHighestHashMessage (*BlockHeadersMessage)(nil), // 28: protowire.BlockHeadersMessage - (*RequestNextIbdRootUtxoSetChunkMessage)(nil), // 29: protowire.RequestNextIbdRootUtxoSetChunkMessage - (*DoneIbdRootUtxoSetChunksMessage)(nil), // 30: protowire.DoneIbdRootUtxoSetChunksMessage + (*RequestNextPruningPointUtxoSetChunkMessage)(nil), // 29: protowire.RequestNextPruningPointUtxoSetChunkMessage + (*DonePruningPointUtxoSetChunksMessage)(nil), // 30: protowire.DonePruningPointUtxoSetChunksMessage (*GetCurrentNetworkRequestMessage)(nil), // 31: protowire.GetCurrentNetworkRequestMessage (*GetCurrentNetworkResponseMessage)(nil), // 32: protowire.GetCurrentNetworkResponseMessage (*SubmitBlockRequestMessage)(nil), // 33: protowire.SubmitBlockRequestMessage @@ -2041,17 +2048,17 @@ var file_messages_proto_depIdxs = []int32{ 17, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage 18, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage 19, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 20, // 20: protowire.KaspadMessage.requestIBDRootUTXOSetAndBlock:type_name -> protowire.RequestIBDRootUTXOSetAndBlockMessage - 21, // 21: protowire.KaspadMessage.ibdRootUtxoSetChunk:type_name -> protowire.IbdRootUtxoSetChunkMessage + 20, // 20: protowire.KaspadMessage.requestPruningPointUTXOSetAndBlock:type_name -> protowire.RequestPruningPointUTXOSetAndBlockMessage + 21, // 21: protowire.KaspadMessage.pruningPointUtxoSetChunk:type_name -> protowire.PruningPointUtxoSetChunkMessage 22, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 23, // 23: protowire.KaspadMessage.ibdRootNotFound:type_name -> protowire.IBDRootNotFoundMessage - 24, // 24: protowire.KaspadMessage.requestIBDRootHash:type_name -> protowire.RequestIBDRootHashMessage - 25, // 25: protowire.KaspadMessage.ibdRootHash:type_name -> protowire.IBDRootHashMessage + 23, // 23: protowire.KaspadMessage.unexpectedPruningPoint:type_name -> protowire.UnexpectedPruningPointMessage + 24, // 24: protowire.KaspadMessage.requestPruningPointHash:type_name -> protowire.RequestPruningPointHashMessage + 25, // 25: protowire.KaspadMessage.pruningPointHash:type_name -> protowire.PruningPointHashMessage 26, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage 27, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage 28, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage - 29, // 29: protowire.KaspadMessage.requestNextIbdRootUtxoSetChunk:type_name -> protowire.RequestNextIbdRootUtxoSetChunkMessage - 30, // 30: protowire.KaspadMessage.doneIbdRootUtxoSetChunks:type_name -> protowire.DoneIbdRootUtxoSetChunksMessage + 29, // 29: protowire.KaspadMessage.requestNextPruningPointUtxoSetChunk:type_name -> protowire.RequestNextPruningPointUtxoSetChunkMessage + 30, // 30: protowire.KaspadMessage.donePruningPointUtxoSetChunks:type_name -> protowire.DonePruningPointUtxoSetChunksMessage 31, // 31: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage 32, // 32: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage 33, // 33: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage @@ -2163,17 +2170,17 @@ func file_messages_proto_init() { (*KaspadMessage_Version)(nil), (*KaspadMessage_TransactionNotFound)(nil), (*KaspadMessage_Reject)(nil), - (*KaspadMessage_RequestIBDRootUTXOSetAndBlock)(nil), - (*KaspadMessage_IbdRootUtxoSetChunk)(nil), + (*KaspadMessage_RequestPruningPointUTXOSetAndBlock)(nil), + (*KaspadMessage_PruningPointUtxoSetChunk)(nil), (*KaspadMessage_RequestIBDBlocks)(nil), - (*KaspadMessage_IbdRootNotFound)(nil), - (*KaspadMessage_RequestIBDRootHash)(nil), - (*KaspadMessage_IbdRootHash)(nil), + (*KaspadMessage_UnexpectedPruningPoint)(nil), + (*KaspadMessage_RequestPruningPointHash)(nil), + (*KaspadMessage_PruningPointHash)(nil), (*KaspadMessage_IbdBlockLocator)(nil), (*KaspadMessage_IbdBlockLocatorHighestHash)(nil), (*KaspadMessage_BlockHeaders)(nil), - (*KaspadMessage_RequestNextIbdRootUtxoSetChunk)(nil), - (*KaspadMessage_DoneIbdRootUtxoSetChunks)(nil), + (*KaspadMessage_RequestNextPruningPointUtxoSetChunk)(nil), + (*KaspadMessage_DonePruningPointUtxoSetChunks)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 4aed64c5d..50631bac9 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -28,17 +28,17 @@ message KaspadMessage { VersionMessage version = 20; TransactionNotFoundMessage transactionNotFound = 21; RejectMessage reject = 22; - RequestIBDRootUTXOSetAndBlockMessage requestIBDRootUTXOSetAndBlock = 24; - IbdRootUtxoSetChunkMessage ibdRootUtxoSetChunk = 25; + RequestPruningPointUTXOSetAndBlockMessage requestPruningPointUTXOSetAndBlock = 24; + PruningPointUtxoSetChunkMessage pruningPointUtxoSetChunk = 25; RequestIBDBlocksMessage requestIBDBlocks = 26; - IBDRootNotFoundMessage ibdRootNotFound = 27; - RequestIBDRootHashMessage requestIBDRootHash = 28; - IBDRootHashMessage ibdRootHash = 29; + UnexpectedPruningPointMessage unexpectedPruningPoint = 27; + RequestPruningPointHashMessage requestPruningPointHash = 28; + PruningPointHashMessage pruningPointHash = 29; IbdBlockLocatorMessage ibdBlockLocator = 30; IbdBlockLocatorHighestHashMessage ibdBlockLocatorHighestHash = 31; BlockHeadersMessage blockHeaders = 32; - RequestNextIbdRootUtxoSetChunkMessage requestNextIbdRootUtxoSetChunk = 33; - DoneIbdRootUtxoSetChunksMessage doneIbdRootUtxoSetChunks = 34; + RequestNextPruningPointUtxoSetChunkMessage requestNextPruningPointUtxoSetChunk = 33; + DonePruningPointUtxoSetChunksMessage donePruningPointUtxoSetChunks = 34; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go index 45c2793ec..6a74c6316 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go @@ -1594,16 +1594,16 @@ func (x *RejectMessage) GetReason() string { return "" } -type RequestIBDRootUTXOSetAndBlockMessage struct { +type RequestPruningPointUTXOSetAndBlockMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IbdRoot *Hash `protobuf:"bytes,1,opt,name=ibdRoot,proto3" json:"ibdRoot,omitempty"` + PruningPointHash *Hash `protobuf:"bytes,1,opt,name=pruningPointHash,proto3" json:"pruningPointHash,omitempty"` } -func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { - *x = RequestIBDRootUTXOSetAndBlockMessage{} +func (x *RequestPruningPointUTXOSetAndBlockMessage) Reset() { + *x = RequestPruningPointUTXOSetAndBlockMessage{} if protoimpl.UnsafeEnabled { mi := &file_p2p_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1611,13 +1611,13 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) Reset() { } } -func (x *RequestIBDRootUTXOSetAndBlockMessage) String() string { +func (x *RequestPruningPointUTXOSetAndBlockMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RequestIBDRootUTXOSetAndBlockMessage) ProtoMessage() {} +func (*RequestPruningPointUTXOSetAndBlockMessage) ProtoMessage() {} -func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { +func (x *RequestPruningPointUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Message { mi := &file_p2p_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1629,28 +1629,28 @@ func (x *RequestIBDRootUTXOSetAndBlockMessage) ProtoReflect() protoreflect.Messa return mi.MessageOf(x) } -// Deprecated: Use RequestIBDRootUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. -func (*RequestIBDRootUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use RequestPruningPointUTXOSetAndBlockMessage.ProtoReflect.Descriptor instead. +func (*RequestPruningPointUTXOSetAndBlockMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{28} } -func (x *RequestIBDRootUTXOSetAndBlockMessage) GetIbdRoot() *Hash { +func (x *RequestPruningPointUTXOSetAndBlockMessage) GetPruningPointHash() *Hash { if x != nil { - return x.IbdRoot + return x.PruningPointHash } return nil } -type IbdRootUtxoSetChunkMessage struct { +type PruningPointUtxoSetChunkMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Chunk []byte `protobuf:"bytes,1,opt,name=chunk,proto3" json:"chunk,omitempty"` + OutpointAndUtxoEntryPairs []*OutpointAndUtxoEntryPair `protobuf:"bytes,1,rep,name=outpointAndUtxoEntryPairs,proto3" json:"outpointAndUtxoEntryPairs,omitempty"` } -func (x *IbdRootUtxoSetChunkMessage) Reset() { - *x = IbdRootUtxoSetChunkMessage{} +func (x *PruningPointUtxoSetChunkMessage) Reset() { + *x = PruningPointUtxoSetChunkMessage{} if protoimpl.UnsafeEnabled { mi := &file_p2p_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1658,13 +1658,13 @@ func (x *IbdRootUtxoSetChunkMessage) Reset() { } } -func (x *IbdRootUtxoSetChunkMessage) String() string { +func (x *PruningPointUtxoSetChunkMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*IbdRootUtxoSetChunkMessage) ProtoMessage() {} +func (*PruningPointUtxoSetChunkMessage) ProtoMessage() {} -func (x *IbdRootUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { +func (x *PruningPointUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { mi := &file_p2p_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1676,26 +1676,29 @@ func (x *IbdRootUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use IbdRootUtxoSetChunkMessage.ProtoReflect.Descriptor instead. -func (*IbdRootUtxoSetChunkMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use PruningPointUtxoSetChunkMessage.ProtoReflect.Descriptor instead. +func (*PruningPointUtxoSetChunkMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{29} } -func (x *IbdRootUtxoSetChunkMessage) GetChunk() []byte { +func (x *PruningPointUtxoSetChunkMessage) GetOutpointAndUtxoEntryPairs() []*OutpointAndUtxoEntryPair { if x != nil { - return x.Chunk + return x.OutpointAndUtxoEntryPairs } return nil } -type RequestNextIbdRootUtxoSetChunkMessage struct { +type OutpointAndUtxoEntryPair struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Outpoint *Outpoint `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + UtxoEntry *UtxoEntry `protobuf:"bytes,2,opt,name=utxoEntry,proto3" json:"utxoEntry,omitempty"` } -func (x *RequestNextIbdRootUtxoSetChunkMessage) Reset() { - *x = RequestNextIbdRootUtxoSetChunkMessage{} +func (x *OutpointAndUtxoEntryPair) Reset() { + *x = OutpointAndUtxoEntryPair{} if protoimpl.UnsafeEnabled { mi := &file_p2p_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1703,13 +1706,13 @@ func (x *RequestNextIbdRootUtxoSetChunkMessage) Reset() { } } -func (x *RequestNextIbdRootUtxoSetChunkMessage) String() string { +func (x *OutpointAndUtxoEntryPair) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RequestNextIbdRootUtxoSetChunkMessage) ProtoMessage() {} +func (*OutpointAndUtxoEntryPair) ProtoMessage() {} -func (x *RequestNextIbdRootUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { +func (x *OutpointAndUtxoEntryPair) ProtoReflect() protoreflect.Message { mi := &file_p2p_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1721,19 +1724,38 @@ func (x *RequestNextIbdRootUtxoSetChunkMessage) ProtoReflect() protoreflect.Mess return mi.MessageOf(x) } -// Deprecated: Use RequestNextIbdRootUtxoSetChunkMessage.ProtoReflect.Descriptor instead. -func (*RequestNextIbdRootUtxoSetChunkMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use OutpointAndUtxoEntryPair.ProtoReflect.Descriptor instead. +func (*OutpointAndUtxoEntryPair) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{30} } -type DoneIbdRootUtxoSetChunksMessage struct { +func (x *OutpointAndUtxoEntryPair) GetOutpoint() *Outpoint { + if x != nil { + return x.Outpoint + } + return nil +} + +func (x *OutpointAndUtxoEntryPair) GetUtxoEntry() *UtxoEntry { + if x != nil { + return x.UtxoEntry + } + return nil +} + +type UtxoEntry struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Amount uint64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` + ScriptPublicKey *ScriptPublicKey `protobuf:"bytes,2,opt,name=scriptPublicKey,proto3" json:"scriptPublicKey,omitempty"` + BlockBlueScore uint64 `protobuf:"varint,3,opt,name=blockBlueScore,proto3" json:"blockBlueScore,omitempty"` + IsCoinbase bool `protobuf:"varint,4,opt,name=isCoinbase,proto3" json:"isCoinbase,omitempty"` } -func (x *DoneIbdRootUtxoSetChunksMessage) Reset() { - *x = DoneIbdRootUtxoSetChunksMessage{} +func (x *UtxoEntry) Reset() { + *x = UtxoEntry{} if protoimpl.UnsafeEnabled { mi := &file_p2p_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1741,13 +1763,13 @@ func (x *DoneIbdRootUtxoSetChunksMessage) Reset() { } } -func (x *DoneIbdRootUtxoSetChunksMessage) String() string { +func (x *UtxoEntry) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DoneIbdRootUtxoSetChunksMessage) ProtoMessage() {} +func (*UtxoEntry) ProtoMessage() {} -func (x *DoneIbdRootUtxoSetChunksMessage) ProtoReflect() protoreflect.Message { +func (x *UtxoEntry) ProtoReflect() protoreflect.Message { mi := &file_p2p_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1759,11 +1781,115 @@ func (x *DoneIbdRootUtxoSetChunksMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DoneIbdRootUtxoSetChunksMessage.ProtoReflect.Descriptor instead. -func (*DoneIbdRootUtxoSetChunksMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use UtxoEntry.ProtoReflect.Descriptor instead. +func (*UtxoEntry) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{31} } +func (x *UtxoEntry) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *UtxoEntry) GetScriptPublicKey() *ScriptPublicKey { + if x != nil { + return x.ScriptPublicKey + } + return nil +} + +func (x *UtxoEntry) GetBlockBlueScore() uint64 { + if x != nil { + return x.BlockBlueScore + } + return 0 +} + +func (x *UtxoEntry) GetIsCoinbase() bool { + if x != nil { + return x.IsCoinbase + } + return false +} + +type RequestNextPruningPointUtxoSetChunkMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RequestNextPruningPointUtxoSetChunkMessage) Reset() { + *x = RequestNextPruningPointUtxoSetChunkMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestNextPruningPointUtxoSetChunkMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestNextPruningPointUtxoSetChunkMessage) ProtoMessage() {} + +func (x *RequestNextPruningPointUtxoSetChunkMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestNextPruningPointUtxoSetChunkMessage.ProtoReflect.Descriptor instead. +func (*RequestNextPruningPointUtxoSetChunkMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{32} +} + +type DonePruningPointUtxoSetChunksMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DonePruningPointUtxoSetChunksMessage) Reset() { + *x = DonePruningPointUtxoSetChunksMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DonePruningPointUtxoSetChunksMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DonePruningPointUtxoSetChunksMessage) ProtoMessage() {} + +func (x *DonePruningPointUtxoSetChunksMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DonePruningPointUtxoSetChunksMessage.ProtoReflect.Descriptor instead. +func (*DonePruningPointUtxoSetChunksMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{33} +} + type RequestIBDBlocksMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1775,7 +1901,7 @@ type RequestIBDBlocksMessage struct { func (x *RequestIBDBlocksMessage) Reset() { *x = RequestIBDBlocksMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[32] + mi := &file_p2p_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1788,7 +1914,7 @@ func (x *RequestIBDBlocksMessage) String() string { func (*RequestIBDBlocksMessage) ProtoMessage() {} func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[32] + mi := &file_p2p_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1801,7 +1927,7 @@ func (x *RequestIBDBlocksMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestIBDBlocksMessage.ProtoReflect.Descriptor instead. func (*RequestIBDBlocksMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{32} + return file_p2p_proto_rawDescGZIP(), []int{34} } func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { @@ -1811,92 +1937,14 @@ func (x *RequestIBDBlocksMessage) GetHashes() []*Hash { return nil } -type IBDRootNotFoundMessage struct { +type UnexpectedPruningPointMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *IBDRootNotFoundMessage) Reset() { - *x = IBDRootNotFoundMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IBDRootNotFoundMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IBDRootNotFoundMessage) ProtoMessage() {} - -func (x *IBDRootNotFoundMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IBDRootNotFoundMessage.ProtoReflect.Descriptor instead. -func (*IBDRootNotFoundMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{33} -} - -type RequestIBDRootHashMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *RequestIBDRootHashMessage) Reset() { - *x = RequestIBDRootHashMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RequestIBDRootHashMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RequestIBDRootHashMessage) ProtoMessage() {} - -func (x *RequestIBDRootHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RequestIBDRootHashMessage.ProtoReflect.Descriptor instead. -func (*RequestIBDRootHashMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{34} -} - -type IBDRootHashMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` -} - -func (x *IBDRootHashMessage) Reset() { - *x = IBDRootHashMessage{} +func (x *UnexpectedPruningPointMessage) Reset() { + *x = UnexpectedPruningPointMessage{} if protoimpl.UnsafeEnabled { mi := &file_p2p_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1904,13 +1952,13 @@ func (x *IBDRootHashMessage) Reset() { } } -func (x *IBDRootHashMessage) String() string { +func (x *UnexpectedPruningPointMessage) String() string { return protoimpl.X.MessageStringOf(x) } -func (*IBDRootHashMessage) ProtoMessage() {} +func (*UnexpectedPruningPointMessage) ProtoMessage() {} -func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { +func (x *UnexpectedPruningPointMessage) ProtoReflect() protoreflect.Message { mi := &file_p2p_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1922,12 +1970,90 @@ func (x *IBDRootHashMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use IBDRootHashMessage.ProtoReflect.Descriptor instead. -func (*IBDRootHashMessage) Descriptor() ([]byte, []int) { +// Deprecated: Use UnexpectedPruningPointMessage.ProtoReflect.Descriptor instead. +func (*UnexpectedPruningPointMessage) Descriptor() ([]byte, []int) { return file_p2p_proto_rawDescGZIP(), []int{35} } -func (x *IBDRootHashMessage) GetHash() *Hash { +type RequestPruningPointHashMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RequestPruningPointHashMessage) Reset() { + *x = RequestPruningPointHashMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestPruningPointHashMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestPruningPointHashMessage) ProtoMessage() {} + +func (x *RequestPruningPointHashMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestPruningPointHashMessage.ProtoReflect.Descriptor instead. +func (*RequestPruningPointHashMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{36} +} + +type PruningPointHashMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash *Hash `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (x *PruningPointHashMessage) Reset() { + *x = PruningPointHashMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PruningPointHashMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PruningPointHashMessage) ProtoMessage() {} + +func (x *PruningPointHashMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PruningPointHashMessage.ProtoReflect.Descriptor instead. +func (*PruningPointHashMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{37} +} + +func (x *PruningPointHashMessage) GetHash() *Hash { if x != nil { return x.Hash } @@ -1946,7 +2072,7 @@ type IbdBlockLocatorMessage struct { func (x *IbdBlockLocatorMessage) Reset() { *x = IbdBlockLocatorMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[36] + mi := &file_p2p_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1959,7 +2085,7 @@ func (x *IbdBlockLocatorMessage) String() string { func (*IbdBlockLocatorMessage) ProtoMessage() {} func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[36] + mi := &file_p2p_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1972,7 +2098,7 @@ func (x *IbdBlockLocatorMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use IbdBlockLocatorMessage.ProtoReflect.Descriptor instead. func (*IbdBlockLocatorMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{36} + return file_p2p_proto_rawDescGZIP(), []int{38} } func (x *IbdBlockLocatorMessage) GetTargetHash() *Hash { @@ -2000,7 +2126,7 @@ type IbdBlockLocatorHighestHashMessage struct { func (x *IbdBlockLocatorHighestHashMessage) Reset() { *x = IbdBlockLocatorHighestHashMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[37] + mi := &file_p2p_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2013,7 +2139,7 @@ func (x *IbdBlockLocatorHighestHashMessage) String() string { func (*IbdBlockLocatorHighestHashMessage) ProtoMessage() {} func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[37] + mi := &file_p2p_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2026,7 +2152,7 @@ func (x *IbdBlockLocatorHighestHashMessage) ProtoReflect() protoreflect.Message // Deprecated: Use IbdBlockLocatorHighestHashMessage.ProtoReflect.Descriptor instead. func (*IbdBlockLocatorHighestHashMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{37} + return file_p2p_proto_rawDescGZIP(), []int{39} } func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { @@ -2047,7 +2173,7 @@ type BlockHeadersMessage struct { func (x *BlockHeadersMessage) Reset() { *x = BlockHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[38] + mi := &file_p2p_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2060,7 +2186,7 @@ func (x *BlockHeadersMessage) String() string { func (*BlockHeadersMessage) ProtoMessage() {} func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[38] + mi := &file_p2p_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2073,7 +2199,7 @@ func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{38} + return file_p2p_proto_rawDescGZIP(), []int{40} } func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { @@ -2268,54 +2394,82 @@ var file_p2p_proto_rawDesc = []byte{ 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x24, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x54, 0x58, 0x4f, 0x53, 0x65, - 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x29, 0x0a, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x07, 0x69, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x32, 0x0a, 0x1a, 0x49, - 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, - 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, - 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, - 0x27, 0x0a, 0x25, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x62, - 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, - 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x44, 0x6f, 0x6e, 0x65, - 0x49, 0x62, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, - 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x42, 0x0a, 0x17, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, - 0x18, 0x0a, 0x16, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, - 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x12, 0x49, 0x42, 0x44, 0x52, 0x6f, 0x6f, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, - 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, - 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, - 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, - 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, - 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, - 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 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, + 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x29, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, + 0x54, 0x58, 0x4f, 0x53, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x10, 0x70, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x22, 0x84, 0x01, 0x0a, 0x1f, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x61, 0x0a, 0x19, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x41, 0x6e, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x61, + 0x69, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, + 0x64, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x19, + 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x7f, 0x0a, 0x18, 0x4f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2f, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xb1, 0x01, 0x0a, 0x09, 0x55, + 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x44, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x2c, + 0x0a, 0x2a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x75, + 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x26, 0x0a, 0x24, + 0x44, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x42, 0x0a, 0x17, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x42, 0x44, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x27, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, + 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x1f, 0x0a, 0x1d, 0x55, 0x6e, 0x65, 0x78, + 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3e, 0x0a, 0x17, 0x50, + 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x8a, 0x01, 0x0a, 0x16, + 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x6f, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x21, 0x49, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, + 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, + 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, + 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 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 ( @@ -2330,47 +2484,49 @@ func file_p2p_proto_rawDescGZIP() []byte { return file_p2p_proto_rawDescData } -var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 39) +var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 41) var file_p2p_proto_goTypes = []interface{}{ - (*RequestAddressesMessage)(nil), // 0: protowire.RequestAddressesMessage - (*AddressesMessage)(nil), // 1: protowire.AddressesMessage - (*NetAddress)(nil), // 2: protowire.NetAddress - (*SubnetworkId)(nil), // 3: protowire.SubnetworkId - (*TransactionMessage)(nil), // 4: protowire.TransactionMessage - (*TransactionInput)(nil), // 5: protowire.TransactionInput - (*Outpoint)(nil), // 6: protowire.Outpoint - (*TransactionId)(nil), // 7: protowire.TransactionId - (*ScriptPublicKey)(nil), // 8: protowire.ScriptPublicKey - (*TransactionOutput)(nil), // 9: protowire.TransactionOutput - (*BlockMessage)(nil), // 10: protowire.BlockMessage - (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage - (*Hash)(nil), // 12: protowire.Hash - (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage - (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage - (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage - (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage - (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage - (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage - (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage - (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage - (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage - (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage - (*PingMessage)(nil), // 23: protowire.PingMessage - (*PongMessage)(nil), // 24: protowire.PongMessage - (*VerackMessage)(nil), // 25: protowire.VerackMessage - (*VersionMessage)(nil), // 26: protowire.VersionMessage - (*RejectMessage)(nil), // 27: protowire.RejectMessage - (*RequestIBDRootUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestIBDRootUTXOSetAndBlockMessage - (*IbdRootUtxoSetChunkMessage)(nil), // 29: protowire.IbdRootUtxoSetChunkMessage - (*RequestNextIbdRootUtxoSetChunkMessage)(nil), // 30: protowire.RequestNextIbdRootUtxoSetChunkMessage - (*DoneIbdRootUtxoSetChunksMessage)(nil), // 31: protowire.DoneIbdRootUtxoSetChunksMessage - (*RequestIBDBlocksMessage)(nil), // 32: protowire.RequestIBDBlocksMessage - (*IBDRootNotFoundMessage)(nil), // 33: protowire.IBDRootNotFoundMessage - (*RequestIBDRootHashMessage)(nil), // 34: protowire.RequestIBDRootHashMessage - (*IBDRootHashMessage)(nil), // 35: protowire.IBDRootHashMessage - (*IbdBlockLocatorMessage)(nil), // 36: protowire.IbdBlockLocatorMessage - (*IbdBlockLocatorHighestHashMessage)(nil), // 37: protowire.IbdBlockLocatorHighestHashMessage - (*BlockHeadersMessage)(nil), // 38: protowire.BlockHeadersMessage + (*RequestAddressesMessage)(nil), // 0: protowire.RequestAddressesMessage + (*AddressesMessage)(nil), // 1: protowire.AddressesMessage + (*NetAddress)(nil), // 2: protowire.NetAddress + (*SubnetworkId)(nil), // 3: protowire.SubnetworkId + (*TransactionMessage)(nil), // 4: protowire.TransactionMessage + (*TransactionInput)(nil), // 5: protowire.TransactionInput + (*Outpoint)(nil), // 6: protowire.Outpoint + (*TransactionId)(nil), // 7: protowire.TransactionId + (*ScriptPublicKey)(nil), // 8: protowire.ScriptPublicKey + (*TransactionOutput)(nil), // 9: protowire.TransactionOutput + (*BlockMessage)(nil), // 10: protowire.BlockMessage + (*BlockHeaderMessage)(nil), // 11: protowire.BlockHeaderMessage + (*Hash)(nil), // 12: protowire.Hash + (*RequestBlockLocatorMessage)(nil), // 13: protowire.RequestBlockLocatorMessage + (*BlockLocatorMessage)(nil), // 14: protowire.BlockLocatorMessage + (*RequestHeadersMessage)(nil), // 15: protowire.RequestHeadersMessage + (*RequestNextHeadersMessage)(nil), // 16: protowire.RequestNextHeadersMessage + (*DoneHeadersMessage)(nil), // 17: protowire.DoneHeadersMessage + (*RequestRelayBlocksMessage)(nil), // 18: protowire.RequestRelayBlocksMessage + (*RequestTransactionsMessage)(nil), // 19: protowire.RequestTransactionsMessage + (*TransactionNotFoundMessage)(nil), // 20: protowire.TransactionNotFoundMessage + (*InvRelayBlockMessage)(nil), // 21: protowire.InvRelayBlockMessage + (*InvTransactionsMessage)(nil), // 22: protowire.InvTransactionsMessage + (*PingMessage)(nil), // 23: protowire.PingMessage + (*PongMessage)(nil), // 24: protowire.PongMessage + (*VerackMessage)(nil), // 25: protowire.VerackMessage + (*VersionMessage)(nil), // 26: protowire.VersionMessage + (*RejectMessage)(nil), // 27: protowire.RejectMessage + (*RequestPruningPointUTXOSetAndBlockMessage)(nil), // 28: protowire.RequestPruningPointUTXOSetAndBlockMessage + (*PruningPointUtxoSetChunkMessage)(nil), // 29: protowire.PruningPointUtxoSetChunkMessage + (*OutpointAndUtxoEntryPair)(nil), // 30: protowire.OutpointAndUtxoEntryPair + (*UtxoEntry)(nil), // 31: protowire.UtxoEntry + (*RequestNextPruningPointUtxoSetChunkMessage)(nil), // 32: protowire.RequestNextPruningPointUtxoSetChunkMessage + (*DonePruningPointUtxoSetChunksMessage)(nil), // 33: protowire.DonePruningPointUtxoSetChunksMessage + (*RequestIBDBlocksMessage)(nil), // 34: protowire.RequestIBDBlocksMessage + (*UnexpectedPruningPointMessage)(nil), // 35: protowire.UnexpectedPruningPointMessage + (*RequestPruningPointHashMessage)(nil), // 36: protowire.RequestPruningPointHashMessage + (*PruningPointHashMessage)(nil), // 37: protowire.PruningPointHashMessage + (*IbdBlockLocatorMessage)(nil), // 38: protowire.IbdBlockLocatorMessage + (*IbdBlockLocatorHighestHashMessage)(nil), // 39: protowire.IbdBlockLocatorHighestHashMessage + (*BlockHeadersMessage)(nil), // 40: protowire.BlockHeadersMessage } var file_p2p_proto_depIdxs = []int32{ 3, // 0: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId @@ -2400,18 +2556,22 @@ var file_p2p_proto_depIdxs = []int32{ 7, // 24: protowire.InvTransactionsMessage.ids:type_name -> protowire.TransactionId 2, // 25: protowire.VersionMessage.address:type_name -> protowire.NetAddress 3, // 26: protowire.VersionMessage.subnetworkId:type_name -> protowire.SubnetworkId - 12, // 27: protowire.RequestIBDRootUTXOSetAndBlockMessage.ibdRoot:type_name -> protowire.Hash - 12, // 28: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash - 12, // 29: protowire.IBDRootHashMessage.hash:type_name -> protowire.Hash - 12, // 30: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash - 12, // 31: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash - 12, // 32: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash - 11, // 33: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage - 34, // [34:34] is the sub-list for method output_type - 34, // [34:34] is the sub-list for method input_type - 34, // [34:34] is the sub-list for extension type_name - 34, // [34:34] is the sub-list for extension extendee - 0, // [0:34] is the sub-list for field type_name + 12, // 27: protowire.RequestPruningPointUTXOSetAndBlockMessage.pruningPointHash:type_name -> protowire.Hash + 30, // 28: protowire.PruningPointUtxoSetChunkMessage.outpointAndUtxoEntryPairs:type_name -> protowire.OutpointAndUtxoEntryPair + 6, // 29: protowire.OutpointAndUtxoEntryPair.outpoint:type_name -> protowire.Outpoint + 31, // 30: protowire.OutpointAndUtxoEntryPair.utxoEntry:type_name -> protowire.UtxoEntry + 8, // 31: protowire.UtxoEntry.scriptPublicKey:type_name -> protowire.ScriptPublicKey + 12, // 32: protowire.RequestIBDBlocksMessage.hashes:type_name -> protowire.Hash + 12, // 33: protowire.PruningPointHashMessage.hash:type_name -> protowire.Hash + 12, // 34: protowire.IbdBlockLocatorMessage.targetHash:type_name -> protowire.Hash + 12, // 35: protowire.IbdBlockLocatorMessage.blockLocatorHashes:type_name -> protowire.Hash + 12, // 36: protowire.IbdBlockLocatorHighestHashMessage.highestHash:type_name -> protowire.Hash + 11, // 37: protowire.BlockHeadersMessage.blockHeaders:type_name -> protowire.BlockHeaderMessage + 38, // [38:38] is the sub-list for method output_type + 38, // [38:38] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_p2p_proto_init() } @@ -2757,7 +2917,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootUTXOSetAndBlockMessage); i { + switch v := v.(*RequestPruningPointUTXOSetAndBlockMessage); i { case 0: return &v.state case 1: @@ -2769,7 +2929,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdRootUtxoSetChunkMessage); i { + switch v := v.(*PruningPointUtxoSetChunkMessage); i { case 0: return &v.state case 1: @@ -2781,7 +2941,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestNextIbdRootUtxoSetChunkMessage); i { + switch v := v.(*OutpointAndUtxoEntryPair); i { case 0: return &v.state case 1: @@ -2793,7 +2953,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DoneIbdRootUtxoSetChunksMessage); i { + switch v := v.(*UtxoEntry); i { case 0: return &v.state case 1: @@ -2805,7 +2965,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDBlocksMessage); i { + switch v := v.(*RequestNextPruningPointUtxoSetChunkMessage); i { case 0: return &v.state case 1: @@ -2817,7 +2977,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootNotFoundMessage); i { + switch v := v.(*DonePruningPointUtxoSetChunksMessage); i { case 0: return &v.state case 1: @@ -2829,7 +2989,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RequestIBDRootHashMessage); i { + switch v := v.(*RequestIBDBlocksMessage); i { case 0: return &v.state case 1: @@ -2841,7 +3001,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IBDRootHashMessage); i { + switch v := v.(*UnexpectedPruningPointMessage); i { case 0: return &v.state case 1: @@ -2853,7 +3013,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorMessage); i { + switch v := v.(*RequestPruningPointHashMessage); i { case 0: return &v.state case 1: @@ -2865,7 +3025,7 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IbdBlockLocatorHighestHashMessage); i { + switch v := v.(*PruningPointHashMessage); i { case 0: return &v.state case 1: @@ -2877,6 +3037,30 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorHighestHashMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlockHeadersMessage); i { case 0: return &v.state @@ -2895,7 +3079,7 @@ func file_p2p_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_p2p_proto_rawDesc, NumEnums: 0, - NumMessages: 39, + NumMessages: 41, NumExtensions: 0, NumServices: 0, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto index 14d3e9ff1..1e729793c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto @@ -146,31 +146,43 @@ message RejectMessage{ string reason = 1; } -message RequestIBDRootUTXOSetAndBlockMessage{ - Hash ibdRoot = 1; +message RequestPruningPointUTXOSetAndBlockMessage{ + Hash pruningPointHash = 1; } -message IbdRootUtxoSetChunkMessage{ - bytes chunk = 1; +message PruningPointUtxoSetChunkMessage{ + repeated OutpointAndUtxoEntryPair outpointAndUtxoEntryPairs = 1; } -message RequestNextIbdRootUtxoSetChunkMessage { +message OutpointAndUtxoEntryPair{ + Outpoint outpoint = 1; + UtxoEntry utxoEntry = 2; } -message DoneIbdRootUtxoSetChunksMessage { +message UtxoEntry { + uint64 amount = 1; + ScriptPublicKey scriptPublicKey = 2; + uint64 blockBlueScore = 3; + bool isCoinbase = 4; +} + +message RequestNextPruningPointUtxoSetChunkMessage { +} + +message DonePruningPointUtxoSetChunksMessage { } message RequestIBDBlocksMessage{ repeated Hash hashes = 1; } -message IBDRootNotFoundMessage{ +message UnexpectedPruningPointMessage{ } -message RequestIBDRootHashMessage{ +message RequestPruningPointHashMessage{ } -message IBDRootHashMessage{ +message PruningPointHashMessage{ Hash hash = 1; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go deleted file mode 100644 index 4c9a75059..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_ibd_root_utxo_set_chunks.go +++ /dev/null @@ -1,12 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_DoneIbdRootUtxoSetChunks) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgDoneIBDRootUTXOSetChunks{}, nil -} - -func (x *KaspadMessage_DoneIbdRootUtxoSetChunks) fromAppMessage(_ *appmessage.MsgDoneIBDRootUTXOSetChunks) error { - x.DoneIbdRootUtxoSetChunks = &DoneIbdRootUtxoSetChunksMessage{} - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_pruning_point_utxo_set_chunks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_pruning_point_utxo_set_chunks.go new file mode 100644 index 000000000..8844004fb --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_done_pruning_point_utxo_set_chunks.go @@ -0,0 +1,12 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_DonePruningPointUtxoSetChunks) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgDonePruningPointUTXOSetChunks{}, nil +} + +func (x *KaspadMessage_DonePruningPointUtxoSetChunks) fromAppMessage(_ *appmessage.MsgDonePruningPointUTXOSetChunks) error { + x.DonePruningPointUtxoSetChunks = &DonePruningPointUtxoSetChunksMessage{} + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go deleted file mode 100644 index c6ff814fd..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_hash.go +++ /dev/null @@ -1,19 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_IbdRootHash) toAppMessage() (appmessage.Message, error) { - hash, err := x.IbdRootHash.Hash.toDomain() - if err != nil { - return nil, err - } - - return &appmessage.MsgIBDRootHashMessage{Hash: hash}, nil -} - -func (x *KaspadMessage_IbdRootHash) fromAppMessage(msgIBDRootHash *appmessage.MsgIBDRootHashMessage) error { - x.IbdRootHash = &IBDRootHashMessage{ - Hash: domainHashToProto(msgIBDRootHash.Hash), - } - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go deleted file mode 100644 index b22b3eecb..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_not_found.go +++ /dev/null @@ -1,11 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_IbdRootNotFound) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgIBDRootNotFound{}, nil -} - -func (x *KaspadMessage_IbdRootNotFound) fromAppMessage(_ *appmessage.MsgIBDRootNotFound) error { - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go deleted file mode 100644 index 22dcdebbe..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_root_utxo_set_chunk.go +++ /dev/null @@ -1,16 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_IbdRootUtxoSetChunk) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgIBDRootUTXOSetChunk{ - Chunk: x.IbdRootUtxoSetChunk.Chunk, - }, nil -} - -func (x *KaspadMessage_IbdRootUtxoSetChunk) fromAppMessage(message *appmessage.MsgIBDRootUTXOSetChunk) error { - x.IbdRootUtxoSetChunk = &IbdRootUtxoSetChunkMessage{ - Chunk: message.Chunk, - } - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_hash.go new file mode 100644 index 000000000..422da9a3d --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_hash.go @@ -0,0 +1,19 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_PruningPointHash) toAppMessage() (appmessage.Message, error) { + hash, err := x.PruningPointHash.Hash.toDomain() + if err != nil { + return nil, err + } + + return &appmessage.MsgPruningPointHashMessage{Hash: hash}, nil +} + +func (x *KaspadMessage_PruningPointHash) fromAppMessage(msgPruningPointHash *appmessage.MsgPruningPointHashMessage) error { + x.PruningPointHash = &PruningPointHashMessage{ + Hash: domainHashToProto(msgPruningPointHash.Hash), + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_utxo_set_chunk.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_utxo_set_chunk.go new file mode 100644 index 000000000..39773af5d --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_pruning_point_utxo_set_chunk.go @@ -0,0 +1,71 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" + "math" +) + +func (x *KaspadMessage_PruningPointUtxoSetChunk) toAppMessage() (appmessage.Message, error) { + outpointAndUTXOEntryPairs := make([]*appmessage.OutpointAndUTXOEntryPair, len(x.PruningPointUtxoSetChunk.OutpointAndUtxoEntryPairs)) + for i, outpointAndUTXOEntryPair := range x.PruningPointUtxoSetChunk.OutpointAndUtxoEntryPairs { + transactionID, err := outpointAndUTXOEntryPair.Outpoint.TransactionId.toDomain() + if err != nil { + return nil, err + } + outpoint := &appmessage.Outpoint{ + TxID: *transactionID, + Index: outpointAndUTXOEntryPair.Outpoint.Index, + } + if outpointAndUTXOEntryPair.UtxoEntry.ScriptPublicKey.Version > math.MaxUint16 { + return nil, errors.Errorf("ScriptPublicKey version is bigger then uint16.") + } + scriptPublicKey := &externalapi.ScriptPublicKey{ + Script: outpointAndUTXOEntryPair.UtxoEntry.ScriptPublicKey.Script, + Version: uint16(outpointAndUTXOEntryPair.UtxoEntry.ScriptPublicKey.Version), + } + utxoEntry := &appmessage.UTXOEntry{ + Amount: outpointAndUTXOEntryPair.UtxoEntry.Amount, + ScriptPublicKey: scriptPublicKey, + BlockBlueScore: outpointAndUTXOEntryPair.UtxoEntry.BlockBlueScore, + IsCoinbase: outpointAndUTXOEntryPair.UtxoEntry.IsCoinbase, + } + outpointAndUTXOEntryPairs[i] = &appmessage.OutpointAndUTXOEntryPair{ + Outpoint: outpoint, + UTXOEntry: utxoEntry, + } + } + return &appmessage.MsgPruningPointUTXOSetChunk{ + OutpointAndUTXOEntryPairs: outpointAndUTXOEntryPairs, + }, nil +} + +func (x *KaspadMessage_PruningPointUtxoSetChunk) fromAppMessage(message *appmessage.MsgPruningPointUTXOSetChunk) error { + outpointAndUTXOEntryPairs := make([]*OutpointAndUtxoEntryPair, len(message.OutpointAndUTXOEntryPairs)) + for i, outpointAndUTXOEntryPair := range message.OutpointAndUTXOEntryPairs { + transactionID := domainTransactionIDToProto(&outpointAndUTXOEntryPair.Outpoint.TxID) + outpoint := &Outpoint{ + TransactionId: transactionID, + Index: outpointAndUTXOEntryPair.Outpoint.Index, + } + scriptPublicKey := &ScriptPublicKey{ + Script: outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey.Script, + Version: uint32(outpointAndUTXOEntryPair.UTXOEntry.ScriptPublicKey.Version), + } + utxoEntry := &UtxoEntry{ + Amount: outpointAndUTXOEntryPair.UTXOEntry.Amount, + ScriptPublicKey: scriptPublicKey, + BlockBlueScore: outpointAndUTXOEntryPair.UTXOEntry.BlockBlueScore, + IsCoinbase: outpointAndUTXOEntryPair.UTXOEntry.IsCoinbase, + } + outpointAndUTXOEntryPairs[i] = &OutpointAndUtxoEntryPair{ + Outpoint: outpoint, + UtxoEntry: utxoEntry, + } + } + x.PruningPointUtxoSetChunk = &PruningPointUtxoSetChunkMessage{ + OutpointAndUtxoEntryPairs: outpointAndUTXOEntryPairs, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go deleted file mode 100644 index 770fb8a36..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_hash.go +++ /dev/null @@ -1,11 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_RequestIBDRootHash) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgRequestIBDRootHashMessage{}, nil -} - -func (x *KaspadMessage_RequestIBDRootHash) fromAppMessage(_ *appmessage.MsgRequestIBDRootHashMessage) error { - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go deleted file mode 100644 index d8eb8d65e..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_ibd_root_utxo_set_and_block.go +++ /dev/null @@ -1,20 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_RequestIBDRootUTXOSetAndBlock) toAppMessage() (appmessage.Message, error) { - ibdRoot, err := x.RequestIBDRootUTXOSetAndBlock.IbdRoot.toDomain() - if err != nil { - return nil, err - } - - return &appmessage.MsgRequestIBDRootUTXOSetAndBlock{IBDRoot: ibdRoot}, nil -} - -func (x *KaspadMessage_RequestIBDRootUTXOSetAndBlock) fromAppMessage( - msgRequestIBDRootUTXOSetAndBlock *appmessage.MsgRequestIBDRootUTXOSetAndBlock) error { - - x.RequestIBDRootUTXOSetAndBlock = &RequestIBDRootUTXOSetAndBlockMessage{} - x.RequestIBDRootUTXOSetAndBlock.IbdRoot = domainHashToProto(msgRequestIBDRootUTXOSetAndBlock.IBDRoot) - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go deleted file mode 100644 index fbdb88db4..000000000 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_ibd_root_utxo_set_chunk.go +++ /dev/null @@ -1,12 +0,0 @@ -package protowire - -import "github.com/kaspanet/kaspad/app/appmessage" - -func (x *KaspadMessage_RequestNextIbdRootUtxoSetChunk) toAppMessage() (appmessage.Message, error) { - return &appmessage.MsgRequestNextIBDRootUTXOSetChunk{}, nil -} - -func (x *KaspadMessage_RequestNextIbdRootUtxoSetChunk) fromAppMessage(message *appmessage.MsgRequestNextIBDRootUTXOSetChunk) error { - x.RequestNextIbdRootUtxoSetChunk = &RequestNextIbdRootUtxoSetChunkMessage{} - return nil -} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_pruning_point_utxo_set_chunk.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_pruning_point_utxo_set_chunk.go new file mode 100644 index 000000000..cb13e83f2 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_next_pruning_point_utxo_set_chunk.go @@ -0,0 +1,12 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestNextPruningPointUtxoSetChunk) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgRequestNextPruningPointUTXOSetChunk{}, nil +} + +func (x *KaspadMessage_RequestNextPruningPointUtxoSetChunk) fromAppMessage(_ *appmessage.MsgRequestNextPruningPointUTXOSetChunk) error { + x.RequestNextPruningPointUtxoSetChunk = &RequestNextPruningPointUtxoSetChunkMessage{} + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_hash.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_hash.go new file mode 100644 index 000000000..a38e1c08b --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_hash.go @@ -0,0 +1,11 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestPruningPointHash) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgRequestPruningPointHashMessage{}, nil +} + +func (x *KaspadMessage_RequestPruningPointHash) fromAppMessage(_ *appmessage.MsgRequestPruningPointHashMessage) error { + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_utxo_set_and_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_utxo_set_and_block.go new file mode 100644 index 000000000..db1908fe2 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_request_pruning_point_utxo_set_and_block.go @@ -0,0 +1,19 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_RequestPruningPointUTXOSetAndBlock) toAppMessage() (appmessage.Message, error) { + pruningPointHash, err := x.RequestPruningPointUTXOSetAndBlock.PruningPointHash.toDomain() + if err != nil { + return nil, err + } + return &appmessage.MsgRequestPruningPointUTXOSetAndBlock{PruningPointHash: pruningPointHash}, nil +} + +func (x *KaspadMessage_RequestPruningPointUTXOSetAndBlock) fromAppMessage( + msgRequestPruningPointUTXOSetAndBlock *appmessage.MsgRequestPruningPointUTXOSetAndBlock) error { + + x.RequestPruningPointUTXOSetAndBlock = &RequestPruningPointUTXOSetAndBlockMessage{} + x.RequestPruningPointUTXOSetAndBlock.PruningPointHash = domainHashToProto(msgRequestPruningPointUTXOSetAndBlock.PruningPointHash) + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_unexpected_pruning_point.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_unexpected_pruning_point.go new file mode 100644 index 000000000..5327a039a --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_unexpected_pruning_point.go @@ -0,0 +1,11 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_UnexpectedPruningPoint) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgUnexpectedPruningPoint{}, nil +} + +func (x *KaspadMessage_UnexpectedPruningPoint) fromAppMessage(_ *appmessage.MsgUnexpectedPruningPoint) error { + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index 26c7038a5..d0a8a08be 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -195,15 +195,15 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgRequestIBDRootUTXOSetAndBlock: - payload := new(KaspadMessage_RequestIBDRootUTXOSetAndBlock) + case *appmessage.MsgRequestPruningPointUTXOSetAndBlock: + payload := new(KaspadMessage_RequestPruningPointUTXOSetAndBlock) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.MsgIBDRootUTXOSetChunk: - payload := new(KaspadMessage_IbdRootUtxoSetChunk) + case *appmessage.MsgPruningPointUTXOSetChunk: + payload := new(KaspadMessage_PruningPointUtxoSetChunk) err := payload.fromAppMessage(message) if err != nil { return nil, err @@ -216,22 +216,22 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgIBDRootNotFound: - payload := new(KaspadMessage_IbdRootNotFound) + case *appmessage.MsgUnexpectedPruningPoint: + payload := new(KaspadMessage_UnexpectedPruningPoint) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.MsgRequestIBDRootHashMessage: - payload := new(KaspadMessage_RequestIBDRootHash) + case *appmessage.MsgRequestPruningPointHashMessage: + payload := new(KaspadMessage_RequestPruningPointHash) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.MsgIBDRootHashMessage: - payload := new(KaspadMessage_IbdRootHash) + case *appmessage.MsgPruningPointHashMessage: + payload := new(KaspadMessage_PruningPointHash) err := payload.fromAppMessage(message) if err != nil { return nil, err @@ -258,15 +258,15 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil - case *appmessage.MsgRequestNextIBDRootUTXOSetChunk: - payload := new(KaspadMessage_RequestNextIbdRootUtxoSetChunk) + case *appmessage.MsgRequestNextPruningPointUTXOSetChunk: + payload := new(KaspadMessage_RequestNextPruningPointUtxoSetChunk) err := payload.fromAppMessage(message) if err != nil { return nil, err } return payload, nil - case *appmessage.MsgDoneIBDRootUTXOSetChunks: - payload := new(KaspadMessage_DoneIbdRootUtxoSetChunks) + case *appmessage.MsgDonePruningPointUTXOSetChunks: + payload := new(KaspadMessage_DonePruningPointUtxoSetChunks) err := payload.fromAppMessage(message) if err != nil { return nil, err From 9a17198e7db475567b0fba90d0a60512129e1645 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 24 Jan 2021 14:14:03 +0200 Subject: [PATCH 272/351] Remove redundant type check (#1445) --- app/protocol/flows/addressexchange/sendaddresses.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/protocol/flows/addressexchange/sendaddresses.go b/app/protocol/flows/addressexchange/sendaddresses.go index f7a9cdd17..7cbdf4932 100644 --- a/app/protocol/flows/addressexchange/sendaddresses.go +++ b/app/protocol/flows/addressexchange/sendaddresses.go @@ -1,7 +1,6 @@ package addressexchange import ( - "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "math/rand" "github.com/kaspanet/kaspad/app/appmessage" @@ -17,16 +16,11 @@ type SendAddressesContext interface { // SendAddresses sends addresses to a peer that requests it. func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, outgoingRoute *router.Route) error { for { - message, err := incomingRoute.Dequeue() + _, err := incomingRoute.Dequeue() if err != nil { return err } - _, ok := message.(*appmessage.MsgRequestAddresses) - if !ok { - return protocolerrors.Errorf(true, "unexpected message. "+ - "Expected: %s, got: %s", appmessage.CmdRequestAddresses, message.Command()) - } addresses := context.AddressManager().Addresses() msgAddresses := appmessage.NewMsgAddresses(shuffleAddresses(addresses)) From ca04c049abca322f3bd41b7a746a4ab9f14b0972 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 24 Jan 2021 14:48:11 +0200 Subject: [PATCH 273/351] When the pruning point moves, update its UTXO set outside of a database transaction (#1444) * Remove pruningPointUTXOSetStaging and implement UpdatePruningPointUTXOSet. * Implement StageStartSavingNewPruningPointUTXOSet, HadStartedSavingNewPruningPointUTXOSet, and FinishSavingNewPruningPointUTXOSet. * Fix a bad return. * Implement UpdatePruningPointUTXOSetIfRequired. * Call UpdatePruningPointUTXOSetIfRequired on consensus creation. * Rename savingNewPruningPointUTXOSetKey to updatingPruningPointUTXOSet. * Add a log. * Add calls to runtime.GC() at its start and end. * Rename a variable. * Replace calls to runtime.GC to calls to LogMemoryStats. * Wrap the contents of LogMemoryStats in a log closure. --- .../pruningstore/pruningstore.go | 102 +++++++++++------- domain/consensus/factory.go | 4 + .../interface_datastructures_pruningstore.go | 7 +- .../interface_processes_pruningmanager.go | 1 + .../blockprocessor/validateandinsertblock.go | 5 + .../pruningmanager/pruningmanager.go | 64 +++++++++-- infrastructure/logger/utils.go | 12 +++ 7 files changed, 144 insertions(+), 51 deletions(-) diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index aa0e1367f..6cb29cbc7 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -11,6 +11,7 @@ import ( var pruningBlockHashKey = database.MakeBucket(nil).Key([]byte("pruning-block-hash")) var candidatePruningPointHashKey = database.MakeBucket(nil).Key([]byte("candidate-pruning-point-hash")) var pruningPointUTXOSetBucket = database.MakeBucket([]byte("pruning-point-utxo-set")) +var updatingPruningPointUTXOSetKey = database.MakeBucket(nil).Key([]byte("updating-pruning-point-utxo-set")) // pruningStore represents a store for the current pruning state type pruningStore struct { @@ -19,7 +20,7 @@ type pruningStore struct { pruningPointCandidateStaging *externalapi.DomainHash pruningPointCandidateCache *externalapi.DomainHash - pruningPointUTXOSetStaging model.ReadOnlyUTXOSetIterator + startUpdatingPruningPointUTXOSetStaging bool } // New instantiates a new PruningStore @@ -70,17 +71,13 @@ func (ps *pruningStore) StagePruningPoint(pruningPointBlockHash *externalapi.Dom ps.pruningPointStaging = pruningPointBlockHash } -func (ps *pruningStore) StagePruningPointUTXOSet(pruningPointUTXOSetIterator model.ReadOnlyUTXOSetIterator) { - ps.pruningPointUTXOSetStaging = pruningPointUTXOSetIterator -} - func (ps *pruningStore) IsStaged() bool { - return ps.pruningPointStaging != nil || ps.pruningPointUTXOSetStaging != nil + return ps.pruningPointStaging != nil || ps.startUpdatingPruningPointUTXOSetStaging } func (ps *pruningStore) Discard() { ps.pruningPointStaging = nil - ps.pruningPointUTXOSetStaging = nil + ps.startUpdatingPruningPointUTXOSetStaging = false } func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { @@ -108,49 +105,60 @@ func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { ps.pruningPointCandidateCache = ps.pruningPointCandidateStaging } - if ps.pruningPointUTXOSetStaging != nil { - // Delete all the old UTXOs from the database - deleteCursor, err := dbTx.Cursor(pruningPointUTXOSetBucket) + if ps.startUpdatingPruningPointUTXOSetStaging { + err := dbTx.Put(updatingPruningPointUTXOSetKey, []byte{0}) if err != nil { return err } - for ok := deleteCursor.First(); ok; ok = deleteCursor.Next() { - key, err := deleteCursor.Key() - if err != nil { - return err - } - err = dbTx.Delete(key) - if err != nil { - return err - } - } - - // Insert all the new UTXOs into the database - for ok := ps.pruningPointUTXOSetStaging.First(); ok; ok = ps.pruningPointUTXOSetStaging.Next() { - outpoint, entry, err := ps.pruningPointUTXOSetStaging.Get() - if err != nil { - return err - } - serializedOutpoint, err := serializeOutpoint(outpoint) - if err != nil { - return err - } - key := pruningPointUTXOSetBucket.Key(serializedOutpoint) - serializedUTXOEntry, err := serializeUTXOEntry(entry) - if err != nil { - return err - } - err = dbTx.Put(key, serializedUTXOEntry) - if err != nil { - return err - } - } } ps.Discard() return nil } +func (ps *pruningStore) UpdatePruningPointUTXOSet(dbContext model.DBWriter, + utxoSetIterator model.ReadOnlyUTXOSetIterator) error { + + // Delete all the old UTXOs from the database + deleteCursor, err := dbContext.Cursor(pruningPointUTXOSetBucket) + if err != nil { + return err + } + for ok := deleteCursor.First(); ok; ok = deleteCursor.Next() { + key, err := deleteCursor.Key() + if err != nil { + return err + } + err = dbContext.Delete(key) + if err != nil { + return err + } + } + + // Insert all the new UTXOs into the database + for ok := utxoSetIterator.First(); ok; ok = utxoSetIterator.Next() { + outpoint, entry, err := utxoSetIterator.Get() + if err != nil { + return err + } + serializedOutpoint, err := serializeOutpoint(outpoint) + if err != nil { + return err + } + key := pruningPointUTXOSetBucket.Key(serializedOutpoint) + serializedUTXOEntry, err := serializeUTXOEntry(entry) + if err != nil { + return err + } + err = dbContext.Put(key, serializedUTXOEntry) + if err != nil { + return err + } + } + + return nil +} + // PruningPoint gets the current pruning point func (ps *pruningStore) PruningPoint(dbContext model.DBReader) (*externalapi.DomainHash, error) { if ps.pruningPointStaging != nil { @@ -241,3 +249,15 @@ func (ps *pruningStore) PruningPointUTXOs(dbContext model.DBReader, } return outpointAndUTXOEntryPairs, nil } + +func (ps *pruningStore) StageStartUpdatingPruningPointUTXOSet() { + ps.startUpdatingPruningPointUTXOSetStaging = true +} + +func (ps *pruningStore) HadStartedUpdatingPruningPointUTXOSet(dbContext model.DBWriter) (bool, error) { + return dbContext.Has(updatingPruningPointUTXOSetKey) +} + +func (ps *pruningStore) FinishUpdatingPruningPointUTXOSet(dbContext model.DBWriter) error { + return dbContext.Delete(updatingPruningPointUTXOSetKey) +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 993464989..96a72c928 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -365,6 +365,10 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat if err != nil { return nil, err } + err = pruningManager.UpdatePruningPointUTXOSetIfRequired() + if err != nil { + return nil, err + } return c, nil } diff --git a/domain/consensus/model/interface_datastructures_pruningstore.go b/domain/consensus/model/interface_datastructures_pruningstore.go index e8149e975..6fce5098d 100644 --- a/domain/consensus/model/interface_datastructures_pruningstore.go +++ b/domain/consensus/model/interface_datastructures_pruningstore.go @@ -6,13 +6,18 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type PruningStore interface { Store StagePruningPoint(pruningPointBlockHash *externalapi.DomainHash) - StagePruningPointUTXOSet(pruningPointUTXOSetIterator ReadOnlyUTXOSetIterator) StagePruningPointCandidate(candidate *externalapi.DomainHash) IsStaged() bool PruningPointCandidate(dbContext DBReader) (*externalapi.DomainHash, error) HasPruningPointCandidate(dbContext DBReader) (bool, error) PruningPoint(dbContext DBReader) (*externalapi.DomainHash, error) HasPruningPoint(dbContext DBReader) (bool, error) + + StageStartUpdatingPruningPointUTXOSet() + HadStartedUpdatingPruningPointUTXOSet(dbContext DBWriter) (bool, error) + FinishUpdatingPruningPointUTXOSet(dbContext DBWriter) error + UpdatePruningPointUTXOSet(dbContext DBWriter, utxoSetIterator ReadOnlyUTXOSetIterator) error + ClearImportedPruningPointUTXOs(dbContext DBWriter) error AppendImportedPruningPointUTXOs(dbTx DBTransaction, outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error ImportedPruningPointUTXOIterator(dbContext DBReader) (ReadOnlyUTXOSetIterator, error) diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index effefcbfe..75d907f82 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -8,4 +8,5 @@ type PruningManager interface { IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) ClearImportedPruningPointData() error AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error + UpdatePruningPointUTXOSetIfRequired() error } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 7b232e43b..528826ee6 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -117,6 +117,11 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, return nil, err } + err = bp.pruningManager.UpdatePruningPointUTXOSetIfRequired() + if err != nil { + return nil, err + } + log.Debug(logger.NewLogClosure(func() string { hashrate := difficulty.GetHashrateString(difficulty.CompactToBig(block.Header.Bits()), bp.targetTimePerBlock) return fmt.Sprintf("Block %s validated and inserted, network hashrate: %s", blockHash, hashrate) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 6479a2810..ab789b682 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -311,20 +311,15 @@ func (pm *pruningManager) savePruningPoint(pruningPointHash *externalapi.DomainH onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.savePruningPoint") defer onEnd() - utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPointHash) - if err != nil { - return err - } - // TODO: This is an assert that takes ~30 seconds to run // It must be removed or optimized before launching testnet - err = pm.validateUTXOSetFitsCommitment(utxoSetIterator, pruningPointHash) + err := pm.validateUTXOSetFitsCommitment(pruningPointHash) if err != nil { return err } pm.pruningStore.StagePruningPoint(pruningPointHash) - pm.pruningStore.StagePruningPointUTXOSet(utxoSetIterator) + pm.pruningStore.StageStartUpdatingPruningPointUTXOSet() return nil } @@ -417,8 +412,11 @@ func (pm *pruningManager) pruningPointCandidate() (*externalapi.DomainHash, erro // validateUTXOSetFitsCommitment makes sure that the calculated UTXOSet of the new pruning point fits the commitment. // This is a sanity test, to make sure that kaspad doesn't store, and subsequently sends syncing peers the wrong UTXOSet. -func (pm *pruningManager) validateUTXOSetFitsCommitment(utxoSetIterator model.ReadOnlyUTXOSetIterator, - pruningPointHash *externalapi.DomainHash) error { +func (pm *pruningManager) validateUTXOSetFitsCommitment(pruningPointHash *externalapi.DomainHash) error { + utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPointHash) + if err != nil { + return err + } utxoSetMultiset := multiset.New() for ok := utxoSetIterator.First(); ok; ok = utxoSetIterator.Next() { @@ -500,3 +498,51 @@ func (pm *pruningManager) AppendImportedPruningPointUTXOs( return dbTx.Commit() } + +func (pm *pruningManager) UpdatePruningPointUTXOSetIfRequired() error { + hadStartedUpdatingPruningPointUTXOSet, err := pm.pruningStore.HadStartedUpdatingPruningPointUTXOSet(pm.databaseContext) + if err != nil { + return err + } + if !hadStartedUpdatingPruningPointUTXOSet { + return nil + } + + log.Debugf("Pruning point UTXO set update is required") + err = pm.updatePruningPointUTXOSet() + if err != nil { + return err + } + log.Debugf("Pruning point UTXO set updated") + + return nil +} + +func (pm *pruningManager) updatePruningPointUTXOSet() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "updatePruningPointUTXOSet") + defer onEnd() + + logger.LogMemoryStats(log, "updatePruningPointUTXOSet start") + defer logger.LogMemoryStats(log, "updatePruningPointUTXOSet end") + + log.Debugf("Getting the pruning point") + pruningPoint, err := pm.pruningStore.PruningPoint(pm.databaseContext) + if err != nil { + return err + } + + log.Debugf("Restoring the pruning point UTXO set") + utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPoint) + if err != nil { + return err + } + + log.Debugf("Updating the pruning point UTXO set") + err = pm.pruningStore.UpdatePruningPointUTXOSet(pm.databaseContext, utxoSetIterator) + if err != nil { + return err + } + + log.Debugf("Finishing updating the pruning point UTXO set") + return pm.pruningStore.FinishUpdatingPruningPointUTXOSet(pm.databaseContext) +} diff --git a/infrastructure/logger/utils.go b/infrastructure/logger/utils.go index c383a00a8..1ba315d55 100644 --- a/infrastructure/logger/utils.go +++ b/infrastructure/logger/utils.go @@ -1,6 +1,8 @@ package logger import ( + "fmt" + "runtime" "time" ) @@ -15,3 +17,13 @@ func LogAndMeasureExecutionTime(log *Logger, functionName string) (onEnd func()) log.Debugf("%s end. Took: %s", functionName, time.Since(start)) } } + +// LogMemoryStats logs memory stats for `functionName` +func LogMemoryStats(log *Logger, functionName string) { + log.Debug(NewLogClosure(func() string { + stats := runtime.MemStats{} + runtime.ReadMemStats(&stats) + return fmt.Sprintf("%s: used memory: %d bytes, total: %d bytes", functionName, + stats.Alloc, stats.HeapIdle-stats.HeapReleased+stats.HeapInuse) + })) +} From 7ea8a72a9ebdf54eb76f889da7f1c32ad12951b6 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Sun, 24 Jan 2021 17:35:20 +0200 Subject: [PATCH 274/351] Add TestReceiveAddressesErrors (#1446) * Add TestReceiveAddressesErrors * Change errors to be more descriptive * Fix checkFlowError --- .../flows/addressexchange/receiveaddresses.go | 2 - .../addressexchange/receiveaddresses_test.go | 68 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 app/protocol/flows/addressexchange/receiveaddresses_test.go diff --git a/app/protocol/flows/addressexchange/receiveaddresses.go b/app/protocol/flows/addressexchange/receiveaddresses.go index 779ab7714..366f350b0 100644 --- a/app/protocol/flows/addressexchange/receiveaddresses.go +++ b/app/protocol/flows/addressexchange/receiveaddresses.go @@ -5,14 +5,12 @@ import ( "github.com/kaspanet/kaspad/app/protocol/common" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" - "github.com/kaspanet/kaspad/infrastructure/config" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) // ReceiveAddressesContext is the interface for the context needed for the ReceiveAddresses flow. type ReceiveAddressesContext interface { - Config() *config.Config AddressManager() *addressmanager.AddressManager } diff --git a/app/protocol/flows/addressexchange/receiveaddresses_test.go b/app/protocol/flows/addressexchange/receiveaddresses_test.go new file mode 100644 index 000000000..7b104052e --- /dev/null +++ b/app/protocol/flows/addressexchange/receiveaddresses_test.go @@ -0,0 +1,68 @@ +package addressexchange_test + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/flows/addressexchange" + peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/pkg/errors" + "strings" + "testing" + "time" +) + +type fakeReceiveAddressesContext struct{} + +func (f fakeReceiveAddressesContext) AddressManager() *addressmanager.AddressManager { + return nil +} + +func checkFlowError(t *testing.T, err error, isProtocolError bool, shouldBan bool, contains string) { + pErr := &protocolerrors.ProtocolError{} + if errors.As(err, &pErr) != isProtocolError { + t.Fatalf("Unexepcted error %+v", err) + } + + if pErr.ShouldBan != shouldBan { + t.Fatalf("Exepcted shouldBan %t but got %t", shouldBan, pErr.ShouldBan) + } + + if !strings.Contains(err.Error(), contains) { + t.Fatalf("Unexpected error: %+v", err) + } +} + +func TestReceiveAddressesErrors(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + incomingRoute := router.NewRoute() + outgoingRoute := router.NewRoute() + peer := peerpkg.New(nil) + errChan := make(chan error) + go func() { + errChan <- addressexchange.ReceiveAddresses(fakeReceiveAddressesContext{}, incomingRoute, outgoingRoute, peer) + }() + + _, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + // Sending addressmanager.GetAddressesMax+1 addresses should trigger a ban + err = incomingRoute.Enqueue(appmessage.NewMsgAddresses(make([]*appmessage.NetAddress, + addressmanager.GetAddressesMax+1))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + select { + case err := <-errChan: + checkFlowError(t, err, true, true, "address count exceeded") + case <-time.After(time.Second): + t.Fatalf("timed out after %s", time.Second) + } + }) +} From 819ec9f2a7cb13e6d90bc5aebbd4b3edc4a0e8dc Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 25 Jan 2021 13:38:59 +0200 Subject: [PATCH 275/351] Pass fromOutpoint into GetPruningPointUTXOs instead of offset, so it could Seek over the cursor (#1447) * Implement TestGetPruningPointUTXOs. * Fix a bad error message. * Fix TestGetPruningPointUTXOs for testnet. * Make sure all the UTXOs are returned in TestGetPruningPointUTXOs. * Implement BenchmarkGetPruningPointUTXOs. * Pass fromOutpoint into GetPruningPointUTXOs instead of offset, so it could Seek over the cursor. * Fix weird benchmark timer calls. * Remove unnecessary collection of outpointAndUTXOEntryPairs from BenchmarkGetPruningPointUTXOs. * Fix a comment. --- ...equest_pruning_point_utxo_set_and_block.go | 7 +- domain/consensus/consensus.go | 4 +- .../pruningstore/pruningstore.go | 18 +- .../consensus/model/externalapi/consensus.go | 2 +- .../interface_datastructures_pruningstore.go | 2 +- ...idateandinsertimportedpruningpoint_test.go | 274 +++++++++++++++++- 6 files changed, 293 insertions(+), 14 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go b/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go index bb4bc1452..ee4024a06 100644 --- a/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go +++ b/app/protocol/flows/blockrelay/handle_request_pruning_point_utxo_set_and_block.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/app/protocol/common" "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" @@ -96,11 +97,11 @@ func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) sendPruningPointUTXOSe // Send the UTXO set in `step`-sized chunks const step = 1000 - offset := 0 + var fromOutpoint *externalapi.DomainOutpoint chunksSent := 0 for { pruningPointUTXOs, err := flow.Domain().Consensus().GetPruningPointUTXOs( - msgRequestPruningPointUTXOSetAndBlock.PruningPointHash, offset, step) + msgRequestPruningPointUTXOSetAndBlock.PruningPointHash, fromOutpoint, step) if err != nil { if errors.Is(err, ruleerrors.ErrWrongPruningPointHash) { return flow.outgoingRoute.Enqueue(appmessage.NewMsgUnexpectedPruningPoint()) @@ -124,7 +125,7 @@ func (flow *handleRequestPruningPointUTXOSetAndBlockFlow) sendPruningPointUTXOSe return flow.outgoingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) } - offset += step + fromOutpoint = pruningPointUTXOs[len(pruningPointUTXOs)-1].Outpoint chunksSent++ // Wait for the peer to request more chunks every `ibdBatchSize` chunks diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index d66b71be1..77dc480ec 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -200,7 +200,7 @@ func (s *consensus) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) } func (s *consensus) GetPruningPointUTXOs(expectedPruningPointHash *externalapi.DomainHash, - offset int, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { + fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { s.lock.Lock() defer s.lock.Unlock() @@ -216,7 +216,7 @@ func (s *consensus) GetPruningPointUTXOs(expectedPruningPointHash *externalapi.D pruningPointHash) } - pruningPointUTXOs, err := s.pruningStore.PruningPointUTXOs(s.databaseContext, offset, limit) + pruningPointUTXOs, err := s.pruningStore.PruningPointUTXOs(s.databaseContext, fromOutpoint, limit) if err != nil { return nil, err } diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index 6cb29cbc7..e2b9088e2 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -223,19 +223,27 @@ func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader) (bool, error) } func (ps *pruningStore) PruningPointUTXOs(dbContext model.DBReader, - offset int, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { + fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { cursor, err := dbContext.Cursor(pruningPointUTXOSetBucket) if err != nil { return nil, err } - pruningPointUTXOIterator := ps.newCursorUTXOSetIterator(cursor) - offsetIndex := 0 - for offsetIndex < offset && pruningPointUTXOIterator.Next() { - offsetIndex++ + if fromOutpoint != nil { + serializedFromOutpoint, err := serializeOutpoint(fromOutpoint) + if err != nil { + return nil, err + } + seekKey := pruningPointUTXOSetBucket.Key(serializedFromOutpoint) + err = cursor.Seek(seekKey) + if err != nil { + return nil, err + } } + pruningPointUTXOIterator := ps.newCursorUTXOSetIterator(cursor) + outpointAndUTXOEntryPairs := make([]*externalapi.OutpointAndUTXOEntryPair, 0, limit) for len(outpointAndUTXOEntryPairs) < limit && pruningPointUTXOIterator.Next() { outpoint, utxoEntry, err := pruningPointUTXOIterator.Get() diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index e832d6aff..88927f288 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -13,7 +13,7 @@ type Consensus interface { GetHashesBetween(lowHash, highHash *DomainHash, maxBlueScoreDifference uint64) ([]*DomainHash, error) GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error) - GetPruningPointUTXOs(expectedPruningPointHash *DomainHash, offset int, limit int) ([]*OutpointAndUTXOEntryPair, error) + GetPruningPointUTXOs(expectedPruningPointHash *DomainHash, fromOutpoint *DomainOutpoint, limit int) ([]*OutpointAndUTXOEntryPair, error) PruningPoint() (*DomainHash, error) ClearImportedPruningPointData() error AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*OutpointAndUTXOEntryPair) error diff --git a/domain/consensus/model/interface_datastructures_pruningstore.go b/domain/consensus/model/interface_datastructures_pruningstore.go index 6fce5098d..886442d7d 100644 --- a/domain/consensus/model/interface_datastructures_pruningstore.go +++ b/domain/consensus/model/interface_datastructures_pruningstore.go @@ -25,5 +25,5 @@ type PruningStore interface { ImportedPruningPointMultiset(dbContext DBReader) (Multiset, error) UpdateImportedPruningPointMultiset(dbTx DBTransaction, multiset Multiset) error CommitImportedPruningPointUTXOSet(dbContext DBWriter) error - PruningPointUTXOs(dbContext DBReader, offset int, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) + PruningPointUTXOs(dbContext DBReader, fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go index 70fade737..d70f3401d 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint_test.go @@ -6,7 +6,9 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/pkg/errors" @@ -92,7 +94,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) { t.Fatalf("Unexpected pruning point %s", pruningPoint) } - pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, 0, 1000) + pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, nil, 1000) if err != nil { t.Fatalf("GetPruningPointUTXOs: %+v", err) } @@ -270,7 +272,7 @@ func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) { t.Fatalf("Unexpected pruning point %s", pruningPoint) } - pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, 0, 1000) + pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, nil, 1000) if err != nil { t.Fatalf("GetPruningPointUTXOs: %+v", err) } @@ -414,3 +416,271 @@ func makeFakeUTXOs() []*externalapi.OutpointAndUTXOEntryPair { }, } } + +func TestGetPruningPointUTXOs(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + // This is done to reduce the pruning depth to 8 blocks + finalityDepth := 4 + params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock + params.K = 0 + + params.BlockCoinbaseMaturity = 0 + + factory := consensus.NewFactory() + testConsensus, teardown, err := factory.NewTestConsensus(params, false, "TestGetPruningPointUTXOs") + if err != nil { + t.Fatalf("Error setting up testConsensus: %+v", err) + } + defer teardown(false) + + // Create a block that accepts the genesis coinbase so that we won't have script problems down the line + emptyCoinbase := &externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } + blockAboveGeneis, err := testConsensus.BuildBlock(emptyCoinbase, nil) + if err != nil { + t.Fatalf("Error building block above genesis: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(blockAboveGeneis) + if err != nil { + t.Fatalf("Error validating and inserting block above genesis: %+v", err) + } + + // Create a block whose coinbase we could spend + scriptPublicKey, redeemScript := testutils.OpTrueScript() + coinbaseData := &externalapi.DomainCoinbaseData{ScriptPublicKey: scriptPublicKey} + blockWithSpendableCoinbase, err := testConsensus.BuildBlock(coinbaseData, nil) + if err != nil { + t.Fatalf("Error building block with spendable coinbase: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(blockWithSpendableCoinbase) + if err != nil { + t.Fatalf("Error validating and inserting block with spendable coinbase: %+v", err) + } + + // Create a transaction that adds a lot of UTXOs to the UTXO set + transactionToSpend := blockWithSpendableCoinbase.Transactions[0] + signatureScript, err := txscript.PayToScriptHashSignatureScript(redeemScript, nil) + if err != nil { + t.Fatalf("Error creating signature script: %+v", err) + } + input := &externalapi.DomainTransactionInput{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: *consensushashing.TransactionID(transactionToSpend), + Index: 0, + }, + SignatureScript: signatureScript, + Sequence: constants.MaxTxInSequenceNum, + } + + outputs := make([]*externalapi.DomainTransactionOutput, 1125) + for i := 0; i < len(outputs); i++ { + outputs[i] = &externalapi.DomainTransactionOutput{ + ScriptPublicKey: scriptPublicKey, + Value: 10000, + } + } + spendingTransaction := &externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{input}, + Outputs: outputs, + Payload: []byte{}, + } + + // Create a block with that includes the above transaction + includingBlock, err := testConsensus.BuildBlock(emptyCoinbase, []*externalapi.DomainTransaction{spendingTransaction}) + if err != nil { + t.Fatalf("Error building including block: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(includingBlock) + if err != nil { + t.Fatalf("Error validating and inserting including block: %+v", err) + } + + // Add enough blocks to move the pruning point + for { + block, err := testConsensus.BuildBlock(emptyCoinbase, nil) + if err != nil { + t.Fatalf("Error building block: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(block) + if err != nil { + t.Fatalf("Error validating and inserting block: %+v", err) + } + + pruningPoint, err := testConsensus.PruningPoint() + if err != nil { + t.Fatalf("Error getting the pruning point: %+v", err) + } + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + pruningPoint, err := testConsensus.PruningPoint() + if err != nil { + t.Fatalf("Error getting the pruning point: %+v", err) + } + + // Get pruning point UTXOs in a loop + var allOutpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair + step := 100 + var fromOutpoint *externalapi.DomainOutpoint + for { + outpointAndUTXOEntryPairs, err := testConsensus.GetPruningPointUTXOs(pruningPoint, fromOutpoint, step) + if err != nil { + t.Fatalf("Error getting pruning point UTXOs: %+v", err) + } + allOutpointAndUTXOEntryPairs = append(allOutpointAndUTXOEntryPairs, outpointAndUTXOEntryPairs...) + fromOutpoint = outpointAndUTXOEntryPairs[len(outpointAndUTXOEntryPairs)-1].Outpoint + + if len(outpointAndUTXOEntryPairs) < step { + break + } + } + + // Make sure the length of the UTXOs is exactly spendingTransaction.Outputs + 2 coinbase outputs + if len(allOutpointAndUTXOEntryPairs) != len(outputs)+2 { + t.Fatalf("Returned an unexpected amount of UTXOs. "+ + "Want: %d, got: %d", len(outputs)+2, len(allOutpointAndUTXOEntryPairs)) + } + + // Make sure all spendingTransaction.Outputs are in the returned UTXOs + spendingTransactionID := consensushashing.TransactionID(spendingTransaction) + for i := range outputs { + found := false + for _, outpointAndUTXOEntryPair := range allOutpointAndUTXOEntryPairs { + outpoint := outpointAndUTXOEntryPair.Outpoint + if outpoint.TransactionID == *spendingTransactionID && outpoint.Index == uint32(i) { + found = true + break + } + } + if !found { + t.Fatalf("Outpoint %s:%d not found amongst the returned UTXOs", spendingTransactionID, i) + } + } + }) +} + +func BenchmarkGetPruningPointUTXOs(b *testing.B) { + params := dagconfig.DevnetParams + + // This is done to reduce the pruning depth to 200 blocks + finalityDepth := 100 + params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock + params.K = 0 + + params.SkipProofOfWork = true + params.BlockCoinbaseMaturity = 0 + + factory := consensus.NewFactory() + testConsensus, teardown, err := factory.NewTestConsensus(¶ms, false, "TestGetPruningPointUTXOs") + if err != nil { + b.Fatalf("Error setting up testConsensus: %+v", err) + } + defer teardown(false) + + // Create a block whose coinbase we could spend + scriptPublicKey, redeemScript := testutils.OpTrueScript() + coinbaseData := &externalapi.DomainCoinbaseData{ScriptPublicKey: scriptPublicKey} + blockWithSpendableCoinbase, err := testConsensus.BuildBlock(coinbaseData, nil) + if err != nil { + b.Fatalf("Error building block with spendable coinbase: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(blockWithSpendableCoinbase) + if err != nil { + b.Fatalf("Error validating and inserting block with spendable coinbase: %+v", err) + } + + addBlockWithLotsOfOutputs := func(b *testing.B, transactionToSpend *externalapi.DomainTransaction) *externalapi.DomainBlock { + // Create a transaction that adds a lot of UTXOs to the UTXO set + signatureScript, err := txscript.PayToScriptHashSignatureScript(redeemScript, nil) + if err != nil { + b.Fatalf("Error creating signature script: %+v", err) + } + input := &externalapi.DomainTransactionInput{ + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: *consensushashing.TransactionID(transactionToSpend), + Index: 0, + }, + SignatureScript: signatureScript, + Sequence: constants.MaxTxInSequenceNum, + } + outputs := make([]*externalapi.DomainTransactionOutput, 1125) + for i := 0; i < len(outputs); i++ { + outputs[i] = &externalapi.DomainTransactionOutput{ + ScriptPublicKey: scriptPublicKey, + Value: 10000, + } + } + transaction := &externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{input}, + Outputs: outputs, + Payload: []byte{}, + } + + // Create a block that includes the above transaction + block, err := testConsensus.BuildBlock(coinbaseData, []*externalapi.DomainTransaction{transaction}) + if err != nil { + b.Fatalf("Error building block: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(block) + if err != nil { + b.Fatalf("Error validating and inserting block: %+v", err) + } + + return block + } + + // Add finalityDepth blocks, each containing lots of outputs + tip := blockWithSpendableCoinbase + for i := 0; i < finalityDepth; i++ { + tip = addBlockWithLotsOfOutputs(b, tip.Transactions[0]) + } + + // Add enough blocks to move the pruning point + for { + block, err := testConsensus.BuildBlock(coinbaseData, nil) + if err != nil { + b.Fatalf("Error building block: %+v", err) + } + _, err = testConsensus.ValidateAndInsertBlock(block) + if err != nil { + b.Fatalf("Error validating and inserting block: %+v", err) + } + + pruningPoint, err := testConsensus.PruningPoint() + if err != nil { + b.Fatalf("Error getting the pruning point: %+v", err) + } + if !pruningPoint.Equal(params.GenesisHash) { + break + } + } + pruningPoint, err := testConsensus.PruningPoint() + if err != nil { + b.Fatalf("Error getting the pruning point: %+v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Get pruning point UTXOs in a loop + step := 100 + var fromOutpoint *externalapi.DomainOutpoint + for { + outpointAndUTXOEntryPairs, err := testConsensus.GetPruningPointUTXOs(pruningPoint, fromOutpoint, step) + if err != nil { + b.Fatalf("Error getting pruning point UTXOs: %+v", err) + } + fromOutpoint = outpointAndUTXOEntryPairs[len(outpointAndUTXOEntryPairs)-1].Outpoint + + if len(outpointAndUTXOEntryPairs) < step { + break + } + } + } +} From ed85f097421e06345e6b855a1b5d6598a804e7f6 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 25 Jan 2021 16:41:43 +0200 Subject: [PATCH 276/351] Add P2P/RPC name to the gRPC logs (#1448) * Add P2P/RPC name to the gRPC logs * Add p2p/rpc name in more logs --- .../netadapter/server/grpcserver/grpc_server.go | 16 +++++++++------- .../netadapter/server/grpcserver/p2pserver.go | 12 ++++++------ .../netadapter/server/grpcserver/rpcserver.go | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go index ed4870eb5..3a5dd8737 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go @@ -15,14 +15,16 @@ type gRPCServer struct { onConnectedHandler server.OnConnectedHandler listeningAddresses []string server *grpc.Server + name string } // newGRPCServer creates a gRPC server -func newGRPCServer(listeningAddresses []string, maxMessageSize int) *gRPCServer { - log.Debugf("Created new GRPC server with maxMessageSize %d", maxMessageSize) +func newGRPCServer(listeningAddresses []string, maxMessageSize int, name string) *gRPCServer { + log.Debugf("Created new %s GRPC server with maxMessageSize %d", name, maxMessageSize) return &gRPCServer{ server: grpc.NewServer(grpc.MaxRecvMsgSize(maxMessageSize), grpc.MaxSendMsgSize(maxMessageSize)), listeningAddresses: listeningAddresses, + name: name, } } @@ -44,17 +46,17 @@ func (s *gRPCServer) Start() error { func (s *gRPCServer) listenOn(listenAddr string) error { listener, err := net.Listen("tcp", listenAddr) if err != nil { - return errors.Wrapf(err, "error listening on %s", listenAddr) + return errors.Wrapf(err, "%s error listening on %s", s.name, listenAddr) } - spawn("gRPCServer.listenOn-Serve", func() { + spawn(fmt.Sprintf("%s.gRPCServer.listenOn-Serve", s.name), func() { err := s.server.Serve(listener) if err != nil { - panics.Exit(log, fmt.Sprintf("error serving on %s: %+v", listenAddr, err)) + panics.Exit(log, fmt.Sprintf("error serving %s on %s: %+v", s.name, listenAddr, err)) } }) - log.Infof("Server listening on %s", listenAddr) + log.Infof("%s Server listening on %s", s.name, listenAddr) return nil } @@ -86,7 +88,7 @@ func (s *gRPCServer) handleInboundConnection(ctx context.Context, stream grpcStr return err } - log.Infof("Incoming connection from %s", peerInfo.Addr) + log.Infof("%s Incoming connection from %s", s.name, peerInfo.Addr) <-connection.stopChan diff --git a/infrastructure/network/netadapter/server/grpcserver/p2pserver.go b/infrastructure/network/netadapter/server/grpcserver/p2pserver.go index 9500be622..c9baedf8c 100644 --- a/infrastructure/network/netadapter/server/grpcserver/p2pserver.go +++ b/infrastructure/network/netadapter/server/grpcserver/p2pserver.go @@ -22,7 +22,7 @@ const p2pMaxMessageSize = 10 * 1024 * 1024 // 10MB // NewP2PServer creates a new P2PServer func NewP2PServer(listeningAddresses []string) (server.P2PServer, error) { - gRPCServer := newGRPCServer(listeningAddresses, p2pMaxMessageSize) + gRPCServer := newGRPCServer(listeningAddresses, p2pMaxMessageSize, "P2P") p2pServer := &p2pServer{gRPCServer: *gRPCServer} protowire.RegisterP2PServer(gRPCServer.server, p2pServer) return p2pServer, nil @@ -37,7 +37,7 @@ func (p *p2pServer) MessageStream(stream protowire.P2P_MessageStreamServer) erro // Connect connects to the given address // This is part of the P2PServer interface func (p *p2pServer) Connect(address string) (server.Connection, error) { - log.Infof("Dialing to %s", address) + log.Infof("%s Dialing to %s", p.name, address) const dialTimeout = 30 * time.Second ctx, cancel := context.WithTimeout(context.Background(), dialTimeout) @@ -45,19 +45,19 @@ func (p *p2pServer) Connect(address string) (server.Connection, error) { gRPCClientConnection, err := grpc.DialContext(ctx, address, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { - return nil, errors.Wrapf(err, "error connecting to %s", address) + return nil, errors.Wrapf(err, "%s error connecting to %s", p.name, address) } client := protowire.NewP2PClient(gRPCClientConnection) stream, err := client.MessageStream(context.Background(), grpc.UseCompressor(gzip.Name), grpc.MaxCallRecvMsgSize(p2pMaxMessageSize), grpc.MaxCallSendMsgSize(p2pMaxMessageSize)) if err != nil { - return nil, errors.Wrapf(err, "error getting client stream for %s", address) + return nil, errors.Wrapf(err, "%s error getting client stream for %s", p.name, address) } peerInfo, ok := peer.FromContext(stream.Context()) if !ok { - return nil, errors.Errorf("error getting stream peer info from context for %s", address) + return nil, errors.Errorf("%s error getting stream peer info from context for %s", p.name, address) } tcpAddress, ok := peerInfo.Addr.(*net.TCPAddr) if !ok { @@ -71,7 +71,7 @@ func (p *p2pServer) Connect(address string) (server.Connection, error) { return nil, err } - log.Infof("Connected to %s", address) + log.Infof("%s Connected to %s", p.name, address) return connection, nil } diff --git a/infrastructure/network/netadapter/server/grpcserver/rpcserver.go b/infrastructure/network/netadapter/server/grpcserver/rpcserver.go index 420cc0dae..233129ecd 100644 --- a/infrastructure/network/netadapter/server/grpcserver/rpcserver.go +++ b/infrastructure/network/netadapter/server/grpcserver/rpcserver.go @@ -16,7 +16,7 @@ const RPCMaxMessageSize = 1024 * 1024 * 1024 // 1 GB // NewRPCServer creates a new RPCServer func NewRPCServer(listeningAddresses []string) (server.Server, error) { - gRPCServer := newGRPCServer(listeningAddresses, RPCMaxMessageSize) + gRPCServer := newGRPCServer(listeningAddresses, RPCMaxMessageSize, "RPC") rpcServer := &rpcServer{gRPCServer: *gRPCServer} protowire.RegisterRPCServer(gRPCServer.server, rpcServer) return rpcServer, nil From 52da65077aa76a3d394cf8872263721cc85d5f58 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 25 Jan 2021 16:58:11 +0200 Subject: [PATCH 277/351] codecov: Ignore protobuf autogenerated files (#1449) --- .codecov.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codecov.yml b/.codecov.yml index 483eab35b..9d9d28251 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -5,3 +5,5 @@ coverage: project: default: informational: true +ignore: + - "**/*.pb.go" # Ignore all auto generated protobuf structures. \ No newline at end of file From ddfe376388b438c517c0bff9737bd197ddb7bbe6 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 26 Jan 2021 08:42:04 +0200 Subject: [PATCH 278/351] Don't ban peers that sent a requested duplicate block (#1440) * Ignore ErrDuplicateBlock for any blocks that were requested * Don't check for DuplicateBlockErr in processHeaders + improve logs * Return the check for ErrDuplicateBlock in processHeader * Fix log message --- .../flows/blockrelay/handle_relay_invs.go | 4 ++++ app/protocol/flows/blockrelay/ibd.go | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index ae1005688..e359febc9 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -109,6 +109,10 @@ func (flow *handleRelayInvsFlow) start() error { log.Debugf("Processing block %s", inv.Hash) missingParents, blockInsertionResult, err := flow.processBlock(block) if err != nil { + if errors.Is(err, ruleerrors.ErrDuplicateBlock) { + log.Infof("Ignoring duplicate block %s", inv.Hash) + continue + } return err } if len(missingParents) > 0 { diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 75a36212f..ef72eca37 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -2,9 +2,10 @@ package blockrelay import ( "fmt" - "github.com/kaspanet/kaspad/infrastructure/logger" "time" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/app/appmessage" @@ -279,9 +280,13 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo if !errors.As(err, &ruleerrors.RuleError{}) { return errors.Wrapf(err, "failed to process header %s during IBD", blockHash) } - log.Infof("Rejected block header %s from %s during IBD: %s", blockHash, flow.peer, err) - return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", blockHash) + if errors.Is(err, ruleerrors.ErrDuplicateBlock) { + log.Debugf("Skipping block header %s as it is a duplicate", blockHash) + } else { + log.Infof("Rejected block header %s from %s during IBD: %s", blockHash, flow.peer, err) + return protocolerrors.Wrapf(true, err, "got invalid block header %s during IBD", blockHash) + } } return nil @@ -493,6 +498,10 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { + if errors.Is(err, ruleerrors.ErrDuplicateBlock) { + log.Debugf("Skipping IBD Block %s as it has already been added to the DAG", blockHash) + continue + } return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash) } err = flow.OnNewBlock(block, blockInsertionResult) From 1742e76af795fed78d6ab13706e3dd7d1ceb63db Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Tue, 26 Jan 2021 13:31:28 +0200 Subject: [PATCH 279/351] Add TestHandleRelayInvsErrors (#1450) --- .../flows/blockrelay/handle_relay_invs.go | 2 - app/protocol/flows/blockrelay/ibd.go | 4 + app/protocol/flows/testing/common_test.go | 23 + .../flows/testing/handle_relay_invs_test.go | 986 ++++++++++++++++++ .../receiveaddresses_test.go | 20 +- 5 files changed, 1014 insertions(+), 21 deletions(-) create mode 100644 app/protocol/flows/testing/common_test.go create mode 100644 app/protocol/flows/testing/handle_relay_invs_test.go rename app/protocol/flows/{addressexchange => testing}/receiveaddresses_test.go (73%) diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index e359febc9..95e445a82 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -10,7 +10,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/infrastructure/config" - "github.com/kaspanet/kaspad/infrastructure/network/netadapter" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/pkg/errors" ) @@ -24,7 +23,6 @@ var orphanResolutionRange uint32 = 5 type RelayInvsContext interface { Domain() domain.Domain Config() *config.Config - NetAdapter() *netadapter.NetAdapter OnNewBlock(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error SharedRequestedBlocks() *SharedRequestedBlocks Broadcast(message appmessage.Message) error diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index ef72eca37..f4f413c3d 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -313,6 +313,10 @@ func (flow *handleRelayInvsFlow) syncPruningPointUTXOSet() (bool, error) { return false, err } + if !blockInfo.Exists { + return false, errors.Errorf("The pruning point header is missing") + } + if blockInfo.BlockStatus != externalapi.StatusHeaderOnly { log.Debugf("Already has the block data of the new suggested pruning point %s", msgPruningPointHash.Hash) return true, nil diff --git a/app/protocol/flows/testing/common_test.go b/app/protocol/flows/testing/common_test.go new file mode 100644 index 000000000..3d5fdaa96 --- /dev/null +++ b/app/protocol/flows/testing/common_test.go @@ -0,0 +1,23 @@ +package testing + +import ( + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" + "github.com/pkg/errors" + "strings" + "testing" +) + +func checkFlowError(t *testing.T, err error, isProtocolError bool, shouldBan bool, contains string) { + pErr := &protocolerrors.ProtocolError{} + if errors.As(err, &pErr) != isProtocolError { + t.Fatalf("Unexepcted error %+v", err) + } + + if pErr.ShouldBan != shouldBan { + t.Fatalf("Exepcted shouldBan %t but got %t", shouldBan, pErr.ShouldBan) + } + + if !strings.Contains(err.Error(), contains) { + t.Fatalf("Unexpected error. Expected error to contain '%s' but got: %+v", contains, err) + } +} diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go new file mode 100644 index 000000000..6b55b0728 --- /dev/null +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -0,0 +1,986 @@ +package testing + +import ( + "fmt" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/flows/blockrelay" + peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/domain/miningmanager" + "github.com/kaspanet/kaspad/infrastructure/config" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/kaspanet/kaspad/util/mstime" + "testing" + "time" +) + +var orphanBlock = &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{unknownBlockHash}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), +} + +var validPruningPointBlock = &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), +} + +var invalidPruningPointBlock = &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2})}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), +} + +var unexpectedIBDBlock = &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3})}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), +} + +var invalidBlock = &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4})}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), +} + +var unknownBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}) +var knownInvalidBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}) +var validPruningPointHash = consensushashing.BlockHash(validPruningPointBlock) +var invalidBlockHash = consensushashing.BlockHash(invalidBlock) +var invalidPruningPointHash = consensushashing.BlockHash(invalidPruningPointBlock) +var orphanBlockHash = consensushashing.BlockHash(orphanBlock) + +var fakeRelayInvsContextMap = map[externalapi.DomainHash]*externalapi.BlockInfo{ + *knownInvalidBlockHash: { + Exists: true, + BlockStatus: externalapi.StatusInvalid, + }, + *validPruningPointHash: { + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + }, + *invalidPruningPointHash: { + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + }, +} + +type fakeRelayInvsContext struct { + params *dagconfig.Params + askedOrphanBlockInfo bool +} + +func (f *fakeRelayInvsContext) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) { + hash := consensushashing.BlockHash(block) + if hash.Equal(orphanBlockHash) { + return nil, ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes()) + } + + if hash.Equal(invalidBlockHash) { + return nil, ruleerrors.ErrBadMerkleRoot + } + + return nil, nil +} + +func (f *fakeRelayInvsContext) ValidateTransactionAndPopulateWithConsensusData(transaction *externalapi.DomainTransaction) error { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetBlockHeader(blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) { + if info, ok := fakeRelayInvsContextMap[*blockHash]; ok { + return info, nil + } + + // Second time we ask for orphan block it's in the end of IBD, to + // check if the IBD has finished. + // Since we don't actually process headers, we just say the orphan + // exists in the second time we're asked about it to indicate IBD + // has finished. + if blockHash.Equal(orphanBlockHash) { + if f.askedOrphanBlockInfo { + return &externalapi.BlockInfo{Exists: true}, nil + } + f.askedOrphanBlockInfo = true + } + + return &externalapi.BlockInfo{ + Exists: false, + }, nil +} + +func (f *fakeRelayInvsContext) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + // This is done so we can test getting invalid block during IBD. + return []*externalapi.DomainHash{invalidBlockHash}, nil +} + +func (f *fakeRelayInvsContext) GetPruningPointUTXOs(expectedPruningPointHash *externalapi.DomainHash, fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) PruningPoint() (*externalapi.DomainHash, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) ClearImportedPruningPointData() error { + return nil +} + +func (f *fakeRelayInvsContext) AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) ValidateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error { + if consensushashing.BlockHash(newPruningPoint).Equal(invalidPruningPointHash) { + return ruleerrors.ErrBadMerkleRoot + } + + return nil +} + +func (f *fakeRelayInvsContext) GetVirtualSelectedParent() (*externalapi.DomainHash, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + return externalapi.BlockLocator{ + f.params.GenesisHash, + }, nil +} + +func (f *fakeRelayInvsContext) CreateFullHeadersSelectedChainBlockLocator() (externalapi.BlockLocator, error) { + return externalapi.BlockLocator{ + f.params.GenesisHash, + }, nil +} + +func (f *fakeRelayInvsContext) GetSyncInfo() (*externalapi.SyncInfo, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) Tips() ([]*externalapi.DomainHash, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetVirtualInfo() (*externalapi.VirtualInfo, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) { + return true, nil +} + +func (f *fakeRelayInvsContext) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) IsInSelectedParentChainOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) MiningManager() miningmanager.MiningManager { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) Consensus() externalapi.Consensus { + return f +} + +func (f *fakeRelayInvsContext) Domain() domain.Domain { + return f +} + +func (f *fakeRelayInvsContext) Config() *config.Config { + return &config.Config{ + Flags: &config.Flags{ + NetworkFlags: config.NetworkFlags{ + ActiveNetParams: f.params, + }, + }, + } +} + +func (f *fakeRelayInvsContext) OnNewBlock(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks { + return blockrelay.NewSharedRequestedBlocks() +} + +func (f *fakeRelayInvsContext) Broadcast(message appmessage.Message) error { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) GetOrphanRoots(orphanHash *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error) { + panic("unimplemented") +} + +func (f *fakeRelayInvsContext) IsOrphan(blockHash *externalapi.DomainHash) bool { + return false +} + +func (f *fakeRelayInvsContext) IsIBDRunning() bool { + return false +} + +func (f *fakeRelayInvsContext) TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool { + return true +} + +func (f *fakeRelayInvsContext) UnsetIBDRunning() { +} + +func TestHandleRelayInvsErrors(t *testing.T) { + triggerIBD := func(incomingRoute, outgoingRoute *router.Route) { + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(consensushashing.BlockHash(orphanBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestRelayBlocks) + + err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestBlockLocator) + + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + } + + tests := []struct { + name string + funcToExecute func(incomingRoute, outgoingRoute *router.Route) + expectsProtocolError bool + expectsBan bool + expectsErrToContain string + }{ + { + name: "sending unexpected message type", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + err := incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "message in the block relay handleRelayInvsFlow while expecting an inv message", + }, + { + name: "sending a known invalid inv", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(knownInvalidBlockHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "sent inv of an invalid block", + }, + { + name: "sending unrequested block", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(unknownBlockHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestRelayBlocks) + + err = incomingRoute.Enqueue(appmessage.NewMsgBlock(&appmessage.MsgBlockHeader{ + Version: 0, + ParentHashes: nil, + HashMerkleRoot: &externalapi.DomainHash{}, + AcceptedIDMerkleRoot: &externalapi.DomainHash{}, + UTXOCommitment: &externalapi.DomainHash{}, + Timestamp: mstime.Time{}, + Bits: 0, + Nonce: 0, + })) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "got unrequested block", + }, + { + name: "sending invalid block", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(invalidBlockHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestRelayBlocks) + + err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(invalidBlock)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "got invalid block", + }, + { + name: "sending unexpected message instead of block locator", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(consensushashing.BlockHash(orphanBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestRelayBlocks) + + err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestBlockLocator) + + // Sending a block while expected a block locator + err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", + appmessage.CmdBlockLocator), + }, + { + name: "sending unknown highest hash", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgIBDBlockLocator) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(unknownBlockHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "is not in the original blockLocator", + }, + { + name: "sending unexpected type instead of highest hash", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgIBDBlockLocator) + + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", + appmessage.CmdIBDBlockLocatorHighestHash), + }, + { + name: "sending unexpected type instead of a header", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + // Sending unrequested block locator + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s or %s", + appmessage.CmdHeader, appmessage.CmdDoneHeaders), + }, + { + name: "sending unexpected type instead of pruning point hash", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + // Sending unrequested block locator + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", + appmessage.CmdPruningPointHash), + }, + { + name: "sending unexpected type instead of pruning point block", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + // Sending unrequested block locator + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", + appmessage.CmdIBDBlock), + }, + { + name: "sending unexpected type instead of UTXO chunk", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + // Sending unrequested block locator + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. "+ + "expected: %s or %s or %s", appmessage.CmdPruningPointUTXOSetChunk, + appmessage.CmdDonePruningPointUTXOSetChunks, appmessage.CmdUnexpectedPruningPoint), + }, + { + name: "sending invalid pruning point", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(invalidPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "error with pruning point UTXO set", + }, + { + name: "sending unexpected type instead of IBD block", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestIBDBlocks) + + // Sending unrequested block locator + err = incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", + appmessage.CmdIBDBlock), + }, + { + name: "sending unexpected IBD block", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestIBDBlocks) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(unexpectedIBDBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "expected block", + }, + { + name: "sending invalid IBD block", + funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + triggerIBD(incomingRoute, outgoingRoute) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestIBDBlocks) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(invalidBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "invalid block", + }, + } + + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + for _, test := range tests { + incomingRoute := router.NewRoute() + outgoingRoute := router.NewRoute() + peer := peerpkg.New(nil) + errChan := make(chan error) + go func() { + errChan <- blockrelay.HandleRelayInvs(&fakeRelayInvsContext{ + params: params, + }, incomingRoute, outgoingRoute, peer) + }() + + test.funcToExecute(incomingRoute, outgoingRoute) + + select { + case err := <-errChan: + checkFlowError(t, err, test.expectsProtocolError, test.expectsBan, test.expectsErrToContain) + case <-time.After(time.Second): + t.Fatalf("timed out after %s", time.Second) + } + } + }) +} diff --git a/app/protocol/flows/addressexchange/receiveaddresses_test.go b/app/protocol/flows/testing/receiveaddresses_test.go similarity index 73% rename from app/protocol/flows/addressexchange/receiveaddresses_test.go rename to app/protocol/flows/testing/receiveaddresses_test.go index 7b104052e..b38b3fec4 100644 --- a/app/protocol/flows/addressexchange/receiveaddresses_test.go +++ b/app/protocol/flows/testing/receiveaddresses_test.go @@ -1,16 +1,13 @@ -package addressexchange_test +package testing import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/flows/addressexchange" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" - "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/network/addressmanager" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" - "github.com/pkg/errors" - "strings" "testing" "time" ) @@ -21,21 +18,6 @@ func (f fakeReceiveAddressesContext) AddressManager() *addressmanager.AddressMan return nil } -func checkFlowError(t *testing.T, err error, isProtocolError bool, shouldBan bool, contains string) { - pErr := &protocolerrors.ProtocolError{} - if errors.As(err, &pErr) != isProtocolError { - t.Fatalf("Unexepcted error %+v", err) - } - - if pErr.ShouldBan != shouldBan { - t.Fatalf("Exepcted shouldBan %t but got %t", shouldBan, pErr.ShouldBan) - } - - if !strings.Contains(err.Error(), contains) { - t.Fatalf("Unexpected error: %+v", err) - } -} - func TestReceiveAddressesErrors(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { incomingRoute := router.NewRoute() From fb11981da1210f71f9f103db5229863ad64f3c95 Mon Sep 17 00:00:00 2001 From: Svarog Date: Tue, 26 Jan 2021 14:22:35 +0200 Subject: [PATCH 280/351] Make kaspactl usable by human beings (#1452) * Add request_types and their help * Added command parser * Updated main to use command if it's specified * Some progress in making everything work * Fix command parser for pointers to structs * Cleanup code * Enhance usage text * Fixed typo * Some minor style fixing, and remove temporary code * Correctly fallthrough in stringToValue unsupported types Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/appmessage/rpc_get_block.go | 4 +- cmd/kaspactl/command_parser.go | 171 ++++ cmd/kaspactl/commands.go | 87 ++ cmd/kaspactl/config.go | 26 +- cmd/kaspactl/main.go | 62 +- cmd/kaspactl/reflection_helpers.go | 46 ++ .../server/grpcserver/protowire/rpc.pb.go | 768 +++++++++--------- .../server/grpcserver/protowire/rpc.proto | 1 - .../grpcserver/protowire/rpc_get_block.go | 5 +- .../network/rpcclient/rpc_get_block.go | 4 +- 10 files changed, 755 insertions(+), 419 deletions(-) create mode 100644 cmd/kaspactl/command_parser.go create mode 100644 cmd/kaspactl/commands.go create mode 100644 cmd/kaspactl/reflection_helpers.go diff --git a/app/appmessage/rpc_get_block.go b/app/appmessage/rpc_get_block.go index 9742da509..ec334c648 100644 --- a/app/appmessage/rpc_get_block.go +++ b/app/appmessage/rpc_get_block.go @@ -5,7 +5,6 @@ package appmessage type GetBlockRequestMessage struct { baseMessage Hash string - SubnetworkID string IncludeTransactionVerboseData bool } @@ -15,10 +14,9 @@ func (msg *GetBlockRequestMessage) Command() MessageCommand { } // NewGetBlockRequestMessage returns a instance of the message -func NewGetBlockRequestMessage(hash string, subnetworkID string, includeTransactionVerboseData bool) *GetBlockRequestMessage { +func NewGetBlockRequestMessage(hash string, includeTransactionVerboseData bool) *GetBlockRequestMessage { return &GetBlockRequestMessage{ Hash: hash, - SubnetworkID: subnetworkID, IncludeTransactionVerboseData: includeTransactionVerboseData, } } diff --git a/cmd/kaspactl/command_parser.go b/cmd/kaspactl/command_parser.go new file mode 100644 index 000000000..ee74bfc6b --- /dev/null +++ b/cmd/kaspactl/command_parser.go @@ -0,0 +1,171 @@ +package main + +import ( + "reflect" + "strconv" + + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver/protowire" + "github.com/pkg/errors" +) + +func parseCommand(args []string, commandDescs []*commandDescription) (*protowire.KaspadMessage, error) { + commandName, parameterStrings := args[0], args[1:] + + var commandDesc *commandDescription + for _, cd := range commandDescs { + if cd.name == commandName { + commandDesc = cd + break + } + } + if commandDesc == nil { + return nil, errors.Errorf("unknown command: %s. Use --list-commands to list all commands", commandName) + } + if len(parameterStrings) != len(commandDesc.parameters) { + return nil, errors.Errorf("command '%s' expects %d parameters but got %d", + commandName, len(commandDesc.parameters), len(parameterStrings)) + } + + commandValue := reflect.New(unwrapCommandType(commandDesc.typeof)) + for i, parameterDesc := range commandDesc.parameters { + parameterValue, err := stringToValue(parameterDesc, parameterStrings[i]) + if err != nil { + return nil, err + } + setField(commandValue, parameterValue, parameterDesc) + } + + return generateKaspadMessage(commandValue, commandDesc) +} + +func setField(commandValue reflect.Value, parameterValue reflect.Value, parameterDesc *parameterDescription) { + parameterField := commandValue.Elem().FieldByName(parameterDesc.name) + + parameterField.Set(parameterValue) +} + +func stringToValue(parameterDesc *parameterDescription, valueStr string) (reflect.Value, error) { + var value interface{} + var err error + switch parameterDesc.typeof.Kind() { + case reflect.Bool: + value, err = strconv.ParseBool(valueStr) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + case reflect.Int8: + var valueInt64 int64 + valueInt64, err = strconv.ParseInt(valueStr, 10, 8) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = int8(valueInt64) + case reflect.Int16: + var valueInt64 int64 + valueInt64, err = strconv.ParseInt(valueStr, 10, 16) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = int16(valueInt64) + case reflect.Int32: + var valueInt64 int64 + valueInt64, err = strconv.ParseInt(valueStr, 10, 32) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = int32(valueInt64) + case reflect.Int64: + value, err = strconv.ParseInt(valueStr, 10, 64) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + case reflect.Uint8: + var valueUInt64 uint64 + valueUInt64, err = strconv.ParseUint(valueStr, 10, 8) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = uint8(valueUInt64) + case reflect.Uint16: + var valueUInt64 uint64 + valueUInt64, err = strconv.ParseUint(valueStr, 10, 16) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = uint16(valueUInt64) + case reflect.Uint32: + var valueUInt64 uint64 + valueUInt64, err = strconv.ParseUint(valueStr, 10, 32) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = uint32(valueUInt64) + case reflect.Uint64: + value, err = strconv.ParseUint(valueStr, 10, 64) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + case reflect.Float32: + var valueFloat64 float64 + valueFloat64, err = strconv.ParseFloat(valueStr, 32) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + value = float32(valueFloat64) + case reflect.Float64: + value, err = strconv.ParseFloat(valueStr, 64) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + case reflect.String: + value = valueStr + case reflect.Struct: + pointer := reflect.New(parameterDesc.typeof) // create pointer to this type + fieldInterface := pointer.Interface().(proto.Message) + err := protojson.Unmarshal([]byte(valueStr), fieldInterface) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + // Unpointer the value once it's ready + fieldInterfaceValue := reflect.ValueOf(fieldInterface) + value = fieldInterfaceValue.Elem().Interface() + case reflect.Ptr: + dummyParameterDesc := ¶meterDescription{ + name: "valuePointedTo", + typeof: parameterDesc.typeof.Elem(), + } + valuePointedTo, err := stringToValue(dummyParameterDesc, valueStr) + if err != nil { + return reflect.Value{}, errors.WithStack(err) + } + pointer := pointerToValue(valuePointedTo) + + value = pointer.Interface() + + // Int and uint are not supported because their size is platform-dependant + case reflect.Int, + reflect.Uint, + // Other types are not supported simply because they are not used in any command right now + // but support can be added if and when needed + reflect.Slice, + reflect.Func, + reflect.Interface, + reflect.Map, + reflect.UnsafePointer, + reflect.Invalid, + reflect.Uintptr, + reflect.Complex64, + reflect.Complex128, + reflect.Array, + reflect.Chan: + fallthrough + default: + return reflect.Value{}, + errors.Errorf("Unsupported type '%s' for parameter '%s'", parameterDesc.typeof.Kind(), parameterDesc.name) + } + + return reflect.ValueOf(value), nil +} diff --git a/cmd/kaspactl/commands.go b/cmd/kaspactl/commands.go new file mode 100644 index 000000000..db3e2a5a9 --- /dev/null +++ b/cmd/kaspactl/commands.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + "reflect" + "strings" + + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver/protowire" +) + +var commandTypes = []reflect.Type{ + reflect.TypeOf(protowire.KaspadMessage_AddPeerRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetConnectedPeerInfoRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetPeerAddressesRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetCurrentNetworkRequest{}), + + reflect.TypeOf(protowire.KaspadMessage_GetBlockRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetBlocksRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetHeadersRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetBlockCountRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetBlockDagInfoRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetSelectedTipHashRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetVirtualSelectedParentBlueScoreRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetVirtualSelectedParentChainFromBlockRequest{}), + reflect.TypeOf(protowire.KaspadMessage_ResolveFinalityConflictRequest{}), + + reflect.TypeOf(protowire.KaspadMessage_GetBlockTemplateRequest{}), + reflect.TypeOf(protowire.KaspadMessage_SubmitBlockRequest{}), + + reflect.TypeOf(protowire.KaspadMessage_GetMempoolEntryRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetMempoolEntriesRequest{}), + reflect.TypeOf(protowire.KaspadMessage_SubmitTransactionRequest{}), + + reflect.TypeOf(protowire.KaspadMessage_GetUtxosByAddressesRequest{}), +} + +type commandDescription struct { + name string + parameters []*parameterDescription + typeof reflect.Type +} + +type parameterDescription struct { + name string + typeof reflect.Type +} + +func commandDescriptions() []*commandDescription { + commandDescriptions := make([]*commandDescription, len(commandTypes)) + + for i, commandTypeWrapped := range commandTypes { + commandType := unwrapCommandType(commandTypeWrapped) + + name := strings.TrimSuffix(commandType.Name(), "RequestMessage") + numFields := commandType.NumField() + + var parameters []*parameterDescription + for i := 0; i < numFields; i++ { + field := commandType.Field(i) + + if !isFieldExported(field) { + continue + } + + parameters = append(parameters, ¶meterDescription{ + name: field.Name, + typeof: field.Type, + }) + } + commandDescriptions[i] = &commandDescription{ + name: name, + parameters: parameters, + typeof: commandTypeWrapped, + } + } + + return commandDescriptions +} + +func (cd *commandDescription) help() string { + sb := &strings.Builder{} + sb.WriteString(cd.name) + for _, parameter := range cd.parameters { + _, _ = fmt.Fprintf(sb, " [%s]", parameter.name) + } + return sb.String() +} diff --git a/cmd/kaspactl/config.go b/cmd/kaspactl/config.go index b1dfa1f82..0b240529a 100644 --- a/cmd/kaspactl/config.go +++ b/cmd/kaspactl/config.go @@ -12,9 +12,11 @@ var ( ) type configFlags struct { - RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` - Timeout uint64 `short:"t" long:"timeout" description:"Timeout for the request (in seconds)"` - RequestJSON string `description:"The request in JSON format"` + RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` + Timeout uint64 `short:"t" long:"timeout" description:"Timeout for the request (in seconds)"` + RequestJSON string `short:"j" long:"json" description:"The request in JSON format"` + ListCommands bool `short:"l" long:"list-commands" description:"List all commands and exit"` + CommandAndParameters []string config.NetworkFlags } @@ -23,21 +25,29 @@ func parseConfig() (*configFlags, error) { RPCServer: defaultRPCServer, Timeout: defaultTimeout, } - parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag) - args, err := parser.Parse() + parser := flags.NewParser(cfg, flags.HelpFlag) + parser.Usage = "kaspactl [OPTIONS] [COMMAND] [COMMAND PARAMETERS].\n\nCommand can be supplied only if --json is not used." + + "\n\nUse `kaspactl --list-commands` to get a list of all commands and their parameters" + remainingArgs, err := parser.Parse() if err != nil { return nil, err } + if cfg.ListCommands { + return cfg, nil + } + err = cfg.ResolveNetwork(parser) if err != nil { return nil, err } - if len(args) != 1 { - return nil, errors.New("the last parameter must be the request in JSON format") + cfg.CommandAndParameters = remainingArgs + if len(cfg.CommandAndParameters) == 0 && cfg.RequestJSON == "" || + len(cfg.CommandAndParameters) > 0 && cfg.RequestJSON != "" { + + return nil, errors.New("Exactly one of --json or a command must be specified") } - cfg.RequestJSON = args[0] return cfg, nil } diff --git a/cmd/kaspactl/main.go b/cmd/kaspactl/main.go index b16574c9d..5f4998dc8 100644 --- a/cmd/kaspactl/main.go +++ b/cmd/kaspactl/main.go @@ -2,9 +2,13 @@ package main import ( "fmt" - "github.com/kaspanet/kaspad/infrastructure/network/rpcclient/grpcclient" "os" "time" + + "github.com/pkg/errors" + "google.golang.org/protobuf/encoding/protojson" + + "github.com/kaspanet/kaspad/infrastructure/network/rpcclient/grpcclient" ) func main() { @@ -12,6 +16,10 @@ func main() { if err != nil { printErrorAndExit(fmt.Sprintf("error parsing command-line arguments: %s", err)) } + if cfg.ListCommands { + printAllCommands() + return + } rpcAddress, err := cfg.NetParams().NormalizeRPCServerAddress(cfg.RPCServer) if err != nil { @@ -23,28 +31,56 @@ func main() { } defer client.Disconnect() - var responseString string - done := make(chan struct{}) + responseChan := make(chan string) - go func() { - requestString := cfg.RequestJSON - var err error - responseString, err = client.PostJSON(requestString) - if err != nil { - printErrorAndExit(fmt.Sprintf("error posting the request to the RPC server: %s", err)) - } - done <- struct{}{} - }() + if cfg.RequestJSON != "" { + go postJSON(cfg, client, responseChan) + } else { + go postCommand(cfg, client, responseChan) + } timeout := time.Duration(cfg.Timeout) * time.Second select { - case <-done: + case responseString := <-responseChan: fmt.Println(responseString) case <-time.After(timeout): printErrorAndExit(fmt.Sprintf("timeout of %s has been exceeded", timeout)) } } +func printAllCommands() { + requestDescs := commandDescriptions() + for _, requestDesc := range requestDescs { + fmt.Printf("\t%s\n", requestDesc.help()) + } +} + +func postCommand(cfg *configFlags, client *grpcclient.GRPCClient, responseChan chan string) { + message, err := parseCommand(cfg.CommandAndParameters, commandDescriptions()) + if err != nil { + printErrorAndExit(fmt.Sprintf("error parsing command: %s", err)) + } + + response, err := client.Post(message) + if err != nil { + printErrorAndExit(fmt.Sprintf("error posting the request to the RPC server: %s", err)) + } + responseBytes, err := protojson.Marshal(response) + if err != nil { + printErrorAndExit(errors.Wrapf(err, "error parsing the response from the RPC server").Error()) + } + + responseChan <- string(responseBytes) +} + +func postJSON(cfg *configFlags, client *grpcclient.GRPCClient, doneChan chan string) { + responseString, err := client.PostJSON(cfg.RequestJSON) + if err != nil { + printErrorAndExit(fmt.Sprintf("error posting the request to the RPC server: %s", err)) + } + doneChan <- responseString +} + func printErrorAndExit(message string) { fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", message)) os.Exit(1) diff --git a/cmd/kaspactl/reflection_helpers.go b/cmd/kaspactl/reflection_helpers.go new file mode 100644 index 000000000..491229287 --- /dev/null +++ b/cmd/kaspactl/reflection_helpers.go @@ -0,0 +1,46 @@ +package main + +import ( + "reflect" + "unicode" + + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver/protowire" +) + +// protobuf generates the command types with two types: +// 1. A concrete type that holds the fields of the command bearing the name of the command with `RequestMessage` as suffix +// 2. A wrapper that implements isKaspadMessage_Payload, having a single field pointing to the concrete command +// bearing the name of the command with `KaspadMessage_` prefix and `Request` suffix + +// unwrapCommandType converts a reflect.Type signifying a wrapper type into the concrete request type +func unwrapCommandType(requestTypeWrapped reflect.Type) reflect.Type { + return requestTypeWrapped.Field(0).Type.Elem() +} + +// unwrapCommandValue convertes a reflect.Value of a pointer to a wrapped command into a concrete command +func unwrapCommandValue(commandValueWrapped reflect.Value) reflect.Value { + return commandValueWrapped.Elem().Field(0) +} + +// isFieldExported returns true if the given field is exported. +// Currently the only way to check this is to check if the first rune in the field's name is upper case. +func isFieldExported(field reflect.StructField) bool { + return unicode.IsUpper(rune(field.Name[0])) +} + +// generateKaspadMessage generates a wrapped KaspadMessage with the given `commandValue` +func generateKaspadMessage(commandValue reflect.Value, commandDesc *commandDescription) (*protowire.KaspadMessage, error) { + commandWrapper := reflect.New(commandDesc.typeof) + unwrapCommandValue(commandWrapper).Set(commandValue) + + kaspadMessage := reflect.New(reflect.TypeOf(protowire.KaspadMessage{})) + kaspadMessage.Elem().FieldByName("Payload").Set(commandWrapper) + return kaspadMessage.Interface().(*protowire.KaspadMessage), nil +} + +// pointerToValue returns a reflect.Value that represents a pointer to the given value +func pointerToValue(valuePointedTo reflect.Value) reflect.Value { + pointer := reflect.New(valuePointedTo.Type()) + pointer.Elem().Set(valuePointedTo) + return pointer +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 7aa17abad..5bb291b95 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -1780,8 +1780,7 @@ type GetBlockRequestMessage struct { unknownFields protoimpl.UnknownFields // The hash of the requested block - Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` - SubnetworkId string `protobuf:"bytes,2,opt,name=subnetworkId,proto3" json:"subnetworkId,omitempty"` + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` // Whether to include transaction data in the response IncludeTransactionVerboseData bool `protobuf:"varint,3,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` } @@ -1825,13 +1824,6 @@ func (x *GetBlockRequestMessage) GetHash() string { return "" } -func (x *GetBlockRequestMessage) GetSubnetworkId() string { - if x != nil { - return x.SubnetworkId - } - return "" -} - func (x *GetBlockRequestMessage) GetIncludeTransactionVerboseData() bool { if x != nil { return x.IncludeTransactionVerboseData @@ -4743,401 +4735,399 @@ var file_rpc_proto_rawDesc = []byte{ 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, 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, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x22, 0x72, 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, 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, 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, 0x0a, 0x0c, - 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, - 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, 0x0d, 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, + 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, + 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 0x0d, 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, 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, 0x92, 0x01, 0x0a, 0x18, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 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, - 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, 0x4a, 0x0a, 0x0f, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x54, - 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 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, 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, + 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, 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, 0x0a, + 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, 0x92, + 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 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, 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, + 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 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, 0x22, + 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, 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, + 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, 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, + 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 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, 0x95, 0x01, + 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, + 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, + 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, + 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, + 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, + 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, + 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, + 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, + 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 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, 0x31, + 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 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, - 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, - 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, - 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, - 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, - 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, - 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, - 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, - 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, - 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, - 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, - 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, - 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 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, 0x82, 0x01, 0x0a, 0x38, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 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, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index 290d8f135..87705bfc0 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -236,7 +236,6 @@ message AcceptedBlock{ message GetBlockRequestMessage{ // The hash of the requested block string hash = 1; - string subnetworkId = 2; // Whether to include transaction data in the response bool includeTransactionVerboseData = 3; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go index 906598300..a4b317ff7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_block.go @@ -1,15 +1,15 @@ package protowire import ( + "math" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/pkg/errors" - "math" ) func (x *KaspadMessage_GetBlockRequest) toAppMessage() (appmessage.Message, error) { return &appmessage.GetBlockRequestMessage{ Hash: x.GetBlockRequest.Hash, - SubnetworkID: x.GetBlockRequest.SubnetworkId, IncludeTransactionVerboseData: x.GetBlockRequest.IncludeTransactionVerboseData, }, nil } @@ -17,7 +17,6 @@ func (x *KaspadMessage_GetBlockRequest) toAppMessage() (appmessage.Message, erro func (x *KaspadMessage_GetBlockRequest) fromAppMessage(message *appmessage.GetBlockRequestMessage) error { x.GetBlockRequest = &GetBlockRequestMessage{ Hash: message.Hash, - SubnetworkId: message.SubnetworkID, IncludeTransactionVerboseData: message.IncludeTransactionVerboseData, } return nil diff --git a/infrastructure/network/rpcclient/rpc_get_block.go b/infrastructure/network/rpcclient/rpc_get_block.go index bd917e0d3..668e03c97 100644 --- a/infrastructure/network/rpcclient/rpc_get_block.go +++ b/infrastructure/network/rpcclient/rpc_get_block.go @@ -3,11 +3,11 @@ package rpcclient import "github.com/kaspanet/kaspad/app/appmessage" // GetBlock sends an RPC request respective to the function's name and returns the RPC server's response -func (c *RPCClient) GetBlock(hash string, subnetworkID string, includeTransactionVerboseData bool) ( +func (c *RPCClient) GetBlock(hash string, includeTransactionVerboseData bool) ( *appmessage.GetBlockResponseMessage, error) { err := c.rpcRouter.outgoingRoute().Enqueue( - appmessage.NewGetBlockRequestMessage(hash, subnetworkID, includeTransactionVerboseData)) + appmessage.NewGetBlockRequestMessage(hash, includeTransactionVerboseData)) if err != nil { return nil, err } From 0561347ff1e7afbbcbfdff7ac8ba2d888807df02 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 26 Jan 2021 17:40:54 +0200 Subject: [PATCH 281/351] Remove default dns/grpc seeders (#1454) --- domain/dagconfig/params.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 44b66983e..6c794b21f 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -204,7 +204,6 @@ var MainnetParams = Params{ Net: appmessage.Mainnet, RPCPort: "16110", DefaultPort: "16111", - DNSSeeds: []string{"dnsseed.kas.pa"}, // DAG parameters GenesisBlock: &genesisBlock, @@ -261,7 +260,6 @@ var TestnetParams = Params{ Net: appmessage.Testnet, RPCPort: "16210", DefaultPort: "16211", - GRPCSeeds: []string{"testnet-dnsseed.kas.pa:17100"}, // DAG parameters GenesisBlock: &testnetGenesisBlock, From 3916534a7e6e753927835f4c90cc5fc0f4f69ad3 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 27 Jan 2021 09:13:48 +0200 Subject: [PATCH 282/351] In kaspactl, prettify responses before printing them (#1453) * In kaspactl, prettify responses before printing them. * Indent with four spaces instead of a tab. * Unwrap the response. * Simplify unwrapping the response. * Don't unwrap responses. * Use protojson.MarshalOptions for prettification. --- cmd/kaspactl/main.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/kaspactl/main.go b/cmd/kaspactl/main.go index 5f4998dc8..458ec1c41 100644 --- a/cmd/kaspactl/main.go +++ b/cmd/kaspactl/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver/protowire" "os" "time" @@ -42,7 +43,8 @@ func main() { timeout := time.Duration(cfg.Timeout) * time.Second select { case responseString := <-responseChan: - fmt.Println(responseString) + prettyResponseString := prettifyResponse(responseString) + fmt.Println(prettyResponseString) case <-time.After(timeout): printErrorAndExit(fmt.Sprintf("timeout of %s has been exceeded", timeout)) } @@ -81,6 +83,18 @@ func postJSON(cfg *configFlags, client *grpcclient.GRPCClient, doneChan chan str doneChan <- responseString } +func prettifyResponse(response string) string { + kaspadMessage := &protowire.KaspadMessage{} + err := protojson.Unmarshal([]byte(response), kaspadMessage) + if err != nil { + printErrorAndExit(fmt.Sprintf("error parsing the response from the RPC server: %s", err)) + } + + marshalOptions := &protojson.MarshalOptions{} + marshalOptions.Indent = " " + return marshalOptions.Format(kaspadMessage) +} + func printErrorAndExit(message string) { fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", message)) os.Exit(1) From 6393a8186ae728ba4667eb1299095dc7ae681e28 Mon Sep 17 00:00:00 2001 From: Mike Zak Date: Wed, 27 Jan 2021 09:22:56 +0200 Subject: [PATCH 283/351] Update to version 0.9.0 --- version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version/version.go b/version/version.go index e38956ff9..f1c6319d3 100644 --- a/version/version.go +++ b/version/version.go @@ -10,8 +10,8 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 - appMinor uint = 8 - appPatch uint = 6 + appMinor uint = 9 + appPatch uint = 0 ) // appBuild is defined as a variable so it can be overridden during the build From a6ee871f7ede7d6090454943adde7f54fc2a0022 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 27 Jan 2021 11:04:58 +0200 Subject: [PATCH 284/351] Increase maxSelectedParentTimeDiffToAllowMiningInMilliSeconds to one hour (#1456) --- app/protocol/flowcontext/should_mine.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/protocol/flowcontext/should_mine.go b/app/protocol/flowcontext/should_mine.go index 7f0b4b628..d6dc446c7 100644 --- a/app/protocol/flowcontext/should_mine.go +++ b/app/protocol/flowcontext/should_mine.go @@ -3,7 +3,7 @@ package flowcontext import "github.com/kaspanet/kaspad/util/mstime" const ( - maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 300_000 + maxSelectedParentTimeDiffToAllowMiningInMilliSeconds = 60 * 60 * 1000 // 1 Hour ) // ShouldMine returns whether it's ok to use block template from this node From 01aee62cb081b1ffe242d96927056d75d72a1c48 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 27 Jan 2021 11:40:51 +0200 Subject: [PATCH 285/351] Add log and measure to pruning points (#1457) --- domain/consensus/processes/pruningmanager/pruningmanager.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index ab789b682..8c231027d 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -85,6 +85,8 @@ func New( // FindNextPruningPoint finds the next pruning point from the // given blockHash func (pm *pruningManager) UpdatePruningPointByVirtual() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.UpdatePruningPointByVirtual") + defer onEnd() hasPruningPoint, err := pm.pruningStore.HasPruningPoint(pm.databaseContext) if err != nil { return err @@ -413,6 +415,9 @@ func (pm *pruningManager) pruningPointCandidate() (*externalapi.DomainHash, erro // validateUTXOSetFitsCommitment makes sure that the calculated UTXOSet of the new pruning point fits the commitment. // This is a sanity test, to make sure that kaspad doesn't store, and subsequently sends syncing peers the wrong UTXOSet. func (pm *pruningManager) validateUTXOSetFitsCommitment(pruningPointHash *externalapi.DomainHash) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.validateUTXOSetFitsCommitment") + defer onEnd() + utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(pruningPointHash) if err != nil { return err From 2075c585da81f45d3126afd409263f9d8fbaaa4b Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 27 Jan 2021 13:08:35 +0200 Subject: [PATCH 286/351] Fix race condition in kaspaminer (#1455) Co-authored-by: Ori Newman --- cmd/kaspaminer/mineloop.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 6213a40e9..718724d15 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -20,13 +20,13 @@ import ( "github.com/pkg/errors" ) -var random = rand.New(rand.NewSource(time.Now().UnixNano())) var hashesTried uint64 const logHashRateInterval = 10 * time.Second func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond float64, mineWhenNotSynced bool, miningAddr util.Address) error { + rand.Seed(time.Now().UnixNano()) // Seed the global concurrent-safe random source. errChan := make(chan error) @@ -87,7 +87,7 @@ func logHashRate() { spawn("logHashRate", func() { lastCheck := time.Now() for range time.Tick(logHashRateInterval) { - currentHashesTried := hashesTried + currentHashesTried := atomic.LoadUint64(&hashesTried) currentTime := time.Now() kiloHashesTried := float64(currentHashesTried) / 1000.0 hashRate := kiloHashesTried / currentTime.Sub(lastCheck).Seconds() @@ -129,7 +129,7 @@ func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error func solveBlock(block *externalapi.DomainBlock, stopChan chan struct{}, foundBlock chan *externalapi.DomainBlock) { targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) headerForMining := block.Header.ToMutable() - initialNonce := random.Uint64() + initialNonce := rand.Uint64() // Use the global concurrent-safe random source. for i := initialNonce; i != initialNonce-1; i++ { select { case <-stopChan: @@ -191,8 +191,9 @@ func solveLoop(newTemplateChan chan *appmessage.GetBlockTemplateResponseMessage, stopOldTemplateSolving = make(chan struct{}) block := appmessage.MsgBlockToDomainBlock(template.MsgBlock) + stopOldTemplateSolvingCopy := stopOldTemplateSolving spawn("solveBlock", func() { - solveBlock(block, stopOldTemplateSolving, foundBlock) + solveBlock(block, stopOldTemplateSolvingCopy, foundBlock) }) } if stopOldTemplateSolving != nil { From 2823461fe20b5524a90cc46bae52c922ac5be5bf Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 27 Jan 2021 16:09:32 +0200 Subject: [PATCH 287/351] Change AddressKey from string to port+ipv6 address (#1458) --- .../network/addressmanager/addressmanager.go | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/infrastructure/network/addressmanager/addressmanager.go b/infrastructure/network/addressmanager/addressmanager.go index bd53d1015..4371cc20c 100644 --- a/infrastructure/network/addressmanager/addressmanager.go +++ b/infrastructure/network/addressmanager/addressmanager.go @@ -5,7 +5,7 @@ package addressmanager import ( - "encoding/binary" + "net" "sync" "github.com/kaspanet/kaspad/app/appmessage" @@ -18,9 +18,11 @@ type AddressRandomizer interface { RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress } -// AddressKey represents a "string" key of the ip addresses -// for use as keys in maps. -type AddressKey string +// AddressKey represents a pair of IP and port, the IP is always in V6 representation +type AddressKey struct { + port uint16 + address [net.IPv6len]byte +} // ErrAddressNotFound is an error returned from some functions when a // given address is not found in the address manager @@ -28,13 +30,10 @@ var ErrAddressNotFound = errors.New("address not found") // NetAddressKey returns a key of the ip address to use it in maps. func netAddressKey(netAddress *appmessage.NetAddress) AddressKey { - port := make([]byte, 2, 2) - binary.LittleEndian.PutUint16(port, netAddress.Port) - - key := make([]byte, len(netAddress.IP), len(netAddress.IP)+len(port)) - copy(key, netAddress.IP) - - return AddressKey(append(key, port...)) + key := AddressKey{port: netAddress.Port} + // all IPv4 can be represented as IPv6. + copy(key.address[:], netAddress.IP.To16()) + return key } // netAddressKeys returns a key of the ip address to use it in maps. From 8d6e71d490d34c04aff4c2e84656b36331b3fba9 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 27 Jan 2021 16:42:42 +0200 Subject: [PATCH 288/351] Add IBD test cases and check for MsgUnexpectedPruningPoint on receivePruningPointBlock as well (#1459) * Check for MsgUnexpectedPruningPoint on receivePruningPointBlock as well * Add IBD test cases * Revert "Check for MsgUnexpectedPruningPoint on receivePruningPointBlock as well" This reverts commit 6a6d1ea1807e5e4a4207fd13c78a6f066654606d. * Change log level for two logs * Remove "testing a situation where the pruning point moved during IBD (before sending the pruning point block)" --- app/protocol/flows/blockrelay/ibd.go | 4 +- .../flows/testing/handle_relay_invs_test.go | 690 +++++++++++++++--- 2 files changed, 577 insertions(+), 117 deletions(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index f4f413c3d..6538fec4f 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -446,11 +446,11 @@ func (flow *handleRelayInvsFlow) receiveAndInsertPruningPointUTXOSet( } case *appmessage.MsgDonePruningPointUTXOSetChunks: - log.Debugf("Finished receiving the UTXO set. Total UTXOs: %d", receivedUTXOCount) + log.Infof("Finished receiving the UTXO set. Total UTXOs: %d", receivedUTXOCount) return true, nil case *appmessage.MsgUnexpectedPruningPoint: - log.Debugf("Could not receive the next UTXO chunk because the pruning point %s "+ + log.Infof("Could not receive the next UTXO chunk because the pruning point %s "+ "is no longer the pruning point of peer %s", pruningPointHash, flow.peer) return false, nil diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 6b55b0728..3ebb29199 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -17,6 +17,7 @@ import ( "github.com/kaspanet/kaspad/infrastructure/config" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/util/mstime" + "github.com/pkg/errors" "testing" "time" ) @@ -93,70 +94,42 @@ var invalidBlockHash = consensushashing.BlockHash(invalidBlock) var invalidPruningPointHash = consensushashing.BlockHash(invalidPruningPointBlock) var orphanBlockHash = consensushashing.BlockHash(orphanBlock) -var fakeRelayInvsContextMap = map[externalapi.DomainHash]*externalapi.BlockInfo{ - *knownInvalidBlockHash: { - Exists: true, - BlockStatus: externalapi.StatusInvalid, - }, - *validPruningPointHash: { - Exists: true, - BlockStatus: externalapi.StatusHeaderOnly, - }, - *invalidPruningPointHash: { - Exists: true, - BlockStatus: externalapi.StatusHeaderOnly, - }, -} - type fakeRelayInvsContext struct { + testName string params *dagconfig.Params askedOrphanBlockInfo bool + finishedIBD chan struct{} + + trySetIBDRunningResponse bool + isValidPruningPointResponse bool + validateAndInsertImportedPruningPointResponse error + getBlockInfoResponse *externalapi.BlockInfo + validateAndInsertBlockResponse error } func (f *fakeRelayInvsContext) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) { - hash := consensushashing.BlockHash(block) - if hash.Equal(orphanBlockHash) { - return nil, ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes()) - } - - if hash.Equal(invalidBlockHash) { - return nil, ruleerrors.ErrBadMerkleRoot - } - - return nil, nil + return nil, f.validateAndInsertBlockResponse } func (f *fakeRelayInvsContext) ValidateTransactionAndPopulateWithConsensusData(transaction *externalapi.DomainTransaction) error { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetBlockHeader(blockHash *externalapi.DomainHash) (externalapi.BlockHeader, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) { - if info, ok := fakeRelayInvsContextMap[*blockHash]; ok { - return info, nil - } - - // Second time we ask for orphan block it's in the end of IBD, to - // check if the IBD has finished. - // Since we don't actually process headers, we just say the orphan - // exists in the second time we're asked about it to indicate IBD - // has finished. - if blockHash.Equal(orphanBlockHash) { - if f.askedOrphanBlockInfo { - return &externalapi.BlockInfo{Exists: true}, nil - } - f.askedOrphanBlockInfo = true + if f.getBlockInfoResponse != nil { + return f.getBlockInfoResponse, nil } return &externalapi.BlockInfo{ @@ -165,11 +138,11 @@ func (f *fakeRelayInvsContext) GetBlockInfo(blockHash *externalapi.DomainHash) ( } func (f *fakeRelayInvsContext) GetBlockAcceptanceData(blockHash *externalapi.DomainHash) (externalapi.AcceptanceData, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { @@ -178,11 +151,11 @@ func (f *fakeRelayInvsContext) GetMissingBlockBodyHashes(highHash *externalapi.D } func (f *fakeRelayInvsContext) GetPruningPointUTXOs(expectedPruningPointHash *externalapi.DomainHash, fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) PruningPoint() (*externalapi.DomainHash, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) ClearImportedPruningPointData() error { @@ -190,23 +163,19 @@ func (f *fakeRelayInvsContext) ClearImportedPruningPointData() error { } func (f *fakeRelayInvsContext) AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) ValidateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error { - if consensushashing.BlockHash(newPruningPoint).Equal(invalidPruningPointHash) { - return ruleerrors.ErrBadMerkleRoot - } - - return nil + return f.validateAndInsertImportedPruningPointResponse } func (f *fakeRelayInvsContext) GetVirtualSelectedParent() (*externalapi.DomainHash, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { @@ -222,35 +191,35 @@ func (f *fakeRelayInvsContext) CreateFullHeadersSelectedChainBlockLocator() (ext } func (f *fakeRelayInvsContext) GetSyncInfo() (*externalapi.SyncInfo, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) Tips() ([]*externalapi.DomainHash, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetVirtualInfo() (*externalapi.VirtualInfo, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) { - return true, nil + return f.isValidPruningPointResponse, nil } func (f *fakeRelayInvsContext) GetVirtualSelectedParentChainFromBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) IsInSelectedParentChainOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) MiningManager() miningmanager.MiningManager { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) Consensus() externalapi.Consensus { @@ -272,7 +241,7 @@ func (f *fakeRelayInvsContext) Config() *config.Config { } func (f *fakeRelayInvsContext) OnNewBlock(block *externalapi.DomainBlock, blockInsertionResult *externalapi.BlockInsertionResult) error { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks { @@ -280,15 +249,15 @@ func (f *fakeRelayInvsContext) SharedRequestedBlocks() *blockrelay.SharedRequest } func (f *fakeRelayInvsContext) Broadcast(message appmessage.Message) error { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) AddOrphan(orphanBlock *externalapi.DomainBlock) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) GetOrphanRoots(orphanHash *externalapi.DomainHash) ([]*externalapi.DomainHash, bool, error) { - panic("unimplemented") + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } func (f *fakeRelayInvsContext) IsOrphan(blockHash *externalapi.DomainHash) bool { @@ -300,14 +269,15 @@ func (f *fakeRelayInvsContext) IsIBDRunning() bool { } func (f *fakeRelayInvsContext) TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool { - return true + return f.trySetIBDRunningResponse } func (f *fakeRelayInvsContext) UnsetIBDRunning() { + close(f.finishedIBD) } -func TestHandleRelayInvsErrors(t *testing.T) { - triggerIBD := func(incomingRoute, outgoingRoute *router.Route) { +func TestHandleRelayInvs(t *testing.T) { + triggerIBD := func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(consensushashing.BlockHash(orphanBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -319,6 +289,11 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestRelayBlocks) + context.validateAndInsertBlockResponse = ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes()) + defer func() { + context.validateAndInsertBlockResponse = nil + }() + err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -336,16 +311,24 @@ func TestHandleRelayInvsErrors(t *testing.T) { } } + checkNoActivity := func(t *testing.T, outgoingRoute *router.Route) { + msg, err := outgoingRoute.DequeueWithTimeout(5 * time.Second) + if !errors.Is(err, router.ErrTimeout) { + t.Fatalf("Expected to time out, but got message %s and error %+v", msg.Command(), err) + } + } + tests := []struct { name string - funcToExecute func(incomingRoute, outgoingRoute *router.Route) + funcToExecute func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) expectsProtocolError bool expectsBan bool + expectsIBDToFinish bool expectsErrToContain string }{ { name: "sending unexpected message type", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { err := incomingRoute.Enqueue(appmessage.NewMsgBlockLocator(nil)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -357,7 +340,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, { name: "sending a known invalid inv", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusInvalid, + } + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(knownInvalidBlockHash)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -369,7 +358,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, { name: "sending unrequested block", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(unknownBlockHash)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -401,7 +390,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, { name: "sending invalid block", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(invalidBlockHash)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -413,6 +402,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestRelayBlocks) + context.validateAndInsertBlockResponse = ruleerrors.ErrBadMerkleRoot err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(invalidBlock)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -424,7 +414,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, { name: "sending unexpected message instead of block locator", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(consensushashing.BlockHash(orphanBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -436,6 +426,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestRelayBlocks) + context.validateAndInsertBlockResponse = ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes()) err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -458,10 +449,20 @@ func TestHandleRelayInvsErrors(t *testing.T) { expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", appmessage.CmdBlockLocator), }, + { + name: "starting IBD when peer is already in IBD", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + context.trySetIBDRunningResponse = false + triggerIBD(t, incomingRoute, outgoingRoute, context) + + checkNoActivity(t, outgoingRoute) + }, + expectsIBDToFinish: false, + }, { name: "sending unknown highest hash", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -476,12 +477,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: "is not in the original blockLocator", }, { name: "sending unexpected type instead of highest hash", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -496,13 +498,14 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", appmessage.CmdIBDBlockLocatorHighestHash), }, { name: "sending unexpected type instead of a header", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -529,13 +532,14 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s or %s", appmessage.CmdHeader, appmessage.CmdDoneHeaders), }, { - name: "sending unexpected type instead of pruning point hash", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + name: "sending an existing header", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -554,6 +558,191 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + + err = incomingRoute.Enqueue( + appmessage.NewBlockHeadersMessage( + []*appmessage.MsgBlockHeader{ + appmessage.DomainBlockHeaderToBlockHeader(context.params.GenesisBlock.Header)}, + ), + ) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestNextHeaders) + + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + + // Finish the IBD by sending DoneHeaders and send incompatible pruning point + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + context.isValidPruningPointResponse = false + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + checkNoActivity(t, outgoingRoute) + }, + expectsIBDToFinish: true, + }, + { + name: "sending an existing header that fails on ErrDuplicateBlock", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + context.validateAndInsertBlockResponse = ruleerrors.ErrDuplicateBlock + err = incomingRoute.Enqueue( + appmessage.NewBlockHeadersMessage( + []*appmessage.MsgBlockHeader{ + appmessage.DomainBlockHeaderToBlockHeader(context.params.GenesisBlock.Header)}, + ), + ) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestNextHeaders) + + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + + // Finish the IBD by sending DoneHeaders and send incompatible pruning point + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + context.isValidPruningPointResponse = false + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + checkNoActivity(t, outgoingRoute) + }, + expectsIBDToFinish: true, + }, + { + name: "sending an invalid header", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + context.validateAndInsertBlockResponse = ruleerrors.ErrBadMerkleRoot + err = incomingRoute.Enqueue( + appmessage.NewBlockHeadersMessage( + []*appmessage.MsgBlockHeader{ + appmessage.DomainBlockHeaderToBlockHeader(invalidBlock.Header)}, + ), + ) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsIBDToFinish: true, + expectsErrToContain: "got invalid block header", + }, + { + name: "sending unexpected type instead of pruning point hash", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -573,13 +762,14 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", appmessage.CmdPruningPointHash), }, { - name: "sending unexpected type instead of pruning point block", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + name: "sending incompatible pruning point hash", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -598,6 +788,128 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + context.isValidPruningPointResponse = false + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + checkNoActivity(t, outgoingRoute) + }, + expectsIBDToFinish: true, + }, + { + name: "testing a situation where the pruning point moved during IBD (after sending the pruning point block)", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + err = incomingRoute.Enqueue(appmessage.NewMsgUnexpectedPruningPoint()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + checkNoActivity(t, outgoingRoute) + }, + expectsIBDToFinish: true, + }, + { + name: "sending unexpected type instead of pruning point block", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -628,13 +940,14 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", appmessage.CmdIBDBlock), }, { name: "sending unexpected type instead of UTXO chunk", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -653,6 +966,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -688,14 +1008,15 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: fmt.Sprintf("received unexpected message type. "+ "expected: %s or %s or %s", appmessage.CmdPruningPointUTXOSetChunk, appmessage.CmdDonePruningPointUTXOSetChunks, appmessage.CmdUnexpectedPruningPoint), }, { name: "sending invalid pruning point", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -714,6 +1035,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -736,6 +1064,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + context.validateAndInsertImportedPruningPointResponse = ruleerrors.ErrBadMerkleRoot err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(invalidPruningPointBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -748,12 +1077,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: "error with pruning point UTXO set", }, { - name: "sending unexpected type instead of IBD block", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + name: "sending finality violating purning point", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -772,6 +1102,77 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) + + err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(validPruningPointHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) + + context.validateAndInsertImportedPruningPointResponse = ruleerrors.ErrSuggestedPruningViolatesFinality + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + err = incomingRoute.Enqueue(appmessage.NewMsgDonePruningPointUTXOSetChunks()) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsIBDToFinish: true, + }, + { + name: "sending unexpected type instead of IBD block", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + + highestHash := msg.(*appmessage.MsgIBDBlockLocator).BlockLocatorHashes[0] + err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlockLocatorHighestHash(highestHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err = outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestHeaders) + + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -818,13 +1219,14 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: fmt.Sprintf("received unexpected message type. expected: %s", appmessage.CmdIBDBlock), }, { name: "sending unexpected IBD block", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -843,6 +1245,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -888,12 +1297,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: "expected block", }, { name: "sending invalid IBD block", - funcToExecute: func(incomingRoute, outgoingRoute *router.Route) { - triggerIBD(incomingRoute, outgoingRoute) + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + triggerIBD(t, incomingRoute, outgoingRoute, context) msg, err := outgoingRoute.DequeueWithTimeout(time.Second) if err != nil { @@ -912,6 +1322,13 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) + // This is done so it'll think it added the high hash to the DAG and proceed with fetching + // the pruning point UTXO set. + context.getBlockInfoResponse = &externalapi.BlockInfo{ + Exists: true, + BlockStatus: externalapi.StatusHeaderOnly, + } + err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -950,6 +1367,7 @@ func TestHandleRelayInvsErrors(t *testing.T) { } _ = msg.(*appmessage.MsgRequestIBDBlocks) + context.validateAndInsertBlockResponse = ruleerrors.ErrBadMerkleRoot err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(invalidBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -957,30 +1375,72 @@ func TestHandleRelayInvsErrors(t *testing.T) { }, expectsProtocolError: true, expectsBan: true, + expectsIBDToFinish: true, expectsErrToContain: "invalid block", }, } testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { for _, test := range tests { - incomingRoute := router.NewRoute() - outgoingRoute := router.NewRoute() - peer := peerpkg.New(nil) - errChan := make(chan error) - go func() { - errChan <- blockrelay.HandleRelayInvs(&fakeRelayInvsContext{ - params: params, - }, incomingRoute, outgoingRoute, peer) - }() - test.funcToExecute(incomingRoute, outgoingRoute) + // This is done to avoid race condition + test := test - select { - case err := <-errChan: - checkFlowError(t, err, test.expectsProtocolError, test.expectsBan, test.expectsErrToContain) - case <-time.After(time.Second): - t.Fatalf("timed out after %s", time.Second) - } + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + incomingRoute := router.NewRoute() + outgoingRoute := router.NewRoute() + peer := peerpkg.New(nil) + errChan := make(chan error) + context := &fakeRelayInvsContext{ + testName: test.name, + params: params, + finishedIBD: make(chan struct{}), + + trySetIBDRunningResponse: true, + isValidPruningPointResponse: true, + } + go func() { + errChan <- blockrelay.HandleRelayInvs(context, incomingRoute, outgoingRoute, peer) + }() + + test.funcToExecute(t, incomingRoute, outgoingRoute, context) + + if test.expectsErrToContain != "" { + select { + case err := <-errChan: + checkFlowError(t, err, test.expectsProtocolError, test.expectsBan, test.expectsErrToContain) + case <-time.After(time.Second): + t.Fatalf("waiting for error timed out after %s", time.Second) + } + } + + select { + case <-context.finishedIBD: + if !test.expectsIBDToFinish { + t.Fatalf("IBD unexpecetedly finished") + } + case <-time.After(time.Second): + if test.expectsIBDToFinish { + t.Fatalf("IBD didn't finished after %d", time.Second) + } + } + + if test.expectsErrToContain == "" { + // Close the route to stop the flow + incomingRoute.Close() + + select { + case err := <-errChan: + if !errors.Is(err, router.ErrRouteClosed) { + t.Fatalf("unexpected error %+v", err) + } + case <-time.After(time.Second): + t.Fatalf("waiting for flow to finish timed out after %s", time.Second) + } + } + }) } }) } From c9b591f2d3816792295c61ad65c1029af16479b7 Mon Sep 17 00:00:00 2001 From: Michael Sutton Date: Wed, 27 Jan 2021 17:09:20 +0200 Subject: [PATCH 289/351] Final reindex algorithm (#1430) * Mine JSON * [Reindex tests] add test_params and validate_mining flag to test_consensus * Rename file and extend tests * Ignore local test datasets * Use spaces over tabs * Reindex algorithm - full algorithm, initial commit, some tests fail * Reindex algorithm - a few critical fixes * Reindex algorithm - move reindex struct and all related operations to new file * Reindex algorithm - added a validateIntervals method and modified tests to use it (instead of exact comparisons) * Reindex algorithm - modified reindexIntervals to receive the new child as argument and fixed an important related bug * Reindex attack tests - move logic to helper function and add stretch test * Reindex algorithm - variable names and some comments * Reindex algorithm - minor changes * Reindex algorithm - minor changes 2 * Reindex algorithm - extended stretch test * Reindex algorithm - small fix to validate function * Reindex tests - move tests and add DAG files * go format fixes * TestParams doc comment * Reindex tests - exact comparisons are not needed * Update to version 0.8.6 * Remove TestParams and use AddUTXOInvalidHeader instead * Use gzipeed test files * This unintended change somehow slipped in through branch merges * Rename test * Move interval increase/decrease methods to reachability interval file * Addressing a bunch of minor review comments * Addressed a few more minor review comments * Make code of offsetSiblingsBefore and offsetSiblingsAfter symmetric * Optimize reindex logic in cases where reorg occurs + reorg test * Do not change reindex root too fast (on reorg) * Some comments * A few more comments * Addressing review comments * Remove TestNoAttackAlternateReorg and assert chain attack * Minor Co-authored-by: Elichai Turkel Co-authored-by: Mike Zak Co-authored-by: Ori Newman --- .../interface_processes_reachabilitytree.go | 2 +- .../consensus/model/testapi/test_consensus.go | 2 + .../testapi/test_reachability_manager.go | 7 +- .../dagtopologymanager/dagtopologymanager.go | 2 +- .../processes/reachabilitymanager/interval.go | 77 ++ .../ordered_tree_node_set.go | 18 - .../reachability_external_test.go | 69 +- .../reachability_stretch_test.go | 258 ++++ .../reachabilitymanager/reachability_test.go | 27 +- .../reachabilitymanager/reindex_context.go | 804 ++++++++++++ .../processes/reachabilitymanager/stage.go | 2 +- .../test_reachabilitymanager.go | 9 + .../processes/reachabilitymanager/tree.go | 1134 +++++------------ domain/consensus/test_consensus.go | 60 +- ...blocks--2^12-delay-factor--1-k--18.json.gz | Bin 0 -> 30748 bytes ...blocks--2^13-delay-factor--1-k--18.json.gz | Bin 0 -> 61782 bytes ...blocks--2^14-delay-factor--1-k--18.json.gz | Bin 0 -> 122825 bytes ...blocks--2^12-delay-factor--1-k--18.json.gz | Bin 0 -> 31591 bytes ...blocks--2^13-delay-factor--1-k--18.json.gz | Bin 0 -> 62748 bytes ...blocks--2^14-delay-factor--1-k--18.json.gz | Bin 0 -> 125302 bytes 20 files changed, 1576 insertions(+), 895 deletions(-) create mode 100644 domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go create mode 100644 domain/consensus/processes/reachabilitymanager/reindex_context.go create mode 100644 domain/consensus/testdata/reachability/attack-dag-blocks--2^12-delay-factor--1-k--18.json.gz create mode 100644 domain/consensus/testdata/reachability/attack-dag-blocks--2^13-delay-factor--1-k--18.json.gz create mode 100644 domain/consensus/testdata/reachability/attack-dag-blocks--2^14-delay-factor--1-k--18.json.gz create mode 100644 domain/consensus/testdata/reachability/noattack-dag-blocks--2^12-delay-factor--1-k--18.json.gz create mode 100644 domain/consensus/testdata/reachability/noattack-dag-blocks--2^13-delay-factor--1-k--18.json.gz create mode 100644 domain/consensus/testdata/reachability/noattack-dag-blocks--2^14-delay-factor--1-k--18.json.gz diff --git a/domain/consensus/model/interface_processes_reachabilitytree.go b/domain/consensus/model/interface_processes_reachabilitytree.go index e2bbbd7fc..3692f008e 100644 --- a/domain/consensus/model/interface_processes_reachabilitytree.go +++ b/domain/consensus/model/interface_processes_reachabilitytree.go @@ -9,5 +9,5 @@ type ReachabilityManager interface { IsReachabilityTreeAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) IsDAGAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) UpdateReindexRoot(selectedTip *externalapi.DomainHash) error - FindAncestorOfThisAmongChildrenOfOther(this, other *externalapi.DomainHash) (*externalapi.DomainHash, error) + FindNextAncestor(descendant, ancestor *externalapi.DomainHash) (*externalapi.DomainHash, error) } diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index 5e7c5e726..ba2bfd1c4 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/db/database" + "io" ) // TestConsensus wraps the Consensus interface with some methods that are needed by tests only @@ -32,6 +33,7 @@ type TestConsensus interface { AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) + MineJSON(r io.Reader) (tips []*externalapi.DomainHash, err error) DiscardAllStores() AcceptanceDataStore() model.AcceptanceDataStore diff --git a/domain/consensus/model/testapi/test_reachability_manager.go b/domain/consensus/model/testapi/test_reachability_manager.go index 324315772..5eb56c5c3 100644 --- a/domain/consensus/model/testapi/test_reachability_manager.go +++ b/domain/consensus/model/testapi/test_reachability_manager.go @@ -1,6 +1,9 @@ package testapi -import "github.com/kaspanet/kaspad/domain/consensus/model" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // TestReachabilityManager adds to the main ReachabilityManager methods required by tests type TestReachabilityManager interface { @@ -8,4 +11,6 @@ type TestReachabilityManager interface { SetReachabilityReindexWindow(reindexWindow uint64) SetReachabilityReindexSlack(reindexSlack uint64) ReachabilityReindexSlack() uint64 + ValidateIntervals(root *externalapi.DomainHash) error + GetAllNodes(root *externalapi.DomainHash) ([]*externalapi.DomainHash, error) } diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index e5c69cd6c..73d45ff59 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -195,5 +195,5 @@ func (dtm *dagTopologyManager) ChildInSelectedParentChainOf( blockHash, specifiedHighHash) } - return dtm.reachabilityManager.FindAncestorOfThisAmongChildrenOfOther(highHash, blockHash) + return dtm.reachabilityManager.FindNextAncestor(highHash, blockHash) } diff --git a/domain/consensus/processes/reachabilitymanager/interval.go b/domain/consensus/processes/reachabilitymanager/interval.go index 177b32327..b50a1cb6b 100644 --- a/domain/consensus/processes/reachabilitymanager/interval.go +++ b/domain/consensus/processes/reachabilitymanager/interval.go @@ -16,6 +16,54 @@ func intervalSize(ri *model.ReachabilityInterval) uint64 { return ri.End - ri.Start + 1 } +// intervalIncrease returns a ReachabilityInterval with offset added to start and end +func intervalIncrease(ri *model.ReachabilityInterval, offset uint64) *model.ReachabilityInterval { + return &model.ReachabilityInterval{ + Start: ri.Start + offset, + End: ri.End + offset, + } +} + +// intervalDecrease returns a ReachabilityInterval with offset subtracted from start and end +func intervalDecrease(ri *model.ReachabilityInterval, offset uint64) *model.ReachabilityInterval { + return &model.ReachabilityInterval{ + Start: ri.Start - offset, + End: ri.End - offset, + } +} + +// intervalIncreaseStart returns a ReachabilityInterval with offset added to start +func intervalIncreaseStart(ri *model.ReachabilityInterval, offset uint64) *model.ReachabilityInterval { + return &model.ReachabilityInterval{ + Start: ri.Start + offset, + End: ri.End, + } +} + +// intervalDecreaseStart returns a ReachabilityInterval with offset reduced from start +func intervalDecreaseStart(ri *model.ReachabilityInterval, offset uint64) *model.ReachabilityInterval { + return &model.ReachabilityInterval{ + Start: ri.Start - offset, + End: ri.End, + } +} + +// intervalIncreaseEnd returns a ReachabilityInterval with offset added to end +func intervalIncreaseEnd(ri *model.ReachabilityInterval, offset uint64) *model.ReachabilityInterval { + return &model.ReachabilityInterval{ + Start: ri.Start, + End: ri.End + offset, + } +} + +// intervalDecreaseEnd returns a ReachabilityInterval with offset subtracted from end +func intervalDecreaseEnd(ri *model.ReachabilityInterval, offset uint64) *model.ReachabilityInterval { + return &model.ReachabilityInterval{ + Start: ri.Start, + End: ri.End - offset, + } +} + // intervalSplitInHalf splits this interval by a fraction of 0.5. // See splitFraction for further details. func intervalSplitInHalf(ri *model.ReachabilityInterval) ( @@ -111,6 +159,35 @@ func intervalSplitWithExponentialBias(ri *model.ReachabilityInterval, sizes []ui return intervalSplitExact(ri, biasedSizes) } +// exponentialFractions returns a fraction of each size in sizes +// as follows: +// fraction[i] = 2^size[i] / sum_j(2^size[j]) +// In the code below the above equation is divided by 2^max(size) +// to avoid exploding numbers. Note that in 1 / 2^(max(size)-size[i]) +// we divide 1 by potentially a very large number, which will +// result in loss of float precision. This is not a problem - all +// numbers close to 0 bear effectively the same weight. +func exponentialFractions(sizes []uint64) []float64 { + maxSize := uint64(0) + for _, size := range sizes { + if size > maxSize { + maxSize = size + } + } + fractions := make([]float64, len(sizes)) + for i, size := range sizes { + fractions[i] = 1 / math.Pow(2, float64(maxSize-size)) + } + fractionsSum := float64(0) + for _, fraction := range fractions { + fractionsSum += fraction + } + for i, fraction := range fractions { + fractions[i] = fraction / fractionsSum + } + return fractions +} + // intervalContains returns true if ri contains other. func intervalContains(ri *model.ReachabilityInterval, other *model.ReachabilityInterval) bool { return ri.Start <= other.Start && other.End <= ri.End diff --git a/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go b/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go index 84f06fe09..29c4a8dfa 100644 --- a/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go +++ b/domain/consensus/processes/reachabilitymanager/ordered_tree_node_set.go @@ -1,7 +1,6 @@ package reachabilitymanager import ( - "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) @@ -58,20 +57,3 @@ func (rt *reachabilityManager) findAncestorIndexOfNode(tns orderedTreeNodeSet, n } return low - 1, true, nil } - -func (rt *reachabilityManager) propagateIntervals(tns orderedTreeNodeSet, intervals []*model.ReachabilityInterval, - subtreeSizeMaps []map[externalapi.DomainHash]uint64) error { - - for i, node := range tns { - err := rt.stageInterval(node, intervals[i]) - if err != nil { - return err - } - subtreeSizeMap := subtreeSizeMaps[i] - err = rt.propagateInterval(node, subtreeSizeMap) - if err != nil { - return err - } - } - return nil -} diff --git a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go index ad8519179..bc2f26ce4 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_external_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_external_test.go @@ -1,6 +1,7 @@ package reachabilitymanager_test import ( + "math" "testing" "github.com/kaspanet/kaspad/domain/consensus" @@ -57,10 +58,20 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t t.Fatalf("reindex root is expected to change") } - // Add another block over genesis - _, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + // Add enough blocks over genesis to test also the case where the first + // level (genesis in this case) runs out of slack + slackSize := tc.ReachabilityManager().ReachabilityReindexSlack() + blocksToAdd := uint64(math.Log2(float64(slackSize))) + 2 + for i := uint64(0); i < blocksToAdd; i++ { + _, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil) + if err != nil { + t.Fatalf("AddBlock: %+v", err) + } + } + + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) if err != nil { - t.Fatalf("AddBlock: %+v", err) + t.Fatal(err) } }) } @@ -152,6 +163,11 @@ func TestUpdateReindexRoot(t *testing.T) { t.Fatalf("got unexpected chain1RootBlock interval. Want: %d, got: %d", intervalSize(chain1RootBlock), expectedChain1RootIntervalSize) } + + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) + if err != nil { + t.Fatal(err) + } }) } @@ -224,27 +240,16 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { t.Fatalf("rightBlock interval not tight after reindex") } - // Get the current interval for centerBlock. Its interval should be: - // genesisInterval - 1 - leftInterval - leftSlack - rightInterval - rightSlack - expectedCenterInterval := intervalSize(params.GenesisHash) - 1 - - intervalSize(leftBlock) - tc.ReachabilityManager().ReachabilityReindexSlack() - - intervalSize(rightBlock) - tc.ReachabilityManager().ReachabilityReindexSlack() - if intervalSize(centerBlock) != expectedCenterInterval { - t.Fatalf("unexpected centerBlock interval. Want: %d, got: %d", - expectedCenterInterval, intervalSize(centerBlock)) + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) + if err != nil { + t.Fatal(err) } // Add a chain of reachabilityReindexWindow - 1 blocks above leftBlock. // Each addition will trigger a low-than-reindex-root reindex. We // expect the centerInterval to shrink by 1 each time, but its child // to remain unaffected - centerData, err := tc.ReachabilityDataStore().ReachabilityData(tc.DatabaseContext(), centerBlock) - if err != nil { - t.Fatalf("ReachabilityData: %s", err) - } - treeChildOfCenterBlock := centerData.Children()[0] - treeChildOfCenterBlockOriginalIntervalSize := intervalSize(treeChildOfCenterBlock) leftTipHash := leftBlock for i := uint64(0); i < reachabilityReindexWindow-1; i++ { var err error @@ -253,14 +258,9 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { t.Fatalf("AddBlock: %+v", err) } - expectedCenterInterval-- - if intervalSize(centerBlock) != expectedCenterInterval { - t.Fatalf("unexpected centerBlock interval. Want: %d, got: %d", - expectedCenterInterval, intervalSize(centerBlock)) - } - - if intervalSize(treeChildOfCenterBlock) != treeChildOfCenterBlockOriginalIntervalSize { - t.Fatalf("the interval of centerBlock's child unexpectedly changed") + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) + if err != nil { + t.Fatal(err) } } @@ -276,15 +276,15 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) { t.Fatalf("AddBlock: %+v", err) } - expectedCenterInterval-- - if intervalSize(centerBlock) != expectedCenterInterval { - t.Fatalf("unexpected centerBlock interval. Want: %d, got: %d", - expectedCenterInterval, intervalSize(centerBlock)) + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) + if err != nil { + t.Fatal(err) } + } - if intervalSize(treeChildOfCenterBlock) != treeChildOfCenterBlockOriginalIntervalSize { - t.Fatalf("the interval of centerBlock's child unexpectedly changed") - } + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) + if err != nil { + t.Fatal(err) } }) } @@ -324,5 +324,10 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) { if err != nil { t.Fatalf("AddBlock: %+v", err) } + + err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash) + if err != nil { + t.Fatal(err) + } }) } diff --git a/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go b/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go new file mode 100644 index 000000000..48592bcf3 --- /dev/null +++ b/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go @@ -0,0 +1,258 @@ +package reachabilitymanager_test + +import ( + "compress/gzip" + "fmt" + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/pkg/errors" + "math" + "math/rand" + "os" + "testing" +) + +// Test configuration +const ( + numBlocksExponent = 12 + logLevel = "warn" +) + +func initializeTest(t *testing.T, testName string) (tc testapi.TestConsensus, teardown func(keepDataDir bool)) { + t.Parallel() + logger.SetLogLevels(logLevel) + params := dagconfig.SimnetParams + params.SkipProofOfWork = true + tc, teardown, err := consensus.NewFactory().NewTestConsensus(¶ms, false, testName) + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + return tc, teardown +} + +func buildJsonDAG(t *testing.T, tc testapi.TestConsensus, attackJson bool) (tips []*externalapi.DomainHash) { + filePrefix := "noattack" + if attackJson { + filePrefix = "attack" + } + fileName := fmt.Sprintf( + "../../testdata/reachability/%s-dag-blocks--2^%d-delay-factor--1-k--18.json.gz", + filePrefix, numBlocksExponent) + + f, err := os.Open(fileName) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + gzipReader, err := gzip.NewReader(f) + if err != nil { + t.Fatal(err) + } + defer gzipReader.Close() + + tips, err = tc.MineJSON(gzipReader) + if err != nil { + t.Fatal(err) + } + + err = tc.ReachabilityManager().ValidateIntervals(tc.DAGParams().GenesisHash) + if err != nil { + t.Fatal(err) + } + + return tips +} + +func addArbitraryBlocks(t *testing.T, tc testapi.TestConsensus) { + // After loading json, add arbitrary blocks all over the DAG to stretch + // reindex logic, and validate intervals post each addition + + blocks, err := tc.ReachabilityManager().GetAllNodes(tc.DAGParams().GenesisHash) + if err != nil { + t.Fatal(err) + } + + numChainsToAdd := len(blocks) / 2 // Multiply the size of the DAG with arbitrary blocks + maxBlocksInChain := 20 + validationFreq := int(math.Max(1, float64(numChainsToAdd/100))) + + randSource := rand.New(rand.NewSource(33233)) + + for i := 0; i < numChainsToAdd; i++ { + randomIndex := randSource.Intn(len(blocks)) + randomParent := blocks[randomIndex] + newBlock, _, err := tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{randomParent}) + if err != nil { + t.Fatal(err) + } + blocks = append(blocks, newBlock) + // Add a random-length chain every few blocks + if randSource.Intn(8) == 0 { + numBlocksInChain := randSource.Intn(maxBlocksInChain) + chainBlock := newBlock + for j := 0; j < numBlocksInChain; j++ { + chainBlock, _, err = tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{chainBlock}) + if err != nil { + t.Fatal(err) + } + blocks = append(blocks, chainBlock) + } + } + // Normally, validate intervals for new chain only + validationRoot := newBlock + // However every 'validation frequency' blocks validate intervals for entire DAG + if i%validationFreq == 0 || i == numChainsToAdd-1 { + validationRoot = tc.DAGParams().GenesisHash + } + err = tc.ReachabilityManager().ValidateIntervals(validationRoot) + if err != nil { + t.Fatal(err) + } + } +} + +func addAlternatingReorgBlocks(t *testing.T, tc testapi.TestConsensus, tips []*externalapi.DomainHash) { + // Create alternating reorgs to test the cases where + // reindex root is out of current header selected tip chain + + reindexRoot, err := tc.ReachabilityDataStore().ReachabilityReindexRoot(tc.DatabaseContext()) + if err != nil { + t.Fatal(err) + } + + // Try finding two tips; one which has reindex root on it's chain (chainTip), and one which + // does not (reorgTip). The latter is expected to exist in json attack files. + var chainTip, reorgTip *externalapi.DomainHash + for _, block := range tips { + isRootAncestorOfTip, err := tc.ReachabilityManager().IsReachabilityTreeAncestorOf(reindexRoot, block) + if err != nil { + t.Fatal(err) + } + if isRootAncestorOfTip { + chainTip = block + } else { + reorgTip = block + } + } + + if reorgTip == nil { + t.Fatal(errors.Errorf("DAG from jsom file is expected to contain a tip " + + "disagreeing with reindex root chain")) + } + + if chainTip == nil { + t.Fatal(errors.Errorf("reindex root is not on any header tip chain, this is unexpected behavior")) + } + + chainTipGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), chainTip) + if err != nil { + t.Fatal(err) + } + + reorgTipGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), reorgTip) + if err != nil { + t.Fatal(err) + } + + // Get both chains close to each other (we care about blue score and not + // blue work because we have SkipProofOfWork=true) + if chainTipGHOSTDAGData.BlueScore() > reorgTipGHOSTDAGData.BlueScore() { + blueScoreDiff := int(chainTipGHOSTDAGData.BlueScore() - reorgTipGHOSTDAGData.BlueScore()) + for i := 0; i < blueScoreDiff+5; i++ { + reorgTip, _, err = tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{reorgTip}) + if err != nil { + t.Fatal(err) + } + } + } else { + blueScoreDiff := int(reorgTipGHOSTDAGData.BlueScore() - chainTipGHOSTDAGData.BlueScore()) + for i := 0; i < blueScoreDiff+5; i++ { + chainTip, _, err = tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{chainTip}) + if err != nil { + t.Fatal(err) + } + } + } + + err = tc.ReachabilityManager().ValidateIntervals(tc.DAGParams().GenesisHash) + if err != nil { + t.Fatal(err) + } + + // Alternate between the chains 200 times + for i := 0; i < 200; i++ { + if i%2 == 0 { + for j := 0; j < 10; j++ { + chainTip, _, err = tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{chainTip}) + if err != nil { + t.Fatal(err) + } + } + } else { + for j := 0; j < 10; j++ { + reorgTip, _, err = tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{reorgTip}) + if err != nil { + t.Fatal(err) + } + } + } + + err = tc.ReachabilityManager().ValidateIntervals(tc.DAGParams().GenesisHash) + if err != nil { + t.Fatal(err) + } + } + + // Since current logic switches reindex root chain with reindex slack threshold - at last make the switch happen + for i := 0; i < int(tc.ReachabilityManager().ReachabilityReindexSlack())+10; i++ { + reorgTip, _, err = tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{reorgTip}) + if err != nil { + t.Fatal(err) + } + } + + err = tc.ReachabilityManager().ValidateIntervals(tc.DAGParams().GenesisHash) + if err != nil { + t.Fatal(err) + } +} + +func TestNoAttack(t *testing.T) { + tc, teardown := initializeTest(t, "TestNoAttack") + defer teardown(false) + buildJsonDAG(t, tc, false) +} + +func TestAttack(t *testing.T) { + tc, teardown := initializeTest(t, "TestAttack") + defer teardown(false) + buildJsonDAG(t, tc, true) +} + +func TestNoAttackFuzzy(t *testing.T) { + tc, teardown := initializeTest(t, "TestNoAttackFuzzy") + defer teardown(false) + tc.ReachabilityManager().SetReachabilityReindexSlack(10) + buildJsonDAG(t, tc, false) + addArbitraryBlocks(t, tc) +} + +func TestAttackFuzzy(t *testing.T) { + tc, teardown := initializeTest(t, "TestAttackFuzzy") + defer teardown(false) + tc.ReachabilityManager().SetReachabilityReindexSlack(10) + buildJsonDAG(t, tc, true) + addArbitraryBlocks(t, tc) +} + +func TestAttackAlternateReorg(t *testing.T) { + tc, teardown := initializeTest(t, "TestAttackAlternateReorg") + defer teardown(false) + tc.ReachabilityManager().SetReachabilityReindexSlack(256) + tips := buildJsonDAG(t, tc, true) + addAlternatingReorgBlocks(t, tc, tips) +} diff --git a/domain/consensus/processes/reachabilitymanager/reachability_test.go b/domain/consensus/processes/reachabilitymanager/reachability_test.go index 3a873ec27..4e9403201 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_test.go @@ -246,6 +246,11 @@ func TestAddChild(t *testing.T) { } } + err = manager.validateIntervals(root) + if err != nil { + t.Fatal(err) + } + // Scenario 2: test addChild where all nodes are direct descendants of root // root -> a, b, c... // Create the root node of a new reachability tree @@ -306,6 +311,11 @@ func TestAddChild(t *testing.T) { t.Fatalf("TestAddChild: childNode is not a descendant of root") } } + + err = manager.validateIntervals(root) + if err != nil { + t.Fatal(err) + } } func TestReachabilityTreeNodeIsAncestorOf(t *testing.T) { @@ -334,6 +344,11 @@ func TestReachabilityTreeNodeIsAncestorOf(t *testing.T) { if !helper.isReachabilityTreeAncestorOf(root, root) { t.Fatalf("TestReachabilityTreeNodeIsAncestorOf: root is expected to be an ancestor of root") } + + err := manager.validateIntervals(root) + if err != nil { + t.Fatal(err) + } } func TestIntervalContains(t *testing.T) { @@ -978,19 +993,19 @@ func TestReachabilityTreeNodeString(t *testing.T) { treeNodeB2 := helper.newNodeWithInterval(newReachabilityInterval(150, 199)) treeNodeC := helper.newNodeWithInterval(newReachabilityInterval(100, 149)) - err := helper.addChildAndStage(treeNodeA, treeNodeB1) + err := helper.stageAddChild(treeNodeA, treeNodeB1) if err != nil { - t.Fatalf("addChildAndStage: %s", err) + t.Fatalf("stageAddChild: %s", err) } - err = helper.addChildAndStage(treeNodeA, treeNodeB2) + err = helper.stageAddChild(treeNodeA, treeNodeB2) if err != nil { - t.Fatalf("addChildAndStage: %s", err) + t.Fatalf("stageAddChild: %s", err) } - err = helper.addChildAndStage(treeNodeB2, treeNodeC) + err = helper.stageAddChild(treeNodeB2, treeNodeC) if err != nil { - t.Fatalf("addChildAndStage: %s", err) + t.Fatalf("stageAddChild: %s", err) } str, err := manager.String(treeNodeA) diff --git a/domain/consensus/processes/reachabilitymanager/reindex_context.go b/domain/consensus/processes/reachabilitymanager/reindex_context.go new file mode 100644 index 000000000..d20c00525 --- /dev/null +++ b/domain/consensus/processes/reachabilitymanager/reindex_context.go @@ -0,0 +1,804 @@ +package reachabilitymanager + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" +) + +var ( + // defaultReindexWindow is the default target window size for reachability + // reindexes. Note that this is not a constant for testing purposes. + defaultReindexWindow uint64 = 200 + + // defaultReindexSlack is default the slack interval given to reachability + // tree nodes not in the selected parent chain. Note that this is not + // a constant for testing purposes. + defaultReindexSlack uint64 = 1 << 12 +) + +// reindexContext is a struct used during reindex operations. It represents a temporary context +// for caching subtree information during the *current* reindex operation only +type reindexContext struct { + manager *reachabilityManager + subTreeSizesCache map[externalapi.DomainHash]uint64 +} + +// newReindexContext creates a new empty reindex context +func newReindexContext(rt *reachabilityManager) reindexContext { + return reindexContext{ + manager: rt, + subTreeSizesCache: make(map[externalapi.DomainHash]uint64), + } +} + +/* + +Core (BFS) algorithms used during reindexing + +*/ + +// countSubtrees counts the size of each subtree under this node, +// and populates the provided subTreeSizeMap with the results. +// It is equivalent to the following recursive implementation: +// +// func (rt *reachabilityManager) countSubtrees(node *model.ReachabilityTreeNode) uint64 { +// subtreeSize := uint64(0) +// for _, child := range node.children { +// subtreeSize += child.countSubtrees() +// } +// return subtreeSize + 1 +// } +// +// However, we are expecting (linearly) deep trees, and so a +// recursive stack-based approach is inefficient and will hit +// recursion limits. Instead, the same logic was implemented +// using a (queue-based) BFS method. At a high level, the +// algorithm uses BFS for reaching all leaves and pushes +// intermediate updates from leaves via parent chains until all +// size information is gathered at the root of the operation +// (i.e. at node). +func (rc *reindexContext) countSubtrees(node *externalapi.DomainHash) error { + + if _, ok := rc.subTreeSizesCache[*node]; ok { + return nil + } + + queue := []*externalapi.DomainHash{node} + calculatedChildrenCount := make(map[externalapi.DomainHash]uint64) + for len(queue) > 0 { + var current *externalapi.DomainHash + current, queue = queue[0], queue[1:] + children, err := rc.manager.children(current) + if err != nil { + return err + } + + if len(children) == 0 { + // We reached a leaf + rc.subTreeSizesCache[*current] = 1 + } else if _, ok := rc.subTreeSizesCache[*current]; !ok { + // We haven't yet calculated the subtree size of + // the current node. Add all its children to the + // queue + queue = append(queue, children...) + continue + } + + // We reached a leaf or a pre-calculated subtree. + // Push information up + for !current.Equal(node) { + current, err = rc.manager.parent(current) + if err != nil { + return err + } + + // If the current is now nil, it means that the previous + // `current` was the genesis block -- the only block that + // does not have parents + if current == nil { + break + } + + calculatedChildrenCount[*current]++ + + children, err := rc.manager.children(current) + if err != nil { + return err + } + + if calculatedChildrenCount[*current] != uint64(len(children)) { + // Not all subtrees of the current node are ready + break + } + // All children of `current` have calculated their subtree size. + // Sum them all together and add 1 to get the sub tree size of + // `current`. + childSubtreeSizeSum := uint64(0) + for _, child := range children { + childSubtreeSizeSum += rc.subTreeSizesCache[*child] + } + rc.subTreeSizesCache[*current] = childSubtreeSizeSum + 1 + } + } + + return nil +} + +// propagateInterval propagates the new interval using a BFS traversal. +// Subtree intervals are recursively allocated according to subtree sizes and +// the allocation rule in splitWithExponentialBias. +func (rc *reindexContext) propagateInterval(node *externalapi.DomainHash) error { + + // Make sure subtrees are counted before propagating + err := rc.countSubtrees(node) + if err != nil { + return err + } + + queue := []*externalapi.DomainHash{node} + for len(queue) > 0 { + var current *externalapi.DomainHash + current, queue = queue[0], queue[1:] + + children, err := rc.manager.children(current) + if err != nil { + return err + } + + if len(children) > 0 { + sizes := make([]uint64, len(children)) + for i, child := range children { + sizes[i] = rc.subTreeSizesCache[*child] + } + + interval, err := rc.manager.intervalRangeForChildAllocation(current) + if err != nil { + return err + } + + intervals, err := intervalSplitWithExponentialBias(interval, sizes) + if err != nil { + return err + } + + for i, child := range children { + childInterval := intervals[i] + err = rc.manager.stageInterval(child, childInterval) + if err != nil { + return err + } + queue = append(queue, child) + } + } + } + return nil +} + +/* + +Functions for handling reindex triggered by adding child block + +*/ + +// reindexIntervals traverses the reachability subtree that's +// defined by the new child node and reallocates reachability interval space +// such that another reindexing is unlikely to occur shortly +// thereafter. It does this by traversing down the reachability +// tree until it finds a node with a subtree size that's greater than +// its interval size. See propagateInterval for further details. +func (rc *reindexContext) reindexIntervals(newChild, reindexRoot *externalapi.DomainHash) error { + current := newChild + // Search for the first ancestor with sufficient interval space + for { + currentInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + currentIntervalSize := intervalSize(currentInterval) + + err = rc.countSubtrees(current) + if err != nil { + return err + } + + currentSubtreeSize := rc.subTreeSizesCache[*current] + + // Current has sufficient space, break and propagate + if currentIntervalSize >= currentSubtreeSize { + break + } + + parent, err := rc.manager.parent(current) + if err != nil { + return err + } + + if parent == nil { + // If we ended up here it means that there are more + // than 2^64 blocks, which shouldn't ever happen. + return errors.Errorf("missing tree " + + "parent during reindexing. Theoretically, this " + + "should only ever happen if there are more " + + "than 2^64 blocks in the DAG.") + } + + if current.Equal(reindexRoot) { + // Reindex root is expected to hold enough capacity as long as there are less + // than ~2^52 blocks in the DAG, which should never happen in our lifetimes + // even if block rate per second is above 100. The calculation follows from the allocation of + // 2^12 (which equals 2^64/2^52) for slack per chain block below the reindex root. + return errors.Errorf("unexpected behavior: reindex root %s is out of capacity"+ + "during reindexing. Theoretically, this "+ + "should only ever happen if there are more "+ + "than ~2^52 blocks in the DAG.", reindexRoot.String()) + } + + isParentStrictAncestorOfRoot, err := rc.manager.isStrictAncestorOf(parent, reindexRoot) + if err != nil { + return err + } + + if isParentStrictAncestorOfRoot { + // In this case parent is guaranteed to have sufficient interval space, + // however we avoid reindexing the entire subtree above parent + // (which includes root and thus majority of blocks mined since) + // and use slacks along the chain up from parent to reindex root. + // Notes: + // 1. we set requiredAllocation=currentSubtreeSize in order to double the + // current interval capacity + // 2. it might be the case that current is the `newChild` itself + return rc.reindexIntervalsEarlierThanRoot(current, reindexRoot, parent, currentSubtreeSize) + } + + current = parent + } + + // Propagate the interval to the subtree + return rc.propagateInterval(current) +} + +// reindexIntervalsEarlierThanRoot implements the reindex algorithm for the case where the +// new child node is not in reindex root's subtree. The function is expected to allocate +// `requiredAllocation` to be added to interval of `allocationNode`. `commonAncestor` is +// expected to be a direct parent of `allocationNode` and an ancestor of `reindexRoot`. +func (rc *reindexContext) reindexIntervalsEarlierThanRoot( + allocationNode, reindexRoot, commonAncestor *externalapi.DomainHash, requiredAllocation uint64) error { + + // The chosen child is: + // a. A reachability tree child of `commonAncestor` + // b. A reachability tree ancestor of `reindexRoot` or `reindexRoot` itself + chosenChild, err := rc.manager.FindNextAncestor(reindexRoot, commonAncestor) + if err != nil { + return err + } + + nodeInterval, err := rc.manager.interval(allocationNode) + if err != nil { + return err + } + + chosenInterval, err := rc.manager.interval(chosenChild) + if err != nil { + return err + } + + if nodeInterval.Start < chosenInterval.Start { + // allocationNode is in the subtree before the chosen child + return rc.reclaimIntervalBefore(allocationNode, commonAncestor, chosenChild, reindexRoot, requiredAllocation) + } + + // allocationNode is in the subtree after the chosen child + return rc.reclaimIntervalAfter(allocationNode, commonAncestor, chosenChild, reindexRoot, requiredAllocation) +} + +func (rc *reindexContext) reclaimIntervalBefore( + allocationNode, commonAncestor, chosenChild, reindexRoot *externalapi.DomainHash, requiredAllocation uint64) error { + + var slackSum uint64 = 0 + var pathLen uint64 = 0 + var pathSlackAlloc uint64 = 0 + + var err error + current := chosenChild + + // Walk up the chain from common ancestor's chosen child towards reindex root + for { + if current.Equal(reindexRoot) { + // Reached reindex root. In this case, since we reached (the unlimited) root, + // we also re-allocate new slack for the chain we just traversed + + previousInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + offset := requiredAllocation + rc.manager.reindexSlack*pathLen - slackSum + err = rc.manager.stageInterval(current, intervalIncreaseStart(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.propagateInterval(current) + if err != nil { + return err + } + + err = rc.offsetSiblingsBefore(allocationNode, current, offset) + if err != nil { + return err + } + + // Set the slack for each chain block to be reserved below during the chain walk-down + pathSlackAlloc = rc.manager.reindexSlack + break + } + + slackBeforeCurrent, err := rc.manager.remainingSlackBefore(current) + if err != nil { + return err + } + slackSum += slackBeforeCurrent + + if slackSum >= requiredAllocation { + previousInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + // Set offset to be just enough to satisfy required allocation + offset := slackBeforeCurrent - (slackSum - requiredAllocation) + + err = rc.manager.stageInterval(current, intervalIncreaseStart(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.offsetSiblingsBefore(allocationNode, current, offset) + if err != nil { + return err + } + + break + } + + current, err = rc.manager.FindNextAncestor(reindexRoot, current) + if err != nil { + return err + } + + pathLen++ + } + + // Go back down the reachability tree towards the common ancestor. + // On every hop we reindex the reachability subtree before the + // current node with an interval that is smaller. + // This is to make room for the required allocation. + for { + current, err = rc.manager.parent(current) + if err != nil { + return err + } + + if current.Equal(commonAncestor) { + break + } + + originalInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + slackBeforeCurrent, err := rc.manager.remainingSlackBefore(current) + if err != nil { + return err + } + + offset := slackBeforeCurrent - pathSlackAlloc + err = rc.manager.stageInterval(current, intervalIncreaseStart(originalInterval, offset)) + if err != nil { + return err + } + + err = rc.offsetSiblingsBefore(allocationNode, current, offset) + if err != nil { + return err + } + } + + return nil +} + +func (rc *reindexContext) offsetSiblingsBefore(allocationNode, current *externalapi.DomainHash, offset uint64) error { + + parent, err := rc.manager.parent(current) + if err != nil { + return err + } + + siblingsBefore, _, err := rc.manager.splitChildren(parent, current) + if err != nil { + return err + } + + // Iterate over the slice in reverse order in order to break if reaching `allocationNode` + for i := len(siblingsBefore) - 1; i >= 0; i-- { + sibling := siblingsBefore[i] + if sibling.Equal(allocationNode) { + // We reached our final destination, allocate `offset` to `allocationNode` by increasing end and break + previousInterval, err := rc.manager.interval(allocationNode) + if err != nil { + return err + } + + err = rc.manager.stageInterval(allocationNode, intervalIncreaseEnd(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.propagateInterval(allocationNode) + if err != nil { + return err + } + + break + } + + previousInterval, err := rc.manager.interval(sibling) + if err != nil { + return err + } + + err = rc.manager.stageInterval(sibling, intervalIncrease(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.propagateInterval(sibling) + if err != nil { + return err + } + } + + return nil +} + +func (rc *reindexContext) reclaimIntervalAfter( + allocationNode, commonAncestor, chosenChild, reindexRoot *externalapi.DomainHash, requiredAllocation uint64) error { + + var slackSum uint64 = 0 + var pathLen uint64 = 0 + var pathSlackAlloc uint64 = 0 + + var err error + current := chosenChild + + // Walk up the chain from common ancestor's chosen child towards reindex root + for { + if current.Equal(reindexRoot) { + // Reached reindex root. In this case, since we reached (the unlimited) root, + // we also re-allocate new slack for the chain we just traversed + + previousInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + offset := requiredAllocation + rc.manager.reindexSlack*pathLen - slackSum + err = rc.manager.stageInterval(current, intervalDecreaseEnd(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.propagateInterval(current) + if err != nil { + return err + } + + err = rc.offsetSiblingsAfter(allocationNode, current, offset) + if err != nil { + return err + } + + // Set the slack for each chain block to be reserved below during the chain walk-down + pathSlackAlloc = rc.manager.reindexSlack + break + } + + slackAfterCurrent, err := rc.manager.remainingSlackAfter(current) + if err != nil { + return err + } + slackSum += slackAfterCurrent + + if slackSum >= requiredAllocation { + previousInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + // Set offset to be just enough to satisfy required allocation + offset := slackAfterCurrent - (slackSum - requiredAllocation) + + err = rc.manager.stageInterval(current, intervalDecreaseEnd(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.offsetSiblingsAfter(allocationNode, current, offset) + if err != nil { + return err + } + + break + } + + current, err = rc.manager.FindNextAncestor(reindexRoot, current) + if err != nil { + return err + } + + pathLen++ + } + + // Go back down the reachability tree towards the common ancestor. + // On every hop we reindex the reachability subtree before the + // current node with an interval that is smaller. + // This is to make room for the required allocation. + for { + current, err = rc.manager.parent(current) + if err != nil { + return err + } + + if current.Equal(commonAncestor) { + break + } + + originalInterval, err := rc.manager.interval(current) + if err != nil { + return err + } + + slackAfterCurrent, err := rc.manager.remainingSlackAfter(current) + if err != nil { + return err + } + + offset := slackAfterCurrent - pathSlackAlloc + err = rc.manager.stageInterval(current, intervalDecreaseEnd(originalInterval, offset)) + if err != nil { + return err + } + + err = rc.offsetSiblingsAfter(allocationNode, current, offset) + if err != nil { + return err + } + } + + return nil +} + +func (rc *reindexContext) offsetSiblingsAfter(allocationNode, current *externalapi.DomainHash, offset uint64) error { + + parent, err := rc.manager.parent(current) + if err != nil { + return err + } + + _, siblingsAfter, err := rc.manager.splitChildren(parent, current) + if err != nil { + return err + } + + for _, sibling := range siblingsAfter { + if sibling.Equal(allocationNode) { + // We reached our final destination, allocate `offset` to `allocationNode` by decreasing start and break + previousInterval, err := rc.manager.interval(allocationNode) + if err != nil { + return err + } + + err = rc.manager.stageInterval(allocationNode, intervalDecreaseStart(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.propagateInterval(allocationNode) + if err != nil { + return err + } + + break + } + + previousInterval, err := rc.manager.interval(sibling) + if err != nil { + return err + } + + err = rc.manager.stageInterval(sibling, intervalDecrease(previousInterval, offset)) + if err != nil { + return err + } + + err = rc.propagateInterval(sibling) + if err != nil { + return err + } + } + + return nil +} + +/* + +Functions for handling reindex triggered by moving reindex root + +*/ + +func (rc *reindexContext) concentrateInterval(reindexRoot, chosenChild *externalapi.DomainHash, isFinalReindexRoot bool) error { + siblingsBeforeChosen, siblingsAfterChosen, err := rc.manager.splitChildren(reindexRoot, chosenChild) + if err != nil { + return err + } + + siblingsBeforeSizesSum, err := rc.tightenIntervalsBefore(reindexRoot, siblingsBeforeChosen) + if err != nil { + return err + } + + siblingsAfterSizesSum, err := rc.tightenIntervalsAfter(reindexRoot, siblingsAfterChosen) + if err != nil { + return err + } + + err = rc.expandIntervalToChosen( + reindexRoot, chosenChild, siblingsBeforeSizesSum, siblingsAfterSizesSum, isFinalReindexRoot) + if err != nil { + return err + } + + return nil +} + +func (rc *reindexContext) tightenIntervalsBefore( + reindexRoot *externalapi.DomainHash, siblingsBeforeChosen []*externalapi.DomainHash) (sizesSum uint64, err error) { + + siblingSubtreeSizes, sizesSum := rc.countChildrenSubtrees(siblingsBeforeChosen) + + rootInterval, err := rc.manager.interval(reindexRoot) + if err != nil { + return 0, err + } + + intervalBeforeChosen := newReachabilityInterval( + rootInterval.Start+rc.manager.reindexSlack, + rootInterval.Start+rc.manager.reindexSlack+sizesSum-1, + ) + + err = rc.propagateChildrenIntervals(intervalBeforeChosen, siblingsBeforeChosen, siblingSubtreeSizes) + if err != nil { + return 0, err + } + + return sizesSum, nil +} + +func (rc *reindexContext) tightenIntervalsAfter( + reindexRoot *externalapi.DomainHash, siblingsAfterChosen []*externalapi.DomainHash) (sizesSum uint64, err error) { + + siblingSubtreeSizes, sizesSum := rc.countChildrenSubtrees(siblingsAfterChosen) + + rootInterval, err := rc.manager.interval(reindexRoot) + if err != nil { + return 0, err + } + + intervalAfterChosen := newReachabilityInterval( + rootInterval.End-rc.manager.reindexSlack-sizesSum, + rootInterval.End-rc.manager.reindexSlack-1, + ) + + err = rc.propagateChildrenIntervals(intervalAfterChosen, siblingsAfterChosen, siblingSubtreeSizes) + if err != nil { + return 0, err + } + + return sizesSum, nil +} + +func (rc *reindexContext) expandIntervalToChosen( + reindexRoot, chosenChild *externalapi.DomainHash, sizesSumBefore, sizesSumAfter uint64, isFinalReindexRoot bool) error { + + rootInterval, err := rc.manager.interval(reindexRoot) + if err != nil { + return err + } + + newChosenInterval := newReachabilityInterval( + rootInterval.Start+sizesSumBefore+rc.manager.reindexSlack, + rootInterval.End-sizesSumAfter-rc.manager.reindexSlack-1, + ) + + currentChosenInterval, err := rc.manager.interval(chosenChild) + if err != nil { + return err + } + + // Propagate interval only if chosenChild is the final reindex root + if isFinalReindexRoot && !intervalContains(newChosenInterval, currentChosenInterval) { + // New interval doesn't contain the previous one, propagation is required + + // We assign slack on both sides as an optimization. Were we to + // assign a tight interval, the next time the reindex root moves we + // would need to propagate intervals again. That is to say, when we + // do allocate slack, next time + // expandIntervalToChosen is called (next time the + // reindex root moves), newChosenInterval is likely to + // contain currentChosenInterval. + err := rc.manager.stageInterval(chosenChild, newReachabilityInterval( + newChosenInterval.Start+rc.manager.reindexSlack, + newChosenInterval.End-rc.manager.reindexSlack, + )) + if err != nil { + return err + } + + err = rc.propagateInterval(chosenChild) + if err != nil { + return err + } + } + + err = rc.manager.stageInterval(chosenChild, newChosenInterval) + if err != nil { + return err + } + + return nil +} + +func (rc *reindexContext) countChildrenSubtrees(children []*externalapi.DomainHash) ( + sizes []uint64, sum uint64) { + + sizes = make([]uint64, len(children)) + sum = 0 + for i, node := range children { + err := rc.countSubtrees(node) + if err != nil { + return nil, 0 + } + + subtreeSize := rc.subTreeSizesCache[*node] + sizes[i] = subtreeSize + sum += subtreeSize + } + return sizes, sum +} + +func (rc *reindexContext) propagateChildrenIntervals( + interval *model.ReachabilityInterval, children []*externalapi.DomainHash, sizes []uint64) error { + + childIntervals, err := intervalSplitExact(interval, sizes) + if err != nil { + return err + } + + for i, child := range children { + childInterval := childIntervals[i] + err := rc.manager.stageInterval(child, childInterval) + if err != nil { + return err + } + + err = rc.propagateInterval(child) + if err != nil { + return err + } + } + + return nil +} diff --git a/domain/consensus/processes/reachabilitymanager/stage.go b/domain/consensus/processes/reachabilitymanager/stage.go index fb58a9b4e..a4e8d7d7a 100644 --- a/domain/consensus/processes/reachabilitymanager/stage.go +++ b/domain/consensus/processes/reachabilitymanager/stage.go @@ -25,7 +25,7 @@ func (rt *reachabilityManager) stageReindexRoot(blockHash *externalapi.DomainHas rt.reachabilityDataStore.StageReachabilityReindexRoot(blockHash) } -func (rt *reachabilityManager) addChildAndStage(node, child *externalapi.DomainHash) error { +func (rt *reachabilityManager) stageAddChild(node, child *externalapi.DomainHash) error { nodeData, err := rt.reachabilityDataForInsertion(node) if err != nil { return err diff --git a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go index 89ede14e0..7824abf82 100644 --- a/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go +++ b/domain/consensus/processes/reachabilitymanager/test_reachabilitymanager.go @@ -2,6 +2,7 @@ package reachabilitymanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" ) @@ -21,6 +22,14 @@ func (t *testReachabilityManager) SetReachabilityReindexWindow(reindexWindow uin t.reachabilityManager.reindexWindow = reindexWindow } +func (t *testReachabilityManager) ValidateIntervals(root *externalapi.DomainHash) error { + return t.reachabilityManager.validateIntervals(root) +} + +func (t *testReachabilityManager) GetAllNodes(root *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + return t.reachabilityManager.getAllNodes(root) +} + // NewTestReachabilityManager creates an instance of a TestReachabilityManager func NewTestReachabilityManager(manager model.ReachabilityManager) testapi.TestReachabilityManager { return &testReachabilityManager{reachabilityManager: manager.(*reachabilityManager)} diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 540f1770a..e328f88f6 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -13,52 +13,6 @@ import ( "github.com/pkg/errors" ) -var ( - // defaultReindexWindow is the default target window size for reachability - // reindexes. Note that this is not a constant for testing purposes. - defaultReindexWindow uint64 = 200 - - // defaultReindexSlack is default the slack interval given to reachability - // tree nodes not in the selected parent chain. Note that this is not - // a constant for testing purposes. - defaultReindexSlack uint64 = 1 << 12 - - // slackReachabilityIntervalForReclaiming is the slack interval to - // reclaim during reachability reindexes earlier than the reindex root. - // See reclaimIntervalBeforeChosenChild for further details. Note that - // this is not a constant for testing purposes. - slackReachabilityIntervalForReclaiming uint64 = 1 -) - -// exponentialFractions returns a fraction of each size in sizes -// as follows: -// fraction[i] = 2^size[i] / sum_j(2^size[j]) -// In the code below the above equation is divided by 2^max(size) -// to avoid exploding numbers. Note that in 1 / 2^(max(size)-size[i]) -// we divide 1 by potentially a very large number, which will -// result in loss of float precision. This is not a problem - all -// numbers close to 0 bear effectively the same weight. -func exponentialFractions(sizes []uint64) []float64 { - maxSize := uint64(0) - for _, size := range sizes { - if size > maxSize { - maxSize = size - } - } - fractions := make([]float64, len(sizes)) - for i, size := range sizes { - fractions[i] = 1 / math.Pow(2, float64(maxSize-size)) - } - fractionsSum := float64(0) - for _, fraction := range fractions { - fractionsSum += fraction - } - for i, fraction := range fractions { - fractions[i] = fraction / fractionsSum - } - return fractions -} - func newReachabilityTreeData() model.ReachabilityData { // Please see the comment above model.ReachabilityTreeNode to understand why // we use these initial values. @@ -69,8 +23,14 @@ func newReachabilityTreeData() model.ReachabilityData { return data } -func (rt *reachabilityManager) intervalRangeForChildAllocation(hash *externalapi.DomainHash) (*model.ReachabilityInterval, error) { - interval, err := rt.interval(hash) +/* + +Interval helper functions + +*/ + +func (rt *reachabilityManager) intervalRangeForChildAllocation(node *externalapi.DomainHash) (*model.ReachabilityInterval, error) { + interval, err := rt.interval(node) if err != nil { return nil, err } @@ -81,7 +41,7 @@ func (rt *reachabilityManager) intervalRangeForChildAllocation(hash *externalapi } func (rt *reachabilityManager) remainingIntervalBefore(node *externalapi.DomainHash) (*model.ReachabilityInterval, error) { - childRange, err := rt.intervalRangeForChildAllocation(node) + childrenRange, err := rt.intervalRangeForChildAllocation(node) if err != nil { return nil, err } @@ -92,7 +52,7 @@ func (rt *reachabilityManager) remainingIntervalBefore(node *externalapi.DomainH } if len(children) == 0 { - return childRange, nil + return childrenRange, nil } firstChildInterval, err := rt.interval(children[0]) @@ -100,11 +60,11 @@ func (rt *reachabilityManager) remainingIntervalBefore(node *externalapi.DomainH return nil, err } - return newReachabilityInterval(childRange.Start, firstChildInterval.Start-1), nil + return newReachabilityInterval(childrenRange.Start, firstChildInterval.Start-1), nil } func (rt *reachabilityManager) remainingIntervalAfter(node *externalapi.DomainHash) (*model.ReachabilityInterval, error) { - childRange, err := rt.intervalRangeForChildAllocation(node) + childrenRange, err := rt.intervalRangeForChildAllocation(node) if err != nil { return nil, err } @@ -115,7 +75,7 @@ func (rt *reachabilityManager) remainingIntervalAfter(node *externalapi.DomainHa } if len(children) == 0 { - return childRange, nil + return childrenRange, nil } lastChildInterval, err := rt.interval(children[len(children)-1]) @@ -123,7 +83,25 @@ func (rt *reachabilityManager) remainingIntervalAfter(node *externalapi.DomainHa return nil, err } - return newReachabilityInterval(lastChildInterval.End+1, childRange.End), nil + return newReachabilityInterval(lastChildInterval.End+1, childrenRange.End), nil +} + +func (rt *reachabilityManager) remainingSlackBefore(node *externalapi.DomainHash) (uint64, error) { + interval, err := rt.remainingIntervalBefore(node) + if err != nil { + return 0, err + } + + return intervalSize(interval), nil +} + +func (rt *reachabilityManager) remainingSlackAfter(node *externalapi.DomainHash) (uint64, error) { + interval, err := rt.remainingIntervalAfter(node) + if err != nil { + return 0, err + } + + return intervalSize(interval), nil } func (rt *reachabilityManager) hasSlackIntervalBefore(node *externalapi.DomainHash) (bool, error) { @@ -144,549 +122,11 @@ func (rt *reachabilityManager) hasSlackIntervalAfter(node *externalapi.DomainHas return intervalSize(interval) > 0, nil } -// addChild adds child to this tree node. If this node has no -// remaining interval to allocate, a reindexing is triggered. -// This method returns a list of model.ReachabilityTreeNodes modified -// by it. -func (rt *reachabilityManager) addChild(node, child, reindexRoot *externalapi.DomainHash) error { - remaining, err := rt.remainingIntervalAfter(node) - if err != nil { - return err - } +/* - // Set the parent-child relationship - err = rt.addChildAndStage(node, child) - if err != nil { - return err - } +ReachabilityManager API functions - err = rt.stageParent(child, node) - if err != nil { - return err - } - - // Temporarily set the child's interval to be empty, at - // the start of node's remaining interval. This is done - // so that child-of-node checks (e.g. - // FindAncestorOfThisAmongChildrenOfOther) will not fail for node. - err = rt.stageInterval(child, newReachabilityInterval(remaining.Start, remaining.Start-1)) - if err != nil { - return err - } - - // Handle node not being a descendant of the reindex root. - // Note that we check node here instead of child because - // at this point we don't yet know child's interval. - isReindexRootAncestorOfNode, err := rt.IsReachabilityTreeAncestorOf(reindexRoot, node) - if err != nil { - return err - } - - if !isReindexRootAncestorOfNode { - reindexStartTime := time.Now() - err := rt.reindexIntervalsEarlierThanReindexRoot(node, reindexRoot) - if err != nil { - return err - } - reindexTimeElapsed := time.Since(reindexStartTime) - log.Debugf("Reachability reindex triggered for "+ - "block %s. This block is not a child of the current "+ - "reindex root %s. Took %dms.", - node, reindexRoot, reindexTimeElapsed.Milliseconds()) - return nil - } - - // No allocation space left -- reindex - if intervalSize(remaining) == 0 { - reindexStartTime := time.Now() - err := rt.reindexIntervals(node) - if err != nil { - return err - } - reindexTimeElapsed := time.Since(reindexStartTime) - log.Debugf("Reachability reindex triggered for "+ - "block %s. Took %dms.", - node, reindexTimeElapsed.Milliseconds()) - return nil - } - - // Allocate from the remaining space - allocated, _, err := intervalSplitInHalf(remaining) - if err != nil { - return err - } - - return rt.stageInterval(child, allocated) -} - -// reindexIntervals traverses the reachability subtree that's -// defined by this node and reallocates reachability interval space -// such that another reindexing is unlikely to occur shortly -// thereafter. It does this by traversing down the reachability -// tree until it finds a node with a subreeSize that's greater than -// its interval size. See propagateInterval for further details. -// This method returns a list of model.ReachabilityTreeNodes modified by it. -func (rt *reachabilityManager) reindexIntervals(node *externalapi.DomainHash) error { - current := node - - // Initial interval and subtree sizes - currentInterval, err := rt.interval(node) - if err != nil { - return err - } - - size := intervalSize(currentInterval) - subTreeSizeMap := make(map[externalapi.DomainHash]uint64) - err = rt.countSubtrees(current, subTreeSizeMap) - if err != nil { - return err - } - - currentSubtreeSize := subTreeSizeMap[*current] - - // Find the first ancestor that has sufficient interval space - for size < currentSubtreeSize { - currentParent, err := rt.parent(current) - if err != nil { - return err - } - - if currentParent == nil { - // If we ended up here it means that there are more - // than 2^64 blocks, which shouldn't ever happen. - return errors.Errorf("missing tree " + - "parent during reindexing. Theoretically, this " + - "should only ever happen if there are more " + - "than 2^64 blocks in the DAG.") - } - current = currentParent - currentInterval, err := rt.interval(current) - if err != nil { - return err - } - - size = intervalSize(currentInterval) - err = rt.countSubtrees(current, subTreeSizeMap) - if err != nil { - return err - } - - currentSubtreeSize = subTreeSizeMap[*current] - } - - // Propagate the interval to the subtree - return rt.propagateInterval(current, subTreeSizeMap) -} - -// countSubtrees counts the size of each subtree under this node, -// and populates the provided subTreeSizeMap with the results. -// It is equivalent to the following recursive implementation: -// -// func (rt *reachabilityManager) countSubtrees(node *model.ReachabilityTreeNode) uint64 { -// subtreeSize := uint64(0) -// for _, child := range node.children { -// subtreeSize += child.countSubtrees() -// } -// return subtreeSize + 1 -// } -// -// However, we are expecting (linearly) deep trees, and so a -// recursive stack-based approach is inefficient and will hit -// recursion limits. Instead, the same logic was implemented -// using a (queue-based) BFS method. At a high level, the -// algorithm uses BFS for reaching all leaves and pushes -// intermediate updates from leaves via parent chains until all -// size information is gathered at the root of the operation -// (i.e. at node). -func (rt *reachabilityManager) countSubtrees(node *externalapi.DomainHash, subTreeSizeMap map[externalapi.DomainHash]uint64) error { - queue := []*externalapi.DomainHash{node} - calculatedChildrenCount := make(map[externalapi.DomainHash]uint64) - for len(queue) > 0 { - var current *externalapi.DomainHash - current, queue = queue[0], queue[1:] - currentChildren, err := rt.children(current) - if err != nil { - return err - } - - if len(currentChildren) == 0 { - // We reached a leaf - subTreeSizeMap[*current] = 1 - } else if _, ok := subTreeSizeMap[*current]; !ok { - // We haven't yet calculated the subtree size of - // the current node. Add all its children to the - // queue - queue = append(queue, currentChildren...) - continue - } - - // We reached a leaf or a pre-calculated subtree. - // Push information up - for !current.Equal(node) { - current, err = rt.parent(current) - if err != nil { - return err - } - - // If the current is now nil, it means that the previous - // `current` was the genesis block -- the only block that - // does not have parents - if current == nil { - break - } - - calculatedChildrenCount[*current]++ - - currentChildren, err := rt.children(current) - if err != nil { - return err - } - - if calculatedChildrenCount[*current] != uint64(len(currentChildren)) { - // Not all subtrees of the current node are ready - break - } - // All children of `current` have calculated their subtree size. - // Sum them all together and add 1 to get the sub tree size of - // `current`. - childSubtreeSizeSum := uint64(0) - for _, child := range currentChildren { - childSubtreeSizeSum += subTreeSizeMap[*child] - } - subTreeSizeMap[*current] = childSubtreeSizeSum + 1 - } - } - - return nil -} - -// propagateInterval propagates the new interval using a BFS traversal. -// Subtree intervals are recursively allocated according to subtree sizes and -// the allocation rule in splitWithExponentialBias. This method returns -// a list of model.ReachabilityTreeNodes modified by it. -func (rt *reachabilityManager) propagateInterval(node *externalapi.DomainHash, subTreeSizeMap map[externalapi.DomainHash]uint64) error { - - queue := []*externalapi.DomainHash{node} - for len(queue) > 0 { - var current *externalapi.DomainHash - current, queue = queue[0], queue[1:] - - currentChildren, err := rt.children(current) - if err != nil { - return err - } - - if len(currentChildren) > 0 { - sizes := make([]uint64, len(currentChildren)) - for i, child := range currentChildren { - sizes[i] = subTreeSizeMap[*child] - } - - interval, err := rt.intervalRangeForChildAllocation(current) - if err != nil { - return err - } - - intervals, err := intervalSplitWithExponentialBias(interval, sizes) - if err != nil { - return err - } - for i, child := range currentChildren { - childInterval := intervals[i] - err = rt.stageInterval(child, childInterval) - if err != nil { - return err - } - queue = append(queue, child) - } - } - } - return nil -} - -func (rt *reachabilityManager) reindexIntervalsEarlierThanReindexRoot(node, - reindexRoot *externalapi.DomainHash) error { - - // Find the common ancestor for both node and the reindex root - commonAncestor, err := rt.findCommonAncestorWithReindexRoot(node, reindexRoot) - if err != nil { - return err - } - - // The chosen child is: - // a. A reachability tree child of `commonAncestor` - // b. A reachability tree ancestor of `reindexRoot` - commonAncestorChosenChild, err := rt.FindAncestorOfThisAmongChildrenOfOther(reindexRoot, commonAncestor) - if err != nil { - return err - } - - nodeInterval, err := rt.interval(node) - if err != nil { - return err - } - - commonAncestorChosenChildInterval, err := rt.interval(commonAncestorChosenChild) - if err != nil { - return err - } - - if nodeInterval.End < commonAncestorChosenChildInterval.Start { - // node is in the subtree before the chosen child - return rt.reclaimIntervalBeforeChosenChild(node, commonAncestor, - commonAncestorChosenChild, reindexRoot) - } - - // node is either: - // * in the subtree after the chosen child - // * the common ancestor - // In both cases we reclaim from the "after" subtree. In the - // latter case this is arbitrary - return rt.reclaimIntervalAfterChosenChild(node, commonAncestor, - commonAncestorChosenChild, reindexRoot) -} - -func (rt *reachabilityManager) reclaimIntervalBeforeChosenChild(rtn, commonAncestor, commonAncestorChosenChild, - reindexRoot *externalapi.DomainHash) error { - - current := commonAncestorChosenChild - - commonAncestorChosenChildHasSlackIntervalBefore, err := rt.hasSlackIntervalBefore(commonAncestorChosenChild) - if err != nil { - return err - } - - if !commonAncestorChosenChildHasSlackIntervalBefore { - // The common ancestor ran out of slack before its chosen child. - // Climb up the reachability tree toward the reindex root until - // we find a node that has enough slack. - for { - currentHasSlackIntervalBefore, err := rt.hasSlackIntervalBefore(current) - if err != nil { - return err - } - - if currentHasSlackIntervalBefore || current.Equal(reindexRoot) { - break - } - - current, err = rt.FindAncestorOfThisAmongChildrenOfOther(reindexRoot, current) - if err != nil { - return err - } - } - - if current.Equal(reindexRoot) { - // "Deallocate" an interval of slackReachabilityIntervalForReclaiming - // from this node. This is the interval that we'll use for the new - // node. - originalInterval, err := rt.interval(current) - if err != nil { - return err - } - - err = rt.stageInterval(current, newReachabilityInterval( - originalInterval.Start+slackReachabilityIntervalForReclaiming, - originalInterval.End, - )) - if err != nil { - return err - } - - err = rt.countSubtreesAndPropagateInterval(current) - if err != nil { - return err - } - - err = rt.stageInterval(current, originalInterval) - if err != nil { - return err - } - } - } - - // Go down the reachability tree towards the common ancestor. - // On every hop we reindex the reachability subtree before the - // current node with an interval that is smaller by - // slackReachabilityIntervalForReclaiming. This is to make room - // for the new node. - for !current.Equal(commonAncestor) { - currentInterval, err := rt.interval(current) - if err != nil { - return err - } - - err = rt.stageInterval(current, newReachabilityInterval( - currentInterval.Start+slackReachabilityIntervalForReclaiming, - currentInterval.End, - )) - if err != nil { - return err - } - - currentParent, err := rt.parent(current) - if err != nil { - return err - } - - err = rt.reindexIntervalsBeforeNode(currentParent, current) - if err != nil { - return err - } - current, err = rt.parent(current) - if err != nil { - return err - } - } - - return nil -} - -// reindexIntervalsBeforeNode applies a tight interval to the reachability -// subtree before `node`. Note that `node` itself is unaffected. -func (rt *reachabilityManager) reindexIntervalsBeforeNode(rtn, node *externalapi.DomainHash) error { - - childrenBeforeNode, _, err := rt.splitChildrenAroundChild(rtn, node) - if err != nil { - return err - } - - childrenBeforeNodeSizes, childrenBeforeNodeSubtreeSizeMaps, childrenBeforeNodeSizesSum := - rt.calcReachabilityTreeNodeSizes(childrenBeforeNode) - - // Apply a tight interval - nodeInterval, err := rt.interval(node) - if err != nil { - return err - } - - newIntervalEnd := nodeInterval.Start - 1 - newInterval := newReachabilityInterval(newIntervalEnd-childrenBeforeNodeSizesSum+1, newIntervalEnd) - intervals, err := intervalSplitExact(newInterval, childrenBeforeNodeSizes) - if err != nil { - return err - } - return rt.propagateIntervals(childrenBeforeNode, intervals, childrenBeforeNodeSubtreeSizeMaps) -} - -func (rt *reachabilityManager) reclaimIntervalAfterChosenChild(node, commonAncestor, commonAncestorChosenChild, - reindexRoot *externalapi.DomainHash) error { - - current := commonAncestorChosenChild - commonAncestorChosenChildHasSlackIntervalAfter, err := rt.hasSlackIntervalAfter(commonAncestorChosenChild) - if err != nil { - return err - } - - if !commonAncestorChosenChildHasSlackIntervalAfter { - // The common ancestor ran out of slack after its chosen child. - // Climb up the reachability tree toward the reindex root until - // we find a node that has enough slack. - for { - currentHasSlackIntervalAfter, err := rt.hasSlackIntervalAfter(commonAncestorChosenChild) - if err != nil { - return err - } - - if currentHasSlackIntervalAfter || current.Equal(reindexRoot) { - break - } - - current, err = rt.FindAncestorOfThisAmongChildrenOfOther(reindexRoot, current) - if err != nil { - return err - } - } - - if current.Equal(reindexRoot) { - // "Deallocate" an interval of slackReachabilityIntervalForReclaiming - // from this node. This is the interval that we'll use for the new - // node. - originalInterval, err := rt.interval(current) - if err != nil { - return err - } - - err = rt.stageInterval(current, newReachabilityInterval( - originalInterval.Start, - originalInterval.End-slackReachabilityIntervalForReclaiming, - )) - if err != nil { - return err - } - - err = rt.countSubtreesAndPropagateInterval(current) - if err != nil { - return err - } - - err = rt.stageInterval(current, originalInterval) - if err != nil { - return err - } - } - } - - // Go down the reachability tree towards the common ancestor. - // On every hop we reindex the reachability subtree after the - // current node with an interval that is smaller by - // slackReachabilityIntervalForReclaiming. This is to make room - // for the new node. - for !current.Equal(commonAncestor) { - currentInterval, err := rt.interval(current) - if err != nil { - return err - } - - err = rt.stageInterval(current, newReachabilityInterval( - currentInterval.Start, - currentInterval.End-slackReachabilityIntervalForReclaiming, - )) - if err != nil { - return err - } - - currentParent, err := rt.parent(current) - if err != nil { - return err - } - - err = rt.reindexIntervalsAfterNode(currentParent, current) - if err != nil { - return err - } - current = currentParent - } - - return nil -} - -// reindexIntervalsAfterNode applies a tight interval to the reachability -// subtree after `node`. Note that `node` itself is unaffected. -func (rt *reachabilityManager) reindexIntervalsAfterNode(rtn, node *externalapi.DomainHash) error { - - _, childrenAfterNode, err := rt.splitChildrenAroundChild(rtn, node) - if err != nil { - return err - } - - childrenAfterNodeSizes, childrenAfterNodeSubtreeSizeMaps, childrenAfterNodeSizesSum := - rt.calcReachabilityTreeNodeSizes(childrenAfterNode) - - // Apply a tight interval - nodeInterval, err := rt.interval(node) - if err != nil { - return err - } - - newIntervalStart := nodeInterval.End + 1 - newInterval := newReachabilityInterval(newIntervalStart, newIntervalStart+childrenAfterNodeSizesSum-1) - intervals, err := intervalSplitExact(newInterval, childrenAfterNodeSizes) - if err != nil { - return err - } - return rt.propagateIntervals(childrenAfterNode, intervals, childrenAfterNodeSubtreeSizeMaps) -} +*/ // IsReachabilityTreeAncestorOf checks if this node is a reachability tree ancestor // of the other node. Note that we use the graph theory convention @@ -705,28 +145,20 @@ func (rt *reachabilityManager) IsReachabilityTreeAncestorOf(node, other *externa return intervalContains(nodeInterval, otherInterval), nil } -// findCommonAncestorWithReindexRoot finds the most recent reachability -// tree ancestor common to both node and the given reindex root. Note -// that we assume that almost always the chain between the reindex root -// and the common ancestor is longer than the chain between node and the -// common ancestor. -func (rt *reachabilityManager) findCommonAncestorWithReindexRoot(node, reindexRoot *externalapi.DomainHash) (*externalapi.DomainHash, error) { - currentThis := node - for { - isAncestorOf, err := rt.IsReachabilityTreeAncestorOf(currentThis, reindexRoot) - if err != nil { - return nil, err - } - - if isAncestorOf { - return currentThis, nil - } - - currentThis, err = rt.parent(currentThis) - if err != nil { - return nil, err - } +// FindNextAncestor finds the reachability tree child +// of 'ancestor' which is also an ancestor of 'descendant'. +func (rt *reachabilityManager) FindNextAncestor(descendant, ancestor *externalapi.DomainHash) (*externalapi.DomainHash, error) { + childrenOfAncestor, err := rt.children(ancestor) + if err != nil { + return nil, err } + + nextAncestor, ok := rt.findAncestorOfNode(childrenOfAncestor, descendant) + if !ok { + return nil, errors.Errorf("ancestor is not an ancestor of descendant") + } + + return nextAncestor, nil } // String returns a string representation of a reachability tree node @@ -742,17 +174,17 @@ func (rt *reachabilityManager) String(node *externalapi.DomainHash) (string, err for len(queue) > 0 { var current *externalapi.DomainHash current, queue = queue[0], queue[1:] - currentChildren, err := rt.children(current) + children, err := rt.children(current) if err != nil { return "", err } - if len(currentChildren) == 0 { + if len(children) == 0 { continue } line := "" - for _, child := range currentChildren { + for _, child := range children { childInterval, err := rt.interval(child) if err != nil { return "", err @@ -766,290 +198,324 @@ func (rt *reachabilityManager) String(node *externalapi.DomainHash) (string, err return strings.Join(lines, "\n"), nil } -func (rt *reachabilityManager) updateReindexRoot(newTreeNode *externalapi.DomainHash) error { +/* - nextReindexRoot, err := rt.reindexRoot() - if err != nil { - return err +Tree helper functions + +*/ + +func (rt *reachabilityManager) isStrictAncestorOf(node, other *externalapi.DomainHash) (bool, error) { + if node.Equal(other) { + return false, nil } + return rt.IsReachabilityTreeAncestorOf(node, other) +} +// findCommonAncestor finds the most recent reachability +// tree ancestor common to both node and the given reindex root. Note +// that we assume that almost always the chain between the reindex root +// and the common ancestor is longer than the chain between node and the +// common ancestor. +func (rt *reachabilityManager) findCommonAncestor(node, root *externalapi.DomainHash) (*externalapi.DomainHash, error) { + current := node for { - candidateReindexRoot, found, err := rt.maybeMoveReindexRoot(nextReindexRoot, newTreeNode) + isAncestorOf, err := rt.IsReachabilityTreeAncestorOf(current, root) if err != nil { - return err + return nil, err } - if !found { - break + + if isAncestorOf { + return current, nil } - nextReindexRoot = candidateReindexRoot - } - rt.stageReindexRoot(nextReindexRoot) - return nil -} - -func (rt *reachabilityManager) maybeMoveReindexRoot(reindexRoot, newTreeNode *externalapi.DomainHash) ( - newReindexRoot *externalapi.DomainHash, found bool, err error) { - - isAncestorOf, err := rt.IsReachabilityTreeAncestorOf(reindexRoot, newTreeNode) - if err != nil { - return nil, false, err - } - if !isAncestorOf { - commonAncestor, err := rt.findCommonAncestorWithReindexRoot(newTreeNode, reindexRoot) + current, err = rt.parent(current) if err != nil { - return nil, false, err + return nil, err } - - return commonAncestor, true, nil } - - reindexRootChosenChild, err := rt.FindAncestorOfThisAmongChildrenOfOther(newTreeNode, reindexRoot) - if err != nil { - return nil, false, err - } - - newTreeNodeGHOSTDAGData, err := rt.ghostdagDataStore.Get(rt.databaseContext, newTreeNode) - if err != nil { - return nil, false, err - } - - reindexRootChosenChildGHOSTDAGData, err := rt.ghostdagDataStore.Get(rt.databaseContext, reindexRootChosenChild) - if err != nil { - return nil, false, err - } - - if newTreeNodeGHOSTDAGData.BlueScore()-reindexRootChosenChildGHOSTDAGData.BlueScore() < rt.reindexWindow { - return nil, false, nil - } - - err = rt.concentrateIntervalAroundReindexRootChosenChild(reindexRoot, reindexRootChosenChild) - if err != nil { - return nil, false, err - } - - return reindexRootChosenChild, true, nil } -// FindAncestorOfThisAmongChildrenOfOther finds the reachability tree child -// of node that is the ancestor of node. -func (rt *reachabilityManager) FindAncestorOfThisAmongChildrenOfOther(this, other *externalapi.DomainHash) (*externalapi.DomainHash, error) { - otherChildren, err := rt.children(other) - if err != nil { - return nil, err - } +// splitChildren splits `node` children into two slices: the nodes that are before +// `pivot` and the nodes that are after. +func (rt *reachabilityManager) splitChildren(node, pivot *externalapi.DomainHash) ( + nodesBeforePivot, nodesAfterPivot []*externalapi.DomainHash, err error) { - ancestor, ok := rt.findAncestorOfNode(otherChildren, this) - if !ok { - return nil, errors.Errorf("node is not an ancestor of this") - } - - return ancestor, nil -} - -func (rt *reachabilityManager) concentrateIntervalAroundReindexRootChosenChild(reindexRoot, - reindexRootChosenChild *externalapi.DomainHash) error { - - reindexRootChildNodesBeforeChosen, reindexRootChildNodesAfterChosen, err := - rt.splitChildrenAroundChild(reindexRoot, reindexRootChosenChild) - if err != nil { - return err - } - - reindexRootChildNodesBeforeChosenSizesSum, err := - rt.tightenIntervalsBeforeReindexRootChosenChild(reindexRoot, reindexRootChildNodesBeforeChosen) - if err != nil { - return err - } - - reindexRootChildNodesAfterChosenSizesSum, err := - rt.tightenIntervalsAfterReindexRootChosenChild(reindexRoot, reindexRootChildNodesAfterChosen) - if err != nil { - return err - } - - err = rt.expandIntervalInReindexRootChosenChild(reindexRoot, reindexRootChosenChild, - reindexRootChildNodesBeforeChosenSizesSum, reindexRootChildNodesAfterChosenSizesSum) - if err != nil { - return err - } - - return nil -} - -// splitChildrenAroundChild splits `node` into two slices: the nodes that are before -// `child` and the nodes that are after. -func (rt *reachabilityManager) splitChildrenAroundChild(node, child *externalapi.DomainHash) ( - nodesBeforeChild, nodesAfterChild []*externalapi.DomainHash, err error) { - - nodeChildren, err := rt.children(node) + children, err := rt.children(node) if err != nil { return nil, nil, err } - for i, candidateChild := range nodeChildren { - if candidateChild.Equal(child) { - return nodeChildren[:i], nodeChildren[i+1:], nil + for i, child := range children { + if child.Equal(pivot) { + return children[:i], children[i+1:], nil } } - return nil, nil, errors.Errorf("child not a child of node") + return nil, nil, errors.Errorf("pivot not a pivot of node") } -func (rt *reachabilityManager) tightenIntervalsBeforeReindexRootChosenChild( - reindexRoot *externalapi.DomainHash, - reindexRootChildNodesBeforeChosen []*externalapi.DomainHash) (reindexRootChildNodesBeforeChosenSizesSum uint64, - err error) { +/* - reindexRootChildNodesBeforeChosenSizes, reindexRootChildNodesBeforeChosenSubtreeSizeMaps, reindexRootChildNodesBeforeChosenSizesSum := - rt.calcReachabilityTreeNodeSizes(reindexRootChildNodesBeforeChosen) +Internal reachabilityManager API - reindexRootInterval, err := rt.interval(reindexRoot) - if err != nil { - return 0, err - } +*/ - intervalBeforeReindexRootStart := newReachabilityInterval( - reindexRootInterval.Start+rt.reindexSlack, - reindexRootInterval.Start+rt.reindexSlack+reindexRootChildNodesBeforeChosenSizesSum-1, - ) - - err = rt.propagateChildIntervals(intervalBeforeReindexRootStart, reindexRootChildNodesBeforeChosen, - reindexRootChildNodesBeforeChosenSizes, reindexRootChildNodesBeforeChosenSubtreeSizeMaps) - if err != nil { - return 0, err - } - return reindexRootChildNodesBeforeChosenSizesSum, nil -} - -func (rt *reachabilityManager) tightenIntervalsAfterReindexRootChosenChild( - reindexRoot *externalapi.DomainHash, - reindexRootChildNodesAfterChosen []*externalapi.DomainHash) (reindexRootChildNodesAfterChosenSizesSum uint64, - err error) { - - reindexRootChildNodesAfterChosenSizes, reindexRootChildNodesAfterChosenSubtreeSizeMaps, - reindexRootChildNodesAfterChosenSizesSum := - rt.calcReachabilityTreeNodeSizes(reindexRootChildNodesAfterChosen) - - reindexRootInterval, err := rt.interval(reindexRoot) - if err != nil { - return 0, err - } - - intervalAfterReindexRootEnd := newReachabilityInterval( - reindexRootInterval.End-rt.reindexSlack-reindexRootChildNodesAfterChosenSizesSum, - reindexRootInterval.End-rt.reindexSlack-1, - ) - - err = rt.propagateChildIntervals(intervalAfterReindexRootEnd, reindexRootChildNodesAfterChosen, - reindexRootChildNodesAfterChosenSizes, reindexRootChildNodesAfterChosenSubtreeSizeMaps) - if err != nil { - return 0, err - } - return reindexRootChildNodesAfterChosenSizesSum, nil -} - -func (rt *reachabilityManager) expandIntervalInReindexRootChosenChild(reindexRoot, - reindexRootChosenChild *externalapi.DomainHash, reindexRootChildNodesBeforeChosenSizesSum uint64, - reindexRootChildNodesAfterChosenSizesSum uint64) error { - - reindexRootInterval, err := rt.interval(reindexRoot) +// addChild adds child to this tree node. If this node has no +// remaining interval to allocate, a reindexing is triggered. When a reindexing +// is triggered, the reindex root point is used within the +// reindex algorithm's logic +func (rt *reachabilityManager) addChild(node, child, reindexRoot *externalapi.DomainHash) error { + remaining, err := rt.remainingIntervalAfter(node) if err != nil { return err } - newReindexRootChildInterval := newReachabilityInterval( - reindexRootInterval.Start+reindexRootChildNodesBeforeChosenSizesSum+rt.reindexSlack, - reindexRootInterval.End-reindexRootChildNodesAfterChosenSizesSum-rt.reindexSlack-1, - ) - - reindexRootChosenChildInterval, err := rt.interval(reindexRootChosenChild) + // Set the parent-child relationship + err = rt.stageAddChild(node, child) if err != nil { return err } - if !intervalContains(newReindexRootChildInterval, reindexRootChosenChildInterval) { - // New interval doesn't contain the previous one, propagation is required + err = rt.stageParent(child, node) + if err != nil { + return err + } - // We assign slack on both sides as an optimization. Were we to - // assign a tight interval, the next time the reindex root moves we - // would need to propagate intervals again. That is to say, When we - // DO allocate slack, next time - // expandIntervalInReindexRootChosenChild is called (next time the - // reindex root moves), newReindexRootChildInterval is likely to - // contain reindexRootChosenChild.Interval. - err := rt.stageInterval(reindexRootChosenChild, newReachabilityInterval( - newReindexRootChildInterval.Start+rt.reindexSlack, - newReindexRootChildInterval.End-rt.reindexSlack, - )) + // No allocation space left at parent -- reindex + if intervalSize(remaining) == 0 { + + // Initially set the child's interval to the empty remaining interval. + // This is done since in some cases, the underlying algorithm will + // allocate space around this point and call intervalIncreaseEnd or + // intervalDecreaseStart making for intervalSize > 0 + err = rt.stageInterval(child, remaining) if err != nil { return err } - err = rt.countSubtreesAndPropagateInterval(reindexRootChosenChild) + rc := newReindexContext(rt) + + reindexStartTime := time.Now() + err := rc.reindexIntervals(child, reindexRoot) if err != nil { return err } + + reindexTimeElapsed := time.Since(reindexStartTime) + log.Debugf("Reachability reindex triggered for "+ + "block %s. Took %dms.", + node, reindexTimeElapsed.Milliseconds()) + + return nil } - err = rt.stageInterval(reindexRootChosenChild, newReindexRootChildInterval) + // Allocate from the remaining space + allocated, _, err := intervalSplitInHalf(remaining) if err != nil { return err } + + return rt.stageInterval(child, allocated) +} + +func (rt *reachabilityManager) updateReindexRoot(selectedTip *externalapi.DomainHash) error { + + currentReindexRoot, err := rt.reindexRoot() + if err != nil { + return err + } + + // First, find the new root + reindexRootAncestor, newReindexRoot, err := rt.findNextReindexRoot(currentReindexRoot, selectedTip) + if err != nil { + return err + } + + // No update to root, return + if currentReindexRoot.Equal(newReindexRoot) { + return nil + } + + rc := newReindexContext(rt) + + // Iterate from reindexRootAncestor towards newReindexRoot + for { + chosenChild, err := rt.FindNextAncestor(selectedTip, reindexRootAncestor) + if err != nil { + return err + } + + isFinalReindexRoot := chosenChild.Equal(newReindexRoot) + + // Concentrate interval from current ancestor to it's chosen child + err = rc.concentrateInterval(reindexRootAncestor, chosenChild, isFinalReindexRoot) + if err != nil { + return err + } + + if isFinalReindexRoot { + break + } + + reindexRootAncestor = chosenChild + } + + // Update reindex root data store + rt.stageReindexRoot(newReindexRoot) return nil } -func (rt *reachabilityManager) countSubtreesAndPropagateInterval(node *externalapi.DomainHash) error { - subtreeSizeMap := make(map[externalapi.DomainHash]uint64) - err := rt.countSubtrees(node, subtreeSizeMap) +// findNextReindexRoot finds the new reindex root based on the current one and the new selected tip. +// The function also returns the common ancestor between the current and new reindex roots (possibly current root itself). +// This ancestor should be used as a starting point for concentrating the interval towards the new root. +func (rt *reachabilityManager) findNextReindexRoot(currentReindexRoot, selectedTip *externalapi.DomainHash) ( + reindexRootAncestor, newReindexRoot *externalapi.DomainHash, err error) { + + reindexRootAncestor = currentReindexRoot + newReindexRoot = currentReindexRoot + + selectedTipGHOSTDAGData, err := rt.ghostdagDataStore.Get(rt.databaseContext, selectedTip) if err != nil { - return err + return nil, nil, err } - return rt.propagateInterval(node, subtreeSizeMap) -} + isCurrentAncestorOfTip, err := rt.IsReachabilityTreeAncestorOf(currentReindexRoot, selectedTip) + if err != nil { + return nil, nil, err + } -func (rt *reachabilityManager) calcReachabilityTreeNodeSizes(treeNodes []*externalapi.DomainHash) ( - sizes []uint64, subtreeSizeMaps []map[externalapi.DomainHash]uint64, sum uint64) { - - sizes = make([]uint64, len(treeNodes)) - subtreeSizeMaps = make([]map[externalapi.DomainHash]uint64, len(treeNodes)) - sum = 0 - for i, node := range treeNodes { - subtreeSizeMap := make(map[externalapi.DomainHash]uint64) - err := rt.countSubtrees(node, subtreeSizeMap) + // Test if current root is ancestor of selected tip - if not, this is a reorg case + if !isCurrentAncestorOfTip { + currentRootGHOSTDAGData, err := rt.ghostdagDataStore.Get(rt.databaseContext, currentReindexRoot) if err != nil { - return nil, nil, 0 + return nil, nil, err } - subtreeSize := subtreeSizeMap[*node] - sizes[i] = subtreeSize - subtreeSizeMaps[i] = subtreeSizeMap - sum += subtreeSize + // We have reindex root out of selected tip chain, however we switch chains only after a sufficient + // threshold of reindexSlack score in order to address possible alternating reorg attacks. + // The reindexSlack constant is used as an heuristic for a large enough constant on the one hand, but + // one which will not harm performance on the other hand - given the available slack at the chain split point + if selectedTipGHOSTDAGData.BlueScore()-currentRootGHOSTDAGData.BlueScore() < rt.reindexSlack { + // Return current - this indicates no change + return currentReindexRoot, currentReindexRoot, nil + } + + // The common ancestor is where we should start concentrating the interval from + commonAncestor, err := rt.findCommonAncestor(selectedTip, currentReindexRoot) + if err != nil { + return nil, nil, err + } + + reindexRootAncestor = commonAncestor + newReindexRoot = commonAncestor } - return sizes, subtreeSizeMaps, sum + + // Iterate from ancestor towards selected tip until passing the reindexWindow threshold, + // for finding the new reindex root + for { + chosenChild, err := rt.FindNextAncestor(selectedTip, newReindexRoot) + if err != nil { + return nil, nil, err + } + + chosenChildGHOSTDAGData, err := rt.ghostdagDataStore.Get(rt.databaseContext, chosenChild) + if err != nil { + return nil, nil, err + } + + if selectedTipGHOSTDAGData.BlueScore()-chosenChildGHOSTDAGData.BlueScore() < rt.reindexWindow { + break + } + + newReindexRoot = chosenChild + } + + return reindexRootAncestor, newReindexRoot, nil } -func (rt *reachabilityManager) propagateChildIntervals(interval *model.ReachabilityInterval, - childNodes []*externalapi.DomainHash, sizes []uint64, subtreeSizeMaps []map[externalapi.DomainHash]uint64) error { +/* - childIntervalSizes, err := intervalSplitExact(interval, sizes) - if err != nil { - return err - } +Test helper functions - for i, child := range childNodes { - childInterval := childIntervalSizes[i] - err := rt.stageInterval(child, childInterval) +*/ + +// Helper function (for testing purposes) to validate that all tree intervals +// under a specified subtree root are allocated correctly and as expected +func (rt *reachabilityManager) validateIntervals(root *externalapi.DomainHash) error { + queue := []*externalapi.DomainHash{root} + for len(queue) > 0 { + var current *externalapi.DomainHash + current, queue = queue[0], queue[1:] + + children, err := rt.children(current) if err != nil { return err } - childSubtreeSizeMap := subtreeSizeMaps[i] - err = rt.propagateInterval(child, childSubtreeSizeMap) + if len(children) > 0 { + queue = append(queue, children...) + } + + currentInterval, err := rt.interval(current) if err != nil { return err } + + if currentInterval.Start > currentInterval.End { + err := errors.Errorf("Interval allocation is empty") + return err + } + + for i, child := range children { + childInterval, err := rt.interval(child) + if err != nil { + return err + } + + if i > 0 { + siblingInterval, err := rt.interval(children[i-1]) + if err != nil { + return err + } + + if siblingInterval.End+1 != childInterval.Start { + err := errors.Errorf("Child intervals are expected be right after each other") + return err + } + } + + if childInterval.Start < currentInterval.Start { + err := errors.Errorf("Child interval to the left of parent") + return err + } + + if childInterval.End >= currentInterval.End { + err := errors.Errorf("Child interval to the right of parent") + return err + } + } } return nil } + +// Helper function (for testing purposes) to get all nodes under a specified subtree root +func (rt *reachabilityManager) getAllNodes(root *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + queue := []*externalapi.DomainHash{root} + nodes := []*externalapi.DomainHash{root} + for len(queue) > 0 { + var current *externalapi.DomainHash + current, queue = queue[0], queue[1:] + + children, err := rt.children(current) + if err != nil { + return nil, err + } + + if len(children) > 0 { + queue = append(queue, children...) + nodes = append(nodes, children...) + } + } + + return nodes, nil +} diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 35e490f0c..48f93166c 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -1,12 +1,15 @@ package consensus import ( + "encoding/json" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/pkg/errors" + "io" ) type testConsensus struct { @@ -103,8 +106,63 @@ func (tc *testConsensus) AddUTXOInvalidBlock(parentHashes []*externalapi.DomainH return consensushashing.BlockHash(block), blockInsertionResult, nil } -func (tc *testConsensus) BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) { +func (tc *testConsensus) MineJSON(r io.Reader) (tips []*externalapi.DomainHash, err error) { + // jsonBlock is a json representation of a block in mine format + type jsonBlock struct { + ID string `json:"id"` + Parents []string `json:"parents"` + } + tipSet := map[externalapi.DomainHash]*externalapi.DomainHash{} + tipSet[*tc.dagParams.GenesisHash] = tc.dagParams.GenesisHash + + parentsMap := make(map[string]*externalapi.DomainHash) + parentsMap["0"] = tc.dagParams.GenesisHash + + decoder := json.NewDecoder(r) + // read open bracket + _, err = decoder.Token() + if err != nil { + return nil, err + } + // while the array contains values + for decoder.More() { + var block jsonBlock + // decode an array value (Message) + err := decoder.Decode(&block) + if err != nil { + return nil, err + } + if block.ID == "0" { + continue + } + parentHashes := make([]*externalapi.DomainHash, len(block.Parents)) + var ok bool + for i, parentID := range block.Parents { + parentHashes[i], ok = parentsMap[parentID] + if !ok { + return nil, errors.Errorf("Couldn't find blockID: %s", parentID) + } + delete(tipSet, *parentHashes[i]) + } + blockHash, _, err := tc.AddUTXOInvalidHeader(parentHashes) + if err != nil { + return nil, err + } + parentsMap[block.ID] = blockHash + tipSet[*blockHash] = blockHash + } + + tips = make([]*externalapi.DomainHash, len(tipSet)) + i := 0 + for _, v := range tipSet { + tips[i] = v + i++ + } + return tips, nil +} + +func (tc *testConsensus) BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) { // Require write lock because BuildBlockWithParents stages temporary data tc.lock.Lock() defer tc.lock.Unlock() diff --git a/domain/consensus/testdata/reachability/attack-dag-blocks--2^12-delay-factor--1-k--18.json.gz b/domain/consensus/testdata/reachability/attack-dag-blocks--2^12-delay-factor--1-k--18.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..b26317f72a17645a2046dbc2b6b12c5660017271 GIT binary patch literal 30748 zcmXtfc_5VE_kV?Kp$PA+Wt;3RmSHR*A)&~YeG3`e*!Q(0A$#^jX_B#J8Dn2Vb}|?{ zV;h4QLik>Ne!o9(pXc6t&g-0e?>Xn5^Wcu5qKYmjS)3!Y^7OQ_aT2w)vKO_6yV^K; zh>G4ZzkNs4)(&pvC;HsV#?uucDtcSg3H*YJz3^~#Iafc`i{jI)GFw(S-$3R*2`@O# zT-B$NB7aTiO|GP?Gk_8He)@pZY-X6D6T770P4y@Cj>&VP6tDL$!=BTgkiQJ4tEAJD z+>pN^7N?stCr77yuHf}ywZ-XP?rF%_N&G44^snpb(dltW{RzYAQsc?O@6)5)&6A`h zqT<2W=>F-_SmUwRTnNoljQpFT*iv$qKfWs7y?5G!Fm2R9VSqGMladW296-1{=OSUZ(}ZEz$VzPl^EPc@i7 z-Eb;6+@Lt5bv!k=^2BuwRt?_ak~HG|_4+jnqiT?@G1?67M<=9pt~_lW_~}Xg$dtv@ z?qwgZ@3Qh`WMtyKQ@0KHp8w$>$sgT=w*`hJmhZthNrJG33ID`|45I%9<&I zKWgXEj2QB+%*yJf(9??wYv5fVs`0e;KNkW2kto@u2rkn0u@d`?o_kFQW7}yU>vIGq z>Xc$LVD}QqDQLEFTmSkcHmZfAbPl0G0r_KIxgjBYfs;ZxuM&v-nhM2mfm%>)Nb~1q z|F0hMtLPjTrj_XInf}42OSUH>^Cd5ZYvsUt2%oZt0nl^*?M4>Sli-P#9L) zaH?xOGwgtLC8^r*D&|?;{kbS%ntJ5Q?wBazl`Ex{NRrq1wcp59HSsmJl|oC*P`gzX z72VNsazfbH44H8u!K{bf#)UM%$m8Q%uB4ZZj&L|LRp!O;Z!D)iJ8P521Nja5;T--W zQ`21jud8KqC{L@`)*?9q5qZs-g8jC47eXohg%@`TxIvi z6Bce%Nt-%q2k-6P-d{#T5z!UH!QNnim*RM z2fl3nTYtgURP7nxtV>HrieC)JPw6l+^0%~OAVdm#@4+kZTo-E(e#}5JGS5pRm^R5x z+UZMVJq*jx6#;L1&Aj-^tUU~~(M4F?=)e(C_ZK)GxrEZ*BJE0j!q!(0UuKw`*=>b9 z@Az$MuV=;9Q9j0#n@)4=eUdWYuz3B#&qCh5qv@D8fKt^LYma}u#ON0Kl8a2pO$vps zKD<7B=Y^Z^sN~-w?3_FzWGgy%u0M2^^up3)^hV_yItwq(aUrQdi=xM53s>F3i>*rx z$%=-P=4_4Tj&NbkZ=B8PoX-{Q_%jE{*VANO()o4)qVhN@P5w`iD2HVslWE zKdbrwzM~GWl9ie$jrm4zDn;ONa`=elsCL3Wlr5GzM}2h(AGuw*P$-eb$$NuoRI z!r!-QH7J*f94`$UAzRR6-?gL_E0<}&md4Zx-_v@fQ@y?q+VDBiYSE@f{2{#*oS)PL zrMM8_6ekYanfV2PAU@tl|%wBz6((l#PG;;+BuoY&9ZC+)9_ZFAnT2*u26Fy)+&8e)@5@wd!Uh&z;m z3uPunohklsQ4-F-L+6DIKeqKSD7O+GH?3}bWoAoDRUxxBS?UANtNc*EjlEZ8X`Jbi zaJFo+=c=|`Ch*huCrfkTeP7Phukvp_+w5r%f8_{*XD4Z}+;AnDswURV)(pS~)74;+ zWY19ehT}i>A1s$_X=%R8$b%LAtGCYrKumCejU~R_R93U%C@6jDU!L4 zEk(kK@{M#y8pn%sSKUO)fMnre@HinU_;r$y+nt&)m{d%!)sMI-E1#>SHa^%y*rog5 zDR?F#2u|AO-f$Mo-5AcycH&iwPL?v54;Br(Bq2T1xfOF4XL9T|_cWR^2~*qcab^Ye@mN)F2n|f?-BhI;0ef$+ z$vxI!Pw8F(>+CYP=_I!_EhXveCO{$l|ZwVdlP4WfMQHV$sDl5#&v& z4D-&E->N5y*mtH@P#R|XG#zh;_ZD*f2T82R;xy^wV&n0Sx(utznv#?yU>(-p_&pnd zbbq1&vv%JR`Vii58H`OaC#IJR_naa77RIR;Ted`?kM<@=EgVz-#!!~yB1Ee8Su*>% z$n6+PR5$xtec&nqx17*7eNxMAjFK(vx_6^#&Lf5g>0FvQ-(RA4yShq$KS;y8^q zu}ZiMK*fl+2iZjr{4BLFsYQOgpRmlTLz$7KWz5U2KK4B_JCsb_K_r- z>~C8kr#i(C&Ze%*Bi0PxQJCoz&VZk$_x|X5o+}1mRd#+7>nu7SRKR{slnn;jg22qQ zr#UVg=p&k#2eI>!7X%omkTu|yPiTdW;y9-xfapzm7gm+{Pwa!%@ALmgQ z@vm)XaCubR+e3kcBm(Y5r$ITT{Ch(I+9rq$%Vk6lOQ=p=Kop|WAknp$R)YWmrtq4w zVhfk8gU_W(8~bsU+-@s4vstY2?V^4bq3oNbXkgk`{Z(qm6HcenUew*Tk}x1((0 zB96Mwk*hh3Va=j?nzQY0exQtnWFCy32vOcl-?iW zA9d)hg>^X~V(;BmyXVnLYT>}Xq8~ePvz$pc6fkVoYo~iFx=iKfN!|p_N@m9f#)V$q ze4|S-Tj0LpX~{0DJgg*tP5WIaZB#`TnTa+CdT2Y*7x&)tV$0?RW}EhObD6U)^ik0f zAZoMTt&W3XT1!-qoS^nHr4<}=6!ZRfg6F4VJNxdGv>bCrZ7fmAxj?z3ODpO!2}hEw zGFbDtdwfyr!_d;sK-)W6EP3&GH+ga(ef*j%7+~ETUl`q_ESrT!HKn693ENHkLXPh`a0kYAARsEfU zE^ZG-K=IJhTn_C(@HT4rH2`+y9f3;uNy(+ccKWDM$Lg?+C2kW@ZCcEkcCReB#h#ok z9##7s+Y5TQM3fUmrnH_ziFd8b?M~!$3h#GG4thGUKTnO$Lme+z=5AfHG&E48wCc7dFYuslkRG1XSl-a%NZ>SCD zFC_D2GSN6L7|?^6sdYqi=1dNpi39W6h1Dd*Pa!-=phO7#h5wO)a}=(|69R;P>Q%T%*aY71>F z?icNV0itc{Vpd=Fj0F-!gEK!YVyTXa#X|aKXFj*SW6Eq_{kzik++Fs*^w~6%d9XcR zRhRZ}J>0%FJ*!}5*d8r9@2LfWRJ~49TMVvLGS`NPL!@Hv?(%+zh4#*0`tEj7LdGn< zCE9tx^TgS@^G~P2E4}uEw&mO1VOV^@!n7#` zAyu)%$flRh3zy{i3YnZ}Cp(rV&WpLQ=NeIHg)y67Xvp$0#la@@2bdbeCq{}s2$m|d zwlPoai$WM!s}lV!{pZt|UecO${Y^&t8e>((#-!Y>SkcNwJ`K(nC^q2+o$`TRtOX6w#%*Bh0`7EzY$VAY_EmAc8juD_%qpT>t?NO;hYWv9T|% zR+}|h+9p^j)V(;2IniE!r)>@I%?xwwLxpmhz*?34Cgxh07-bL3 zSs0pgVNNYGDUUX@8zXv@MmtN*NaH3-$LgIRT<7K^gQ_h}F;xmf4dC6-Id8xq=9LAr zCtuHHN#ym;A)M)1y;Frh^er{bwd^5YN=5Zl%9vtpCLmV>eu5w?NkGEMw3$K-!o^yZ z5^%jt{7a#s~vhR>pYks2D!$%_g+}NgZaxk0_AO0jpm>-!#aqm z@%?+PR}WB=jhcY1((=GVW~!!i5Zq3Z;AeMz;%$X4dO9(JNLqzCEv$!mV3wwr%`h~w z_GWPHRQ0v0w4Q^ymm5onFCJEUeu8uRlKXT~$BPL33oAu*c*@^r=^2-DiI%8Tr}Szd z>3PRh=QhFFt?3pqgbW$FH0c4{6v03qyt4rUh8+wmcuq@rARbF`3c^ zv@nlMA$;AfbZR)Bnqry6)LL1*!-XAcm!?zeN|}Bpp+#G@-DEyjmr|QHe-^dxW049w zG@nf(JeqA0aHIHHbz#^9rLxfC?Ix34Q+jF=wm4O6z#OXAw2gULJcEd3VD%0X{;!PL z5~!Q}tnEoKAu{*Tnlv)wu!uuvt1+MP2oQ>=xBS`!jz3)P_BHL80Xuh@E7hgzn17zt z3VSFTMa5bbEWGt&>F-R(iB1l(x7gykA1wVYB~D5zY?1`SVNX}X9Phw8H>IkA(-?y- z^c0_g*5r-;Sh^YSV|r<+K-l-|I3*F6C@SfyVA$gy8cUUrb#?dc16PT*=o!F1sN*G6)ph56< zxgeY?ErIFGwXx8bk|nakI^@zZidYfi^>fusq2O_2Ww|5H9X4N8W?Tmcw-BPIO~rdi zl5i_zT2cddhE}ec>>K;!gCKD?nn;0E|2u*6Qvn~O_u?i8TVi`ZqTc5&Zpq6l^T5Ju z%A9d=elBo!pT}V^30YjY`iGbo1$-Wf$LT~oz|2oPHEe^z_qHK)@#ayr<5#Q?8BtJ zKfyxP<$;gyi*X^SavOt$oQB0kPE2c2adkv7rO7bn!iX)DqNS+wjI~2});Y^+vQkRe zD3dG|m)awS>LTLOI_2bO5B|i%?!}!9iOxK1#Ks!+g?)08UzWQ(wuZ~zkfEvw;^|vw zQY?5b;8$HN@?3Q#wkBuGV2A1ID)rAl&|ki#@x2rU%2Vj}xIO6IfYNmNxQ|?LtN6QK zl*{#IOYL!A{R|8RTxxc6u6Tgm?H?nBVmex>%kMema4zEgFOpvZtycX=h3HE_3P zFx@8a_vheN04fS|zf+@~LYXjmxs4CqYf(JP(6 zTLqB+h8Aj7xCpB8WZjgL13g?I9Z-I0a)4<4#1#W3vJ z1-EeMU*FOj^2F=~O7@|J4-3sw5}N_FiY`5+tnzcC8~%5)E}g%hbIu^1tO$TnG&rXn zV-%Wo3G$=Y){*k*c{#_$ZnyAAu6PJ^bb&C{tWAn!o#D2>2{he#r6VGH&7Dq>!TT%Z zi;ny?9p?Q%))@bmqf`+4U(0!a2@xXO|{AiPoz^>VFQA+?GG%`<~_90Mq`#2vGvH>#0ItCl|ry6nos<#Vq>`&*|0}RQgh0`-F>NtTP)5 zaT{8I&Nh3K&Xl1j-}jCSu6~vsBY>aqyK;HM%kFzymOFl?n1P7iWq14zXlI4XVFS4e zuQTjrcY0lt!#d}L-rv}>?D5O0gJBUl12wx)sDJ6E9DN)Y0jAURrqgODB50ZV{nL_5 zxwgwNFinjH3YUo=e!awcG2L%r^rY^2>++;h=h%zkdhDKUKD`Ec^CeQCJH1^<7E;eEPLWnGPe-t#gL0EztWwMQauiSmm zG`8&bVkOV-1$ou}G`BRj4&B(^Z<1dyA^W0eHo*Zg`CT zbDY*uIjv)NN9cBCVE^(f{FC`}i|adb*R!4m2IWvj-u+n8zav6b@;NvSk6$={<>}WM z*-PRjpXAXFZzX0(wRwK`R=)b(gCYSc#X0SkdIfRqKl_SbQTuC!>kG!0O&5afP*gc= zb9Qr^sx=3`$u;;~KyiesSA6CZ^5E7;okDjA^BkV(d;%BUG6&EOa&Sp6${k<%rvGrU z|3A3Y%nmxwFPVJwP^`DNQ!l^Jq6VdbKSLOPKah0}V9HBtA>(n)zC;Cwa!<(qgqHY_ zJZ{V9hFx#qRyMpA&zRX_Ik1|{V6eLY`dV$97MY7~<4&egj zu5)1i$z06V)8oVJ;t)*OcxCB$VE%zUBX{zga7gJ@_xHmk5Xd=;T-GR=-oo4q?kx+4 zL(=B&UMpg$xi064fByRDGtcvkvCd_W+s9Lz_oo3D&+vPJ;>x{I%=mz$sR6lYT)-fZ zQe!bgyg@-c@#eAe(9Sj=!grJ8$0h40=&isd8%AqhJ@4^^>pEQEpYZpf_&-3qdwthZ zEsSIviriFUm~vVMiHx6P0q%jnSXlf&?T2xkSSkb)$O8W9rE|L8^#m;b`zfb0hEXzG z4f|$ZJKIbR!{X&zExY?CUwBGW{;j$3J>f=y$D8Zp^A$bxM@clX? zm9oe*gavm*KV-^S&`7z#^#eOw?iNq6#oSt%`nn<1O(gI9!V#+WV9P4_xq{2Jn5P~u zO*-al#Ty=UKZ*DhGV{mfR$)MCP~zKcil1ShZ)n9zW7 zqcJX66UkC$p@z~HzDpBQU~RSd%%9iA=&yU2J?l`;_tdC>TZBU^I0gR-pO+tnf5JH3 zaBN zwbAG<=j&dJnLU34X$fSH{1vi!?7p*YBc5V+rivE^HU1)bjmr!~8pS!rr!4dwn!5gJ zW+$e}irSzjn#fH3o2KxczXOUZhCJmZS!W{F+TEGaB4SI#_qjq2h3+b|%eA0UIog6I zkt|X3J)*~x;7N}jBW1E4pL!Rt8$SIJ!QBbg&wGVWE#rG(z&9n#0cAnrX(;1V%d1<$ zY&4q6)C2XQZhwV(>3Vf)P#L*f_qX1Rc)zr1n`fhMQ0Qlvb(h^>?JX8K{t~v{4ZZqAw}$ zI~4d9?|VG?eAOpPTD2g=E$Lf{Tb@zDV-eGv(_;Ll$$q`#*3{yS4Ps#5=RBq7AgQ#4 z*-&o|HduTY4u>QZ1e{5J&rTz_RNc-P`m!!v=cIcQUZOIK_Kg_**BsE) zt*Z5XI*A>96qlw$%pcTPZ)bcx7uc>DhvyAeDT}re63q>WyhQ|SBeegwp)oMd>BT#v zPdvq0$_7Xg;lg(eq7>XmLdTX%Yh?m<#!Qk$iK%B33er-Jeq@B2rrbjzXpHT~>bt{i z%->AQ=1};j`Ld|LGekfB7Cmm}ec&;uFd%n*cR-FdQMArD7iWv&a>XZEXl9B2DiCp6 z8$GC`GK_r9co5qsYLjxk1kqz;m)YJuZmm^SDlqu$)95!2=yV^e*hKbhUeZl7tz+h* z`)|)!UtZ9FfUJ7PO@k-wiH#*4r6Wz@5Q;G;(gJ9}*XI=$sU2o1##T z;5JT@_?e>N`V3vLtFjZSUVN)4IWtAGJEO)XrLG)dz8Zx`&Y7PcAIj;_t?~-*CrH+< z9hhZg#uvWYeV=lq-l+K(TR0sPoc4!0?R6O-$N#$sr}m5dsgrV&{>QHF!9}ert7G+q zY-4o6HzciHia;5{{NQIG&UEdl)6XtNi%WPpC5`UbG&!uT*G>yx{;=K%jsCe4yBnj& z+PtI6_N&_qZ?}G$A#R#{qqFO|)-i99XI2WVFABc^Yy!>kG`A!-Yp%s7be?K57C0RB zAtM>$H%6iX5gIi57mG=I+^EnW9~7P-S?Tqy3whWL7I4@A-S;h#%)mvgC^`8|SZHBx ze6HJgRXIY!n4kHd0(XT9-$_3C!DcRX62SxJ&=||S{FXSRPtW0WAr2g)mZY_B<#V=6 zP21(nz_3o5dpm-8(=2D6EumJ~;D5^U`zdtAW=Y|9-hpp}x`eSzMxcWr&qIP6}(G|EO*Zy=X(n`wU;_zBy{wC zDq-V363DzR)hC>}m=e3woq8x!Wh<5`krtcTBS2@ifdB0+Xf=3;65R(M;*)X_%M48M zUci@Y9E{Zzz@tkl+k`VEKAp|uTUtUM7u_+8RFB?Jx9wbheOeHEfCrU_ZOJxQQ z`!3k-=uA82+(%M7YWkP)TTSrYhU451^Zexac_s=3;2hR#c`|MA@=i;@psVlo8C7$+ zsR9jnmZ8*v_Iiikl8WXWGA{~md>w7GkXZgnTCJK-H8V2d4C~z4EDfhFxG-zwKom;n03HTAde8peA@#jgLHJZMq%(?c)78Hc2ZP}fvOR_C$KyTa7%0=KOf z=64XMimZB!bO%L=laCc8`qLs|Cf2T67Ta+pP&(@$rsk z2hC$elaKGx?AL$|72N-k}p;IBROTf`_;rn-uXA@_nD(sTfE8JbzqVS#ORV{#(l!hjI;U}%H zeE?2FwSQV0b;zRee5bE7li~Hw0|~vaV`RY5E75NmyuW6riVE1T7Vl_fSQ=8xJ9Pt>DYfbdGc1rtj*4Nz zytOqkPm8jJhkEJ{O)u$~r3qDgxcc9<`1X?}Z0D1v&LsNLMq<3Tn4UQ1Z|f&Fl)vA1 z1y;Qm>Om7S@D0XbZ+a6NO_HJu}Z}9ok~dldbd}~HeVv5!UHvt z^k}0z-C>!kvM@FKpBet_-K7S^kgvC{>q#xh_81jAjXIz0p>HAC&njpIdd&8&ZkT@d z9{;bxBXWYtpM+_P51P-HuUBX&bSaegir>)1c%#fPiyhhQzcN1+Y(&Ebt%JKubcogg zFJ{O2f30)$>@9L&u71y^oyeJ{n^`hxhS^sJ3(7?o=xvw|?A_Nr7TfksEUomwPB5W2 zkgX0nkI6$Wo{a3*?2gq@kSC1q&Ae$ga1+3>={h3}gkgh^N zmy$O&x>mfqWX_bZjTN)A0ZQ-r+?w4pk^}Y98Is@Q6}gC>eTM#*d7bAH0p+^RjW{xFN0 zn+rKiMvV$N;_g96imw*j44enyhka)7H1aBd-cECGQ$_7rZy$woT6mR*Qh-O%yjJXyU}HSAX=CV>w~I5zwl%wALaYqF3}(cEwEIu7 zbj0$vD#(pM8U7G`{2Sn{o2+zRRBC>hkZIarob{%63n(9#_Iakz#W6b#FAprQ>F(VZ z&l?jvc3BRthDZkMrHd-JCH>W143;j@`MA`FbkU)U4$v(y)1B%=61A>?>w`|Y0{|_g}Y}^QixB3>Wru#T42A{V>8Pk+^myw4{qlG@&oN~GGM06;@!yX?jRMj_`5=?cKAspfsggy^7QlXVzLApI#IkE?YAb$bNJ`f4Dz*6LGQzuh14^H= zegb1>IWKx9!Q5YwkDeoIboytS(6H)O=(}@1ZlUW%c;f*=esjgWT5Pi!L7mP*&EM?! zUAVWK5-c%>q;p<}4rxX?hT>hFxG}yzJK?2XE(3*gQVWDQzs!v1K5Ao#;wz0{!h(?C ze8S-{Ju(Wg6%BJjP>+l zdfd<6sK;KdLG~}bt2d*JD&}?Ux)DnRjQF6?f{UD{7;rw~6YpC#u7P`4;GpK*!S5fs z06}@#>g+2o^*9(HG^9o!_c#i!C<9gIT;<>8y)km5esy-*Q{7GmD%!iQ`Px_gyIhTQ z{m2peX2=tdXa6>E2)|pTtnU8cjV1gnKvV*SDg(1KqQ2(-BL^8VJamISlb-$oiLAGI zMFrEQ$BRVY2*b@fFd|BND<2Y&%A!aJv)2DJid$?O)@n+ zoYAD!13;eoDLqo1(y%~9DxU-QieB(4rTqt$JvvSfA9@WbN=T-PR2)YZ99&%r!L=xN z8HBy2_Vh>{%Bc6eBnM7p+3LGe7eu*ZHTWgN$dPsBcbDN89VMw9fkIc$`Yx#C{73u9 zK-~dtBGkU6NN>+7I}1LI5?5eCQE})5J7nEYEB<48DSmQH3!yseo1ts3jk;?;R4Kil zbghMR`BAT~_|Xpf=H1Ace!=Xu#rd7*K{s*&ukhr|2TH>>-(23_U4Ap0p7JcFufRZj z|BuJ*rMkteB;JupN`99D;qc`TyDdo`qnTQ9)x5;Ox=g`ew)xmDYC>;d8LnpHYE8M! z@5ONMhnM8gAF`1Q>yLQ+1e{=Yn-g8d8_8D@2m{!s580*z+Fhm)*6(+{I!T&yN~yJ@ z+DKVQbycuKj`UnNi>v^6!5g?K)3hiH~v&6xnc_eT!P+q+qenjh(e}NDh*Av_C|xzFL!-bz$ROb?(kgX0}cv zWVdg}H!;u?u?n-J?d^K9nLMR^M(6NX7m}Df@V+!1~8eT?8H&+z8Cgu-m;(6 zbN+eE{_v5YkWBk1HXhI3s%DdVI)qoJ~w91?+WtDNld=IHoe-H;2<80d4WO)?Lbcrg<7bg zS#-QPS8l&5W=F2#>st#kJwxRr&4<`_^xDIcY>V>7)p=83f0I_yix)JKYjLO%YOgMV zf*9Tr{v)JV++&dcuqeQpa^#^R9~&zBXdX_r+pRs+(s30^Qgv$uF&>S(8F_zN8-rnZ zg67@_Gma{AdeX9Wpnz?;#{~={#DvjW3}xo}EA5W1_kvkg)3nHhf{R=Q<84z$deD)^ zHyqwi^CstCd41aJ5#Ao;msy@Sm1Mm=ua%P5 zjRv8F4qcZ%>+)CO<{v3+!@*MwhU7YQj?Y=6iZxq)wOg$xmU_8k{f%drKVG`mr=KQ~ z7UMCR@@O^jm6v;KZK9xA;sVfk<3kUX9h(vma|eHB%BfjPTy%9u9qN~`KjR1pXgw&) zUG*u5d>_MZP_KzAMcI<4Nqjql^(Zo|zT~2YL zmf>1TW{i5VLy#TNx{f(Vo>*5Gi`o}qzd2z2(eHnI^gsar%x>!|Wu_+A;vpJRtdLU8 zjM?_e^~4PeAiMCjA3Z96&iq8zgRe2IzxV^*pNaVuq|HZ4KO}-xHA!~?;0kI@ZVim2 zc=cS&$-Fy|aFCu?gfc6qtAGgyr#ovoBO^3_YTyY{7YuPXMy?H*x~xB7lwChti0 zvqG0>f$Do-h90^SwQ|R0wKc2ZM6`_P6f%89TU5eFxvJq#)_s$YW4%|_v>9DB52|H= z!(14_>K40bYaW9<%iBapV4E)zhZTVO>QD1}f?Y(v}pDeAhpfS zV;lXcc>?E7B&V#F2+vIF&HkBlwm@>ZZ?Dnc_6fH)@&1d$nI3|CtxlEQLCV1< z9|w8`7dHauKK?Ch8eG&4x?Y`}oT=HJJ+PSSfbfu5t&S_~P#5Gsm;+=A(=e`G!qUqr zuI3kaEjk1ZVXL4|q!at=qnA{WftIQY!H&Q{`vofv%lKuFEP^+9%7epI8M! zHS2dQ2$JG)<@>An`Qe#hE*-{mE^)Bxw$#jpKG8`77a~+#ZMnpZhSl!3`?jCn{WmK0 zOmY=`uqoUt7wU7;)p>qt^TBJyAZlw`89Vmb*$!2A);!f>d>$$=(_c z3>W+(W&Z(I)}D=>PkrkHmd;MRr}x^*m@W=1y6w(TZx=o_NJScw2_yOAhWG&MYQB#E zb@ug{)W_}~=IEsD5tGi|PasSU=;D-?PJ^ZQ^q7IPQ)f#kn}W z8AbZrIxlj36WQg#iqF{&g9W&6-PY=b?-l!WJhHxUkXV}?EZWlBxud#AC(q%NGg7{j zN7^3H_(}Xs<#!YPM^58?P60NKyew*RAd^S;cb8OQ6u2sX207G)Hb-P565I=)$(ttR zkkiN8MuI^gNX`Qv$0S_ebi1{d*0RIz#V!APi5L~r4|7RxG$pooGPj~ zILS{=L(d;-C|{nvJZDN$SMaZSB(M91OHA){maG@OmQcR!mhR7}ERWP6Y9I~^az0v2 zu6HvZBntI7sn4AEqpLCncgm)mMYnjuAHSLy`5`11(K>#lE{X}8q`sEmvg>vs04RGX zmP^|bn2QQfM~H_A(lJ0v)z&6j>DCjdNN$n-wlM>(%&Qtd_6qQyAbEz34mlL%qRVsB zyL{31ETUvN9;1OU#1*9J(FeB;e?~_+WaH}6gFvzFnpvYgbsm3c7zpC|9&V__!@2!y zyh+lbok@}3qu75XU0P4r+5w(T*IpOgTkm@d;!3$3jTofAsj>Y!iM99-@j)OrOS| ztnWxjqN)!|R51q*$)?pO9@|F@@AkE8cpMsVu840xnUz$QDcAG!JnFe~V}wdTVe|kI z)NoowMdCLNv2qHiKh+_US5=K2oho9ZDTVTt_E10Rdhhm-ZUqIIx9Po^8OSFc76gKS zHjO!dG?mGNK*vAr7#3B>9`Vc)Wphs0B9|>4to`b*|D}{Sa5Ozu+;Lr797eev&T741W^Xr<6 zpcY#=piVlx6rzwGObwj}(&6u8dumo7z3}eNMp|Fa^TEbQdGOe^qo(kAgoy zc%87$!-HE_8*&O8tHh=O3Z3evkdRVvJwlCdI5}LA6|^vr+x$IwA#)bg3_<-H+6n~G ziM^g4a*LbcwWTL0R3G@hfaagEq#F~dJZbs6Uz?X3^LxBq;E#MRJ22*El8SrHX-DjF z2b%$-p!VD1L$h!_sO0Q!czUz#@BZP{W9KWY)ycznP`EocRoZMDSYi2)lvXM5zwx~9dF|Dc@3??47ZU~}J}T9De^{!^PvNda5n{syL@GM0Oy59WW@ zy6KuGUKCAy#H#&9GaSQzWrj!6b*`XBz1IYKbx(gGP%v?U#U)%bv6Me=Y(C@MSc{fh z0=&#^)r65GqU*&%^l3EMc-3+KNx_ULZj)t|o|dwPe@-7%VIm<)>u2c~-3S(xnI=yI zzs%@7+a3^;>|>jcpLc6x`w^5j|1 zoh3~4^1JnZ(iL%MP~O+Fm`*HW>C-2b%~DnJ*%>ExilD9$il{&Z6QI$GDfsp>Vvy&& z{hZ}@zFQ#m3^5HKY-wJxQ&D7H8ee?#J@P^RCh&^eXQ@=1Q;;vJ3NVXjtQPsZm!Q5 z`-StaEC*ZxUntxUK~cFFkpw(ipA}e%;!0V%)M(R?s@)web}!uJgDlQ6xWUzY4-NTf zL~)tG=Wsb31hv_{NKmhEO9u&Y<9Bk;6L!l1(L_5DP{@sYtoboV^-fERBQm%fO(&{h z$ubtdbGB*xfejp5Vg^AC`ytwa`&KX^2_};GnuQ2G*7arK>on$b6v4T(jHT{Kf-)s> z^f%aWOkB_EPAmogVxtUu8moaH2L(!yDC3W(h#X03oOu7l@eZnlsMdwKy!-sIB5NJ0b-ZA<$@%AyXC?F;LIww>V5iPu?{Y1JV6` z+Oc%$^_WSf+~^vn-&gQ86_Kb4Mc>E1a{P7A5^s@Ix2`AoR=RB;=)VLu#+WCW|NE<; zvGq5z3HzNyi=~=jR0*Qon9*Dkw%HIQ%$lqJ=0|tCJ)M?Wi4J}_i8!XWbm_am#b;`S89e+NyZS)Syq_H80HSO#8P zF8^Z5v{GQ)C<*;-NY0Sn#1*fZvdZJz;0dZaR>jCD#}tlIfL1SHL@3}5pj5Q@HN|68 zh~4IlZ(=E^F|bkRtzlZ~9km+tXN2M&i+?(HQ$#;1*8L1dh%>BM9Ic+EL4hXZA2|&b z>MKulSFSGw|8>41?c|mMBFDHLr~auxx#*nq_)a~Z2L0N>ZZmj_mWVK<^h_D17=u-k za8$9RS7$L&{zXb{72-m`_)?>=a^h;Y8DZ?q6$Waw?UyS8ue(_Dp%{r=cRu@6NF2HI zB88T=M)vMs2*os*mtKCU{UThcCO>bm`ZKivgh! zj(aAvR;)2?Fy32F>_l$`uK>H{hw3 zR{bG|uW z`;FIV*6FYN`!DX)jtAn|E7gdBrqa2qp@XD9-cscrI=R@h&R$)mMKjz%;jBs6C?|o-#=F@8N5+0hF$dBB zN6%rN>Wj!w2jqf%5~m_N>vx9UD6)@TE_JcA6LrZoT_D4By`T?{YnRe+VfQH$bsS5T z_+kOPBoEpDwQ%O~Q0;FVzqj0^E^1obWGMzoMx|^MmAH%vMG=O|r4TYR_N`kfNyv;P zduq_6DC-PKSz^f8V>GhQ#8|S2)bBa&?~h&`=bZU&XZwDi_viCGtp1dc{JuoUE@ix} zTg%;}?W2a6T}s%?sOnFOnXW^3ixt!be1u9fHR$%cyYfukx;_+N!=sCF1stuL9u#+t zJbPK&P0i~>?(7bKS>^^m9C$fg zbIsYTEiH!MT4JvtC7{o_L*X?I%I6QR zbt$e8pl5css!Ah$4Zj8BB#RX8acGeq+}aY_$rN|J&x}Zzc?aVN#W*%c%Nl{C7)uB; znRvrLRK7bZQzQCJiu-hrmcB>Z4cNA`cxPHdSmT^~?c9_bsJHTo8+uSw_nA&XlzL0TD+lU$5phEx^X8fW&gNS^1XxqWz(cM=cC$27i zmUB8sIyfdPmo8Zlb!~`IsNl}A5aueb+|a=2rPR<6Tn{8Wx)AplhrxDdozS4KNQOUB zJ^4}bvJ-;EOP&MlPAGF<&ieLG{?sN=yWzHHZV_K8$^dM)d zSuwG06xM*XZb#rF)^hA(+cka)`biqJ?y{4Fj{2_m>GfBrX-BZ|rI^i{&5H!uZ|p{O zDkK+hoL9Qod#@y#%3#AE+3SBqwwGU$9XOU-bmaJ@8ba{jE6YdHRGuLzG8>U-9tIr`Qs7T zg^tg~c$Xg7Pk%b9Zs>K7({3lIL_`*6<$SL2bqevS93~r-D+iv9-i2*Ak@CX_3K)Kx zmV!TCRKISiqAI}ITxbfuAcg_fS~cS=Y2Q&X=#f3Dn(cEXvB?0o6NP!|8GouEjXc9~ z4sSpXgrJa~HGE+2$1gzE(=lxxPa)QFqsSOv-zttw+++W*a`g+$`a| zhe+m7Lj@wqzDu6p*-g%g2Mfq#L_rg)btzHm6^u?+jUd%}p+l-o?T!&nKh%DqbDUt| z%Xw5n#&Nbej-!@*q7_$Lwi}L?R2^{y&ar>OVz)Y(KYN8g*R7olqgj36_e=ckGglIa|7qwPI^}05#XFL5 zE-fwB2ozWYB3cU_js;4FJ=>DU+l+iC<;x8oK#ShERLmYT8OIQhaH#9vR=a2D%W|{BV!GKs^q(w%yIhV%ZU~0aHjo20(55qZCDn`IY>fyhQs2IcdVxFXs|MZ+wXt?5{qlLCGDb91)w;3Lj6? zX0YdA_Ps0OhbX6!v@uOtRM4+8o4GrB)|sY}bjpqOUYc)w{kANNC>F6E*q8j}iq8$_ zwgL(p^%Aa2J2m(YPIwqb@+#1_xZM~l#ebMbf|$|KjNOtsA07^0hy9d1X$x_2c+N!o ze~-O1)AV%j`de7`UXk&B9kTH~ZLJz9kx&PdmEgla`gcJ@tv{M z@*l1vdrfP%MK*+Q&%Pbmyf%DJ&x&E=VMIKfqu3{A(uH=WT8KLmUQc(xdO^TZg9v9+Bv zTcF#<8%W0AwHZt)oJI6p)%4y0e*c@9OhdrAYFd>D_O*-^eBArlN-R(PdKVuS^0D>V z4lqXYNi};@jzR-vZGp(Hd?h<*Q>LYGi%}hlWaBn12Kx;X06b-+-;NAS&P9Z6U+XfCnvg{<~Wi_N3^$W(tPP^T%`RZWm+l{GenzPJjsZyq95&B9-RP|kjNk@9( zmOV%g+F9JxRO>GX6jW{VW5Ue>E$8FDxs%A+mQ%IxqzrE%o9O8#n{Wr0*^69oCth zdG`b1f=|P!P0AMsj%nAVww*BZ#N-@_pw2cVF~;Jq_(Hu@W-3n2%=Lm&_#sTz_X|#`tlooRcM5v+G!~$)F%+yqO zGrGM}SCVDHTb2(mPKQiN)23cdW4$yLaaHn5W!@9I6S5UFx__k-g3UNWMAEc26`M*g zex`Oy*kJ63mI5|S%5P1h{QF+%{$ZW=>l=YG9D-(9x>d27M&dS*ptTCaDXG>DGTF_B zLF>PZm7lG52U2$n4)PBH_hmCidP?N&a(PExp&ze4rG%^9qqpWU1!Q;{mj@Wa)iR6z@+3` zX38!~S0Afa6b30;VHLDer5+%YQ|^oACZ%<9o@qa@(YITbJ$i=!^lr$eAU_EkJ^j+~ zY5~=9-4JWn*SG^@(gvLoY>|>ghPudUUC?K$zphpOg9nrzg4Z1n{e55{v&b;~Yy*R< zZmK%lCg&n|o<*tP`Kx&Z>s{t@oFin?ZXK%r9Ox}@tA}7Q0FkP5AS!f)?o58inBlMc zeo> z|CrvVBV#VohT&ZHCU%#h-2qAF&G8o2XltiM-o{)`L&+Gpz^? zmFk*O62C`rJcs;O^H1XNYlQWQ3I^|X!b|m5G8}++D@z4|j>LEIk4GtQNKganh&`$e zBW9Nf7z}VLg|8ZYX7w)236YnsMRVgKg=_+*GLSmSYD&H zPYopNYqyS3LXJu-W?#HoE7}xOL3 zyks-d+YRuIGWS3HLZz5sZxN*i?LSfm{f$qK$fK#NHGk$mIjx*$5A!(it;k^?KnIao z`f%>JgweB$=OGff(|CIsLvua|>O7YasRD$0$|TN5;r<)ib$bLCAF&Q3es7X=+C)w& zLvOMtWakYZPc*m#y=bJ)Sa0=&W%7(qKcG{E`0>H}9oFC>@%hVMq*s-0C6SY*qRfeZ zHc2_+PYeqz+_uolUy_4vZ1lnPm1(KkQ#QfvW&I>e<>%){H@RAdLk#^en>Z)2*YorYR3!NL=_S2O1!wzV;h z_SH=K@6zF?DNk8x4|xd%L^6))tlruLM6gMtbT}M{U^s8vl4JM>`fDnUOFuP|5ONGa zp!kGR3`*G$L4vr}&!(`*YQY5(bHtuvU0YOHJf4%KIDj^@>o%1(eN79D27_Z+*Bj6W zOM``%frsKxmm$sc>Tvs*f z(y+zndqw;vYfh9pB|!-(*bvJk&;vz|lggQ*y`vMec5NjHAl~UiK3Jyk3;~gA+!)I_ zQ@LG6K}5^b)dSF_oo!Q-$5%7`R+x=lqV-9NocsU&o)*}j(CLWl>r*C- zM?cxG#kWdiU|;K1vW^|?IJLX9?)-;Y!=5UnttUL8t%TnbMf_Yiv+ZhmT zFhMuMk3BhxWB}OIO>=G|%wq-`6>d6rR=6K&S7(7ZEl|vnAq>z^1xdhZRpoyhI&%n^0qW?YyoOD>ryy~8jV`DXuA3K$@25nR4>l3qOqp{|4aZ1c;`PbtE zj9K*MK+CX|p-Hd0fWmE>@pL)H_l}g0EMDxES+9EmLAgKY!|zd>w0i)GsoSRRZ^03zMaf=*MvB!r^>(v^CUF7$VdP%7*R|5P`G>tR)Ue8pMKqB{d9wz`xA88dv$ zoKN`evlow=N4>!-o6IOSo?=yu#>UNi*#@FbkEJF!teeQUf6|--%F@I0=%nYew$W$I z^)r>u)>F0ku|F0;4sB_(UoIh6WoT5<^xMGUd1G1tLsPe{U1riW#+@9frP_HO#E7&Q zC`<;27thHuvZzPk=btO+hQNSvy?E9e-j_M!K;&1f6q(UO;)~g#FjX1Z+$nBNGqPxg zlbxp^MAWEK*}Ag#UIcw2n%L>o4dOt z-#IpL|D4(#_|cA0i1Qks^@AIsAZrB15q-!XwO&_5N=8{vTq48BH~$zR`2X7)KVcgL z6C&p9Y2!D6K;r3VM-aMO7hn!PNYjOh3WASj1)K?O|)7W(g%j1gwxs zGa%=M;WspCs>QSNpnk|y!R}-u+`}h7tu7}mI~4Cu&iT-5QC0is>X`Lx?%{Mbvnn7< zv$d@ih;voQIUuA+&n_|axz-%;yBL&_8WegK^=1?ypXO0Uyy~Jkgw`41&J?WCpnW1T z;}tvLE3Fp22|-kH{}#(0xRdj@f6x;2545(Rjlul+H)2ra{hm3ssrlBoW&g_UA5Y{1 zc|P42#U6nXq;LJAe8W2I$IUygqvCgW(usv}!Wv0@{MWPqfRVLv25d7Zn_53V1|G8T zXiG?qHycd!IDvF{@B(5*y{I4Fx_I~b(!uo=dK-=tWJ@xq?0vxnwQ)+iQZMqjDo8B- zlYRgiHmtvB-<|TMSz)Mq0)9=1LZ75H=leiPsCexWaS zt@6NWVL%2OO;7gOW%8=;&f6y=j5p5~v3JS_tz9ssV@EE9AjV!LF0QYOza%0)6?Nmd zFZc#Q8VkM6@Ddh=ZiZ_cw=O>K48D-iVB@`MfZdKJ%3YTbjIF>dFhXSSk;XR;V7s`Xm)EVlmG*Rz z(K%`1u*hGm{r9iF(sqyov5wk6=ajZyEOL+q1TF*i({zL1GaW!2aQ5f3_Z#QosssMD zl5`AP{^G0&Qj)HQq8$&;zoz%zsu(RUY7U;veRC;n8KLThC#<8){bMf`c^$Mx zKRbXdM5dV)+=S-ZZ-sBsk8Npz2MDnVEi&^lR(CC*8cPxwnyQ&0UxV7g6nhl?+kw;s zShNN|U6~))r;Pe-XPz;BU3hK9%~fcYTHfd=at~0FRZ#UiJWoOV^C&It03kS`W%G1J zqnjT4MCA7DJL)ZRHdo+n1al0F;X}iJ7BRj&&TmGHye8MBj}IITiBY&|gI=$idUL1p zhRuGdngTrM>Gl2M_ds6|gNkt8ERmrg(%xvg?7CI%;&1@}&!RA~RFFI{|N2?`(fR{* zAH7a)hwH%oBI9>9T7QLrJSM!A?Nz&6aGPGES8OREs;Fl$ z0Fksrc-yATXB`W=(h4@1Uk8AS9=OvN%5=e4M$+oG>Gf;)$~j~YYnr1-nX1{Znd*%F?1Beoj<%K=5^bGyl25bOYtjYq38{L1M$X-zSm9JivYBAkzY5YwTmy zWjON6tJ;=wSv7BD2$Uj6hy8>#U#u}m%OOM)M{#n)wY>`4nLL%|4IC}@-fOQUTW(|n z5axZcJf@c|ax;00k=xq{+n(i8bu9%r^ZJ%Cx@jt zY`XgRybiO0c-8b#QG?7&WUoPP=sU*Hi-EKmm>P+_B5`e~?_S{ceX2p{I_1TGZrP7@ zv|^u_wU~M0oKDSAMM)Ar40g;Hj?J4?lO>&R%r*F1Xf>Xbc8&JiYgC*@a!+hTlFeOUTOMuEPGK99DAjuoc}{#hM1u zXeXANm8%kRzHKGo?D%zsq-h)KcL)j&7G~#Vt(ADwO8K-348h?lWC*H?6fc9yYP}qX zl@Ey&40h7yYtve=&6Y!+tpiVV(J;^c>!s9#PaV&TO_DFbWhhW~8M$AS{fU0Qt*yaz zRNbzwV$?bDmuD+@fz9xUV81~YDAlJheNakzTl~|$KfrlpW3fq?Ef8^(DcmFw0NXQs zbL2~r$r&3cP{iw#flV$gE56<0Y}gl(ty^LafUrZKdUXEX3ky#;|G(SDKMqZ^agJ$j zV7kT6l#r5ads99jpGt~O=9e$W&kF%7U;fmv)h&L1DJjf$n`jiM$Z54UYXR^qA_@_#3$!A(w$E+kF_23&&70HrQ?ObO1K!-%X%i%Af?JtBFv z*wnHAgN+CEQ4#S#P{2Mt3H$vTla49gO;P3D3APjs&R{X|z-Lr~2a2x|?Q9n~?M>Ax zC7u+7^Oh*xt_Z(7`I*w`UJ&3q^r8e8*~573AtGDaae;x0MYydnp&wCE-FU9%xXysNM_(ndI^|q)2!O8C~ zQ>_Y#*PyMx?@e+-+BeN%JPzS)@H+6B^4;CSKm+5Fa^zOjKb!=Iz&_Nm6`d{cvDgB> zT^NCJYXs@C#*YGr^?PkPQ~d!#Ja~8|9l1^w#q3U`s}kAaFn5Z5>`HxAOzckPQ!R>! z)qzZq=#9$CIt6|Hfau?2DB!q_qenG%CP8)7fSncXpVu#gp<5e3ipOMK-O^lnc=uttRQ?z%K2 zy~1h!$-^xlcDaBw1)wZ?y+`Uz4URA1SOn0*(0HD*b0d!->p|xj2S{arlY}3dqN)*B zbXh(Ta52-JOVAJzNNOgUCO3X)8X55d3(WCOOMIK6-D3^0Ln&d8qE3BGctO}!V_J5!h?m@STb2gP5@|og$~emO<()vU?1xJ zwSq-g{+8M7jaV>pq!&3+YhIDlAndIb5l9NR*QsN(c&BCu&|^3?UlC!fU+Nk~&6brk z!kLo_8@t$kY?UClzn*v10Z4q6hnSr~tmN-(?s2~SKeF|wQ(|@znatT1GlBZ#Y1S}`b4 zKG3{AAJ6G#(#CO~z7aok664@SZ37bWiRCK86{qPA&~J4ZZ#>^z7vf|tQ<%d}1MZm4 za7&!HhyX;5CZKN+Bu24*3{wj5I1Us>jVWC{k|0`N9kc@R?PRp>=HemFwH$-V-tQ6&Ms<))* zM#k4hJ=jdG+{}=hz{M`i-C9mhzU4b=hh5CJe~Yak8;&hfm9Bs(Gw>sO$7s{b`*L$*Vj&oBMI>u&6za7swjZseDWAql6zN9vrauylWd6D)ns+$ehFNgI;6RrZ z2x;e;<06jW`^PSp+ZQabS3MK=6_G1Hj|6d%J}K)~usg)H~^j1hG*&VQc28=UgyH8Lzrt|D@Cm zJqQ&T#MP|$6}rGWH*uJ1G?t)EGne5`iQ#SwFP6(M_3mAr><{e{Z<;lf`}}@&^5Iv+ z)oM}RxHo>b|Jfp>Y&d}qz|!7;jTW*O>_lJJq18!or=ksP!h>-u{h^D19u7R*9^e&^ zMLA1T_5#E z*m#vggcIK);2SK1&!&R|uIR<9xw%9K8qM66pFfTGMO{?3Ey>A-uy4%29DL@77)r;a zQR$*k-MXjpmklaG@ypuWX9d3GvvTyw{&RllI&HL}3}FOZwxN<7IYu!u3#}JWZ`KqG zjLQ~$srIlIvDjMB`W5lGit3>BWFWD{q~rDbul$mgV#8Rst3SosK926#=!bs6R~ec{ z9~$k)_@XnP@rN$>(z@P>a~6HP4!{>GbM~VJeCJML(GJqwTBJUaub^f#mebL?DUHI4 zi`j*vpFnAiU%-&?FCVPC##n~0w8d>PIC3N%sRyR$h?0&6SqqXHV=oOqJV^4Y)}h^$ z;=Wo-G4uKZG@3^;KCXp$eh-OpioLzMbb zbQq#dhUj7)CyDO&JHYO0F1lu9y+IPdC1nN#Y=qUhH%L970`lIDw3 zCao+{!NU$RDNF~YFI^BN*j{v`cpxnzFw~<$W!=^Hr|k`L=3Y|U+rZFgbC8;!f^s#R zG|idIrUqG7;-86G(^7AS zo`;Y~okPJ#pnP#9UZm*&PB|=wsct4Gu>ko*&Y8KMg;3hn7fH zX-l$g4TXeVL%+w`CYf=b`;crw{YsDBJ{ou5n`Af^zVoc3`HmP$#~W{x$AAUXSbzwv zd`u1^+c=gPP7Nvc_s*oRBXLFEBwHPYtd!IQGm*bxxA+9gT$F?N1?optO=Z3PZ!bb- zeU<#b4$E0M2-5m-amnfIjw0U%vrMqzrYt!+m%tLYEd|EmDkaLY7D z@(+yZRmhG|zS)xs+lv*p2e)Pw+`N8l)-T~!`!QqYP#hYA5n?BW=nq@v$89LiG zGRxXJ*0emB`5-bOMl+FaDc1ozPKTIW)qkcwubft}Ykc^yk0LXvF)H3?$p@xIaZ-My z>SZOrbm64or{D!v4j4hs5Lu(w%DqmvIdDx+Zy`5eUQw&95XGn~Mv4Diz4&|@>TffQ zWlkKO+IS9pW%p`~a)zHHCAfZr5*m0})W(h!dlQaZX*3w>mWH3czbrT{ZFkkJF@TB7 zFmHI;Br+a%#-B8ylQo^nePzZu;6th&%jNwZ>;D4LV~o+XEi>AZ{uCf5RUPxj-;cT-U z|D4&kBR7PKp2`D{p6Zi zoMxYceoMX9rJQogEYJR`8&*eEaYV>h5g=})J-3#3QJ7>v^)SCrRG zsEO{KWxz~DIC(WHiNo=TQMFIAa%~SN@j8qh5QNG&UBNs*<3a|^yU89Ep^C9gbT?%( zH0=wl`Gfb*2@92G;%zHyYjeI_1D3ZvHgbp^e~|vRln{)Gz)94l;WfeuTw-3>dTTe| za&!rS5S(Z5%?cHaFXPohCYdMgF}h%r+e5<=Qg327!X#o{lI#;&A9&kMoPHw}FwxC+ zsqT3~@?eTpdH-I4I63G<1`jZUNuV<)O|%w$l?cvq5sq73`TsaC`+oD6)Yt{nB6lVw zmw>y3iBOfe`WSgMM^y~o=7bVAl+i-$p$Q!g-U_~u?<_XaHWD)`EFt_9-_ug-@s;w? zhq${8{Tl&6mAl}#7lV*&gOo?Z6ni|7OT1$Zw3=eC3q1>UA$mHaz0#QIOakF5#&uz5 zSCWd)8H9zKX;|O7k9RAtW${clAgY*uGV1#%(&r??ABjVvwml&VN(aiFy4q@4*`fEe zI0V$+m^}4g!=I*uV*`oAG$xH>hm?qt&`iXeG}J1Ln9TTQ>173ma0x$Ia{g`z?9L|? z#PA2-kQ9{H?f?r1tJN-WLiU==Y%$ufCoxWCy6=r%h$ZBRa$suZ2Y(INxl%|*F-5JmYG?%HMxCRUz$c^k=gl>L*3d9idxopGK@_7)0gcN=QeYZ-4 zQd2&+sNNjnX>?et7W6lJNSjB^?OaN88BLHOlMN9Cz)_2p7S*joyf5DPKi+_WmXZJl z*;04aGNxQ_TZV_&-=)FpS9pJV<2RIPudf*IHBSWpsN>`R;2wk<_JiceoZ+zP_{Rb! zR87YBGk{>yo%snEU-Aa10SM*8Qeb}cJ3O-xOldG@nRmZKys2;xMnSD-=lk{gwjbaH zosd8TGKtu12Y!#`g*fvv!WKd$795ly75cbPe`hH zVtDm*Wv|ov<|gSJBx2$w&s4yz-2u5|ygn27uSoMm7{8?ECiET_mN+zVlE)x7-t~gN z(+J=qHi~fno2kv=M$kMrFEQ9$5wXdQy%a3BEeeddes1f_UalWz%*HN>`K8*Gb%U=I zr$|()FI6~qEY*F|*uZ&xGmzDZ;69AZ=sEGOBqBcsof1xMqRtJ1Prz6|0A!IX5ksTK z7G6+IridPqExZq(3G?L0PN@zt!`U?9R~ zaDXDN*p-KXUZ079S1>KBR5O_XCuOI0eX#)dVYZ%~8(#fMzG(zJqV?H1;f)>gt%8A# z^XO55Uj!tkD?;`-k0G=Z8h#q`Nbx~L6f^u9@n9~OemSQ&B@5-db|Ik}xjk)u;oeUX zhp5iHUJ)R}jT?bwQG_&)O6V*Q8m@bz4(WILEu2}Lg+SoTt%P2%kL z0c8E}ik3F{F^%Ew@+K-moWjNxCUZaAkP3EP+*2Cue z**DC`WCJWJyX8}6WIS(O=LcO<@-NF`Gn>bS!mEt*r>afA;do25&{U=36x{-)@d4U* z#O$f8N7*iGb|0iN7cGR@@Y6bt0Ouq8oMk2((nDSBYr%i{zoC=6p)z3>IauMUJL%8k1f|Z|;s}=Q!&I*#f5)x%B z`F|BsSjn?)3O_#y^z;b$MoWM&bUYhl9c#8SOoJ| z)x5`Wxc0%S#pk`jKMrCabR!O1`+0NzP`LK1cCc42eHZatb%fuBbBK^|cA40N;_#k>H^Jux;58Pkw2%PLQhraXrk*~$0$H6Eo z+q|v|NoAY(&p#aGlWFwI~T-f_iriTR!_1X#H!y+<4BPCtj!{ z8JXj9{z_?t?7^TUUt`UMC$4XV(sYV{RlS?G2Wy*bP?rLdCATWg8FJ{Rew)ilw7dyr zLFSH~{Ds)8Z)Cx5{V>*CowJLO&9^i&O5l?S?naTichk00{3j2*-FHE1W~cY^vl0J( z|3`C2Zr$22mL0qk?1m6-2QcG4snL@>W}-jUBd}lH9{aP!TQmr+1a7;_s40_qc&Sii iwqY^N^3*@LrM$tFmS5Aye{}s4pHz)0y zRajWeD{Hv9m+)J2OE+g1Vd00u4#1C;h`p<`)1|7j>K-2Tct@KR3QvaT?Kk?* zyFCRdLatPV=w5xF{$gw57GtbQ`%Y4g!>3d3-q-X~EY@XR1jiRuxKzV)g^PoW@r$kF zfQ#YUi-66G1Lup2i_O|I=tX1g*RD6W79PD+i-E#zp323&MS8`f1vF> z`1~>5N0}AMRCh@sx%CUL^MKmHp_hAgo#xAz^|D?sd5PHL)fo0_tHxqEmv2WV$PBV@ ztxVqASD35{sNM5vIbBRd>Nu)3*_bM+HG|I%D1)taiNeNqoP(1=yY8J`FCTNC?@C;p zWK5>cuB2Ed+#ZrEc`W`%Z9vWP=lOXy-)73!s=tV=6@F(a)rN;>XTEyG;y-^8b{qMZ zZeJA#X_xyvzLy{q6OnTMOVjA5a`oAHLD^)0qRD@y5tmn1L1Rrvjb-f+@({hlg*L7 zp|JJ6CX~AcM6M8+&OJXVTw2km_0Bulti=q>3B0)?cV-;YQKxL2yc*a`+*FVXO$_5C zruEEySN01I7(13@L7#x1-o83}pl}*`T*LYJddueDM}+D6fZ6OPHy>X=pQn83ecTGn z4Sq}7`wey1;*(oZJewem4@B{MFsOSTSZ;X0kxZ^|_dxVtR*gPbuFysQ)Ol^iQ`1{^ zantmh(=Vl{#W$vvG^x!9%W<-$?WEcO>%7TYWL!t662tcK89R8`k}p%)I1gZrc#>-* z@P<|XEMWHE-zWOD7g`3>wO?@;mp)kD%Q-zzR+X2042$d7iMR+)KGvN)ROmZ9KQTw= zYE2i}VRI0v{uc+u8Dee&h>?~0$;T4=n~Of^3#P2d(_hm?L!uWNF;*AnuBgh)q?Q)l zT8t!J@H)k%bLZWacGDS@)FJ2`%|+mt#$X5)5*nj$w0O?^?24vNIs>u zb%`4MZ~KO~MepY1igHF@8d{%Tonia+iI#t#wl9e6=xNk8wTBV+UGI|he^bT6tIZc9 zr>&c&HRbI4yN2)F6$X3jcgPo?+@VnzbdK5~PfWxXlMN{u4_tgYpy> zA5#{YSpA)Sl0A#BF$;tE_S^%sEB#XU!Que<>_9R_LXdd~L;<(?l^8pB{PBdY(Rxy{ z?9&MWp_^nY2-}dp&?)E;)O^7DY0JrDeKMc-oh?lrctW-6J--R{*8+;~I!OoKFh868?mPC8`XncQaQJhT! z&k^^1`J-hhB}7r~f#zjp{I#;sX2!brcIL>cd^4E-dl8`?W!6vBlh#>*+sml$Ic5U- zNi0G)X=>CTkXy2Qj+LYi!$4-7`tP3$_0Y0@y5gL8;wt8WdB`h7f5!5OIy@$U()C&O z=HZ~`QGj3<)UhV5*3`8yFvA>4QEcYm=>zgNaee(Bm&SQBb>o)*ca4KX3s?Q51R*># zD|r1{*?Zm({Y(YM)U+D;teJH#XqLtXBWi{G_KPw9B-);t^Z<>nRE- zo@Rj?!SWC4X0BV*Uw_5Wb+NfS9!1u5`tc`T$E(Uc#et~nwJV!BB;foh-VooevxV}S{7Reoam})geU5TRH|SY*{en*Glt7sm zQml1MK*B?uc-3vCz(PH~90GD%6cGewu9n?SXsJ%UqjL!wyA{JNkHEdsxuMCU3=-V; z7QbGxf-q|~$(KpgE9|b6Gr1@f6Tbyb-{N%uH>%Fc>NlHg?teI~V(l?N_zi_Me>9%- z5fgu)$$};ab`K$OAFEB=-{)GO^^6&6K6WRMTf#T~I5g@P;<9@PI`9oAUSKahX4Zve ztZLZ`>q0hDKX<@T=OVQ4YsRLt6U0}_m@-v3A7vEIwq zm?@$0c9T-Ry=OrOzH5*09Fng3$T6X}!63i==v1HHB>&2U4o7J=eoLoyML@!LQ|EUe z@)}mtp2es7Ha01R7Oc3`rN?nI2fr{baiDPRRm`+iL3UmHR)o%!)z#zNP>CS%rKXh} z)8>Eqq5kf;O9u{D6YFk!FI9V}X@oL2J*@tCW=bc#V{faWZ#+=*G5Pz1Sdu{GuFe`o zHZzI^Qomwl*{oS0W3E?7os+g`;XYbu0roW71dIY2QWj+TjW*ROb5~$Lc*v{aqntTi z@}~XwcSC`|RhwSFbyn;+2cF0f-4FI+H?A_X{0gSo=KB3h8(66$CvFENdN3H$65&x(p33hWFuwxZLxkvNN@GiqOup^<>|?g})pzhCdz zs%&^xS-&7<)!0)cT{lut3=fo-7^W>W_Zb1%!SQMm!>b|M2c`If4a&xRztzE zz6bfzhrhtdo>kX~8bnV{0jr!Dm z)D-GxQJnvyIn$_yoAsoL)zEZ-U6iISbFAhqTk71qyNSMM4<*8d+wl7Dd;^37hMm3r z@_a8p2p}&g{-9Asj!*VH_n*9Un`k9P`Ch{z@4|F;lZ^g;Vfz97t|SH8B%u2#wq=rC z$h70rx|!=jjyV`lmJ8Q>BC$q6tUEoM5RoV#Iz)zx!_R7pHV@q(7sCY?4r!96G|uu) z^~ka*sl?r2I-dsCiML5K8cG>T6{(l-UN)hsm5PpNlRCX%*jXI-+_w7{O^# zh#eItJXNsp*rM@Q5$@nrVhx~E$_slRiuAH zd5yc0IfR3~ZR3e)>lHDDg=K#A17)Xs(Ade^Sf8a5ykchaMuja3E?Vg@jW5hvyF9Qn zR3U1x_R!~5Mmg`tNybH=k8d8=d_e#wtpkRKj z2SD+-(lUm_r^{EjpLxEA0hK6M;;C^t z+KebFG>9PYmc<*-JX;g;u_fZi!^4Lvq zN*QGS4BOK$H|lC!DNLk6d>nX}$akvfd-3E(Jyl{J&V`$xz^2IWyl7^3^2A<7lX&?g z77#u#vaT)k5sn6NRl>?hwl?3q@Xtg9JFc?6eMwk?t- z(*^ZV(!=GIr+lDFS!9TQDL0t{I*v5PG{6a~^hGpI{|*#hM9|4ll_gbJB#}M6PoK$1 zRTh7oGj#*;!q!Ydx?%MjdR0fJAPaQ)`*JK`M!>EIR1kH*1&u$gTyEc5rk8b+;*=~X z1_ic8n2DlSPo)d0L6@)6x89}N{|dO;OeNb5s{NS8X+og! z9AeAajLpkv4DigGJaAsL;#YE`_UX@)bs{cOik`#00qSk8U@DGhn12z z6mctq@T?;G5W3|#z6p!D6=*0U4ef4 z@qZQyq)UZ|(u3tmGO}w5Je#|E_EfpRuQ7TcFnKcDG1>tPXyLR&03k+kN9vhE=k(xA9p@v>xQ|7YQ|Z+CKAd@B zvvn`DCzX@#Ffm!!NGBD8@CK1nLTJ}Ga!BX&(ri@qY1y0x!NXGXgO%~6uLw!i@2gM$#E+Q57wmO0+)Rl z@G1=(pLWw=0`CV8jMRs%Pq{6?Ex=M7xk-46o++u!-2mp3+U3*9rgP^jBT~kl&0%Mg zZpV%m7n0+UHZaQXQOQ&y{R<8F;oIxs1FtK?j3;R=kTO__!qvojqQ-Eyi^XteIc=)v zaH_M#uw?RdB7Up;on)qE6mw+NutwD9C9H#H{V�frQ78G6FyV5`In?=<<`tVWzB2y-uYxeTN!mLa z`DCdZQr~=k0547WYNo3nbESOcwKd|eU2kTe>RS~OJ$D#0743oXa>9Ye8gWP98Dcbc z`o`5aODIbqe}vxK4*;@S)~7vkxwmF60?&62=3k2^UM z>uQA82c;kUW@vM7WcrlvH?bmR=A;UhlG1YL^>hIn#X5B!*(kp)7_6)nCsfV=IezbhUfAX|$mXDb0e#I-a%& z*j~%oD%zTt5f<6tSQl6dGkxl~a-yhhMtNBNtg>Z(Zn^;oy!f3F0+BAHvUm8O`;m9hJY4llZfp+Y7aR}&%2pw1!iC? z!*m+7hvcS@UxV|;yL$W|nkz2So7e&mm}aIhoLz5;AJ-6Gr1w3&Gq5wnczs0dxtj~(o?SGtSS`88u>eeY6}|c*d!>xxaf48t3cjFx=hrZDSoSe!R$I!X1CdEB3sp>e=a3GW{5efA>U|al1S||=m`M**U|XPSt^s@dcMVZstF6u<)i3xrJ-pl<}4^G(KG{6A@LQAtSu4NG3a* zL;{e)VAg>G0>rGcpc)pbD6%FLUu;4H>164fy7u0UQUwd*fdRm11-7#I&ZDZ3^?8>M zaC2=h!D*mo!-$893@aeb6^>$crUp2Chg_B%00n_##y)7*;o1Pw>V6yF($3#p#HCIfZ82fgf}TVMdwoDp85)_djA8Ql{iH|>(-Y!1bO=#22xd3`Ss z(oT=D&ocZ^E88L+joJ_9{E?8GO|8=4Pg^>P&Ex0&w z5Nzb1x-`@9&slo7ykOO+ek*sX#qF{zWy3*@r4fx$EsNn55ilzo%1>~Q8f9}poDQJv9MA-R(-eza_5{(@B!p16Ne>?aCdza+~1 zAywR-l)uVBh%r2c)9@z3@*uP@^a7i_ zH;TWQCu=|=KDk(e4@*WT^KtN|lr6iW052-UF+O(s4RQlv>48n28N+jIn9Y=}#^VZ= zx?;}GX>{4%#qd2|>!J*Rv^#)>S`=f0_QwF^Yd34fZfPbw zx#IEe%UEe70sqhmy(6(7HdY!;z=NHJSCE#ezXc_he_m;!W~va~=qqr6yugxJy!W$O z0WY+1=TbTIJ9bFR`qCna{h6{t145elJnAjdvKUMLnGop@&?sLO$C37&{WPJ}yzC>2 zxYneDHPymHY9xngKUL47N)VRCzXcb-(sQppm-k3A8T$Pi*_sr=QFlCTtd}}`v2))3HW?_)WKM3_|P6vM$BXZ|ZZ;+O3 zIF6k${F5C=S_Rf*vT;0g!6zM3mx&Q|W^PsqbnJeCA;iUExr6SY+wq6B<`(?QQ#MD8+u zHElQj?;i+@mUgqWvim7Nb^;suSKiIH@VQsEgs~?Ma+Iv2N<1txD}q$V(=IQ>?a)Go z))RP~;9BKDG3+M;>p9CU|J)#cxI)44r-n{8fs&{Ui2juDQyx^tf29unA)`>J@8>uO zwx6TI(h2;Qq3jp#lJqUjz<1HEm+dm&G;ld-H6}Ji?P91PL(DQ)Ih9{BlxJ_uuTqT- z<>$QT>qg$+H>>o1M&8BzW&_zmG@JEKGM2;Vo#)1y_j*4IZ_gyf^LCn-O2Ho{n19bA zxAx7re8?>Q1m3XJ4Je;ogW$V3ZOj?U3R=bA$>On`!!)}9zW3U4^~Id%42H67@J+Sq z2q`;IlPtbCr4O}@mCWRV!=QahK$(*A{TkFzYiV)ig;J0h!oLYAbmM}?1WR70&B*#DZA~EcF*_0?fvw4 zGS7bOrU+aMy0q|qiwZ!vP)d0{8y=dK@#BP>uh#*(oO%Pj^S%{X z2hc^zy=2(WY$XcH;Xkhcl}ZG^W_|BD_Q=y-D&X)~R$)JH+V&{$?)-rEXR_hwRy{`9J3F~W;jCGAi|NBV zd{~B?Cj;yV2aA7RzTo{8m)b$-lT`z~1CUb%$9&B1-F=66u?HZh41DUZyS^}cnQ?+_ za~M56UtMClO2cL?V3B^5HB8q{{!Fi%yy0op@Zu4*2h#@83)v8G!SL{au3DtSROlvr zA~hmFprL(g_>Qdjd&kqY^u#FTFo*M_V_9fKpU+M)i@iLp_-5rPdbQDi*W9m1nsk)L zr;WplO7`h>?(4Fqsf(|Fpch^iYk~hf$I4? z5C7GI>C^t)hEKaDqvED&S$!va#W8teoV=QywV?~IXFMlYcV)$&xpqM9oa8xq^YoTT z-$_`~k(*SYI0qQO6vNe45rE=l^X!(L9qkZyLy!;duD+o^>ryD|qQpEVC5mfdYEwQc zIS~q4*ke}iZH0QmOy7MtIJwA--G0}ml%A?l-{9Bb9=m>rqw%U3ZLad%hQ(d-Grgx;U#kmtX`OS`n;Y-+N5(m31Sdt8#93e|?_Q`gZ40 zDtiJ|@M<2wn!S^{N-~pGyzL)$F z`r3=gfCrBix;9Fe0A)6UJSP|PDvl1RCzo@A<9`S2E3*I@apqOY$Gz__(J7qFF3cKC zU7uau<)(oT$02j9>t5l-FHNG#Y zxg>rzB9$1;wDckvT%+CcukL-lVWFCmkNuU9-#g1}!owm2lVd&T*&JTnrWWl#W}yeE zTZA{e8~OTiaxGxi(kEn`ZiSb83NdQoM%qlr6$U%S98`MyY03A&*XX9Qwv#iq-hK8jKydvJQ(XFW z^_^%X?%D=FD^*w?)+3;Hf!W~tqB=h>qy4n)PMN~6l2-{XT_}wFSYzRJfB#X;)l!73 z0gr_cOpA4yh2|hy$-Ab3-wK(p>+hG68M-GClHG~{WMW^c;%y)mBGf<3lEryhDs$)T+zUq}Tm7FT10i0L(vK;yN0!CQ5%^5+I1hJwG`0oxyk7#FMwq7+wPO%iwCOeZ=40-3mSYGPzF>JN|P-4W-D(iXZ{H z%p!M9rxOaWEn%c9B_wS&4ce-H0^GlHRf*$_twy0E^XV5`>gv;I>G}%HcMED^@(VMt zCo9jm9*><+(#_*EFIFC5gLFP27;{{o+D;A2u+oXu_I+v&&eV^ey;?#nqMsEa(hjj- z0{mj6jfAFkCJ)YVA{|_JKvJv+=gY%=vMCKGWvOiIAE#7#mQAMX3WE=HCe!@HVw@>1_BBj#Ci*<8nCL~1#SsRw}5(tS%AlG za9u{qU(FS;D1C~%mZJPt(>IFrL)ro@RXh4cGF*uI4T&WRMBwoh4l4qeS#h?7WI>P( z#v8gD_p;$_`Z({L{#~6sPG{14ZUk4U3Fu3Q6QejBE^Z`d+O5$cb;0$#}%r5*2BHZQ5_r_Oe|3A)W=!x zDeeljt!ZW1NV-+90dW8_wwlawj{r1QS2L)bFbkyX$pTwMHT zP8jZ(`}voqBQ5KStDG`n*Zu`x%ifEQJ!wN9Sy-1{<%FVa0XB9%>Uei`_|3&H%pPHE zEn?pkxLh;H@XmqB{To~TFcdQ1QJG`vvL_rs8 zMI^sr@2Jn*lv6ZhGk^V2FPPeTUZz;B(Gb^@lf^c(?tf~>C~Ml_^YcGj_nMSDt+_R$N@B zB#|JMf7zMq0Ct!{L;&%KO;qB5mtYysELx3+~WDlBq?rgSd z2bFyh-T?y?(w~Sm>JQeap|3&~Eu&eFb`CZkLw^hg?*S&bdCQqvL#C&N!zRYN5Scup zW!cQfE+|3&FfsUJgkl$;53PigNa9>%#BN92ON*FfK7fRVOKXdlwYpY`YR`yNKIvV3 zCKMu7y~g@hEjnb{rP(FpHJ&w-c!cF4O|r5Vs`~Z1p;%5sz}wG0-_M38Ju3@-X5^jf zq3#^%w4*_YQ16K2nOC&7qw9wOSwB*X8VmtZ0+oaUL#5kVV-Z(^?$C zJf^P%nS3M}KDC{WUfBKu_%p}wsc*5PDiR~D#mMcE{_sX4rf7|#ffmQ#rd+-8gM7uj zS4Me^;4oi#xJ!;ubM+fs#8@A?qvkaQ)lUt><(7I|^}0gdl@Scau|Gg!LnARgCt{$# zm54j?e9LP+(yv~Vn4SU5@UbH$G}VoMR78cNl(z1u4;HJ^64eKzQa2sj znabx_&i;iBs$6Ca|4jFm{ot2yd-oW3UieOBYUg0wsZ+5n#&wAGZ~7YFi1af@>guvV z+md!vPBO4)WgqW+umSsZobjO#={1hyURTXUjnI|28jfZduEV1D2kA<{f5v#N*9nR8 zHyEE~s;3fgFW37AP$Jrub3XwTDHB&Fd5hMQviH;3eC$m|GkVrQWyfhqdpBw$2s+m| zp}z-b5B1&K*2Qsqeo@K#C#|>M4@33n_+XmlRI5bH9Tp3SX&<)8)74!^qyyJ65EQ); zV615N`nYKtM2k|a?4e?%ovgn}wC3K5%-GT8iKRT(aw4Jd4)Kl`y|)QU+vhQ_e4bAN z0Zt@V>iTU|JGEZ~XTJ#3Sp+Zs@s5|$Ti0qJG5sHu2(R_x)l%@@iiaxb(mM;ep?7ziD?3qCz>Mx z9PRcenPxO4$v(bY9pX`F-0-i*+yPopni-iZ7dQR+H*b)EbcCJUP1wkx9u(Y5029 zkPWnHSTtcVJUBPG@n1@tTYRoIWbuz&dy9zC32>@iUz7qM*LI4@{l$v=7jG8DO2N1h zUOhl9fM)N9oqQvccPcU=8H&6Tb@@@8x!+f4sMO-0@{`2ALHU5V+lEu zDw~ui%YkTD5!?%|y&c)kPsecIiNL1l_hqh6$Cx30*sSgI_Dv&tL}f`@ zveB5x2x2j(tdssvvgOEFae(p5+V^gN7w^v+T|OvZj85X z9W*6R81y`ukLkL+(FmO0iz%bL?clk3CER)xH`%Q;2UhpbbXi^tZFBP<<~Sz-KVwqD06{-YbhVT}2~2IG{PyR1|lM_3VkmJpR5PL6*O ztyHNf7CdML0tI^($oP2|%Zh2mPFgwpvlqa^pFN@MLnrj_K|0P{r3Ms!i5s zY<^yHM+`#J**KF{B6--+@RtzmA@U?P5NaIs)NcJd;hO7 z7^3<#ST?ZZuFl4kfSy7nY<_~X()47R6lT|$PXf^v5H|8c()~DK^YnI#R5qplw*G4w z-#K7?kvz8Ol7t|d(YwvWDScF%Np?^reshhfwWz#5?`US^i$R^i`mArQ>6a2W#5)L2 z9S3NNp8q8k6?RhqNOEbc*zonnYbv+hcnTru#+yrYX&@brHvCJUg{JZ-1c-)#=Pj7^V!)37Mek6AeWE0Ur_Xh9s z&rMx*Pv=l*r z?|bfCe$ELAQJsT#t7oRJ4l#6V->c^KZ%fGnw%&a@KV|ktK^^odlH$dgmZv?>9Z9Q$ zzxDM?pIO}z4`g_5asW$KG-$XaM2eh)IwykSjk5jAY{_pye?`|Rpb_bNFLqKDQKul1 z`HZeHbZ3-x;~C;eikm2#0W#gRd$IFV6K*^qo<0+R(B`m`9R0uO@>G)KXR7PR_O z;jzLrwZD8$FYn%*m8%M!jPwYo{c7Z#RA#Wd_UG<&HcLiDrpb1W#h2d57j0n5^|{Dh z-A(tu^CLH`9*v*3CL@%lJa?e1nm@j|Exe3$Rl~^OdXltkH1i&D#WAr754Qqat7V)e zmn-f+!h}N=9!F-5<({_^+pVT(_mB#;uYx~hqK{_wvD}Ea-4t(}%Xceoo@*s7E6r;s zG_^CXOv-Y|QiY#hn})gn>M3GK1UV~LA(z=zQ0ys5b@E+og5eC4jjX?2aNm=)N;E}m zZJ0_Ph0T3iTRp)cW4CX_-EeWyg=BnBhV^N-!@z7MkBIBZOkB_&dmF7}ZNstl-1RRJ z9$=f&N8%H}t2)Bm9_X=B%zT53$tLixug+aM*dIJ!_T{G0+UKE^|m_I51 z1Jv?-(scIn%`jU%IrrZYe*T@gHwP$z3*_IO?8uXG*;JFqy=)_SZZ5TujF}X|ro8NJ zu?p;Da{Fe_ptJ`cH6)`d8AJr4i<&v5%+Kn-{na$(q%Zuwif&YW0`~-D&i#y0pX4{P z)r|DceEvJ;WSl>1WA2TInyNIwYJa(Ao{P;2t!&Kg)OH%E>M&TjTHAZN{q^RT-ySZ5 zkeI6ftV>VkaBEcc^Uj!`6WnPdo`6Z9eCJieBPz>FOd@P*j!>dpVj&r&$%IjVyLiB=naO5gl0j2F z6c)}z6Sn!@YntwvdtYP7VW#2=`$gZD=Ki77bRp8&$(SKcK*vn&+VAmzj)4Tt;B!Tw zCVv%J59j4~oJIN^Iwo#grryr#2{y@8`c2sMU%oq&6)n5>($B}{OM%w0h=?E8LiqeI z1r{EtDd<}Mhi4hV#srG7v0Ch&asPnGhDZFHqHyhT-ph+Kmk!G6R)3uQGl9+f+sP-1 z3i6NehRn4HeY0XKn^e>f-d z>MYKfy_r;?f3dsEy*xkj(Tz7Bi@AU?O^Ix1a51#AadM}KVpf0;y=R}i7PVWgOm9VH zHYw}PVAT^ko9R|DXGU!CS%THue(nB0!(E3&yIW&a7`kKb-yP&-+@6_m<8`iJ@;1h} zibTGO-^&fZH^^JPHFMQn6^E00Ry|&~YVq+czcvYlDn3?f5%a+l*?25vioMUp?WC{g z?R={C8Kp{&lY;wU&ye7`NA=WeYS&#=`>|M*I7GCTUpmk@?D4VEZkO6;XH_X+mT1%( z^m1jOxpY-+++J@5RbkahXr^AnU|ayic|Zm5r&W`7lBQ1lg)QI`{&QBp+>m)I=!LAi zxRn{0JMS~E%8LL)3Mif3TQ+pAdc(hF^HofNI}%^Pq(=lw6`vzsur2-(bcY!Ce-Uxg zcb44JV{`&ya^6K45Cx?j6+*?_GdOeA6GobGD;RGifSl`r{~B`>4ATn06Gf1X6_`__ z{sQ15{&`5atByj6)U=p~w6L+3oQS5n-cG9e{soMXn8&jn2Z&6t|359cW&F!h|IyIQ zvaDvTMf_QBmsKMOi_Y6KbXEWgOOxM#GL!G)bZ28=-=L{y`*4vcptPM|f`RL?hJQtt z)7X@Ms~^ubGp=Aloshv5TJdAC6NfcSD?{N6p+sa2V%r>ucR8V$IuT8?_`z?$J+k)W zK+9~pt$Ftu? zKiY+_|Cx{h@lKA&XsVa*MJEpQC!a2Ax}m^0Tt?epCumTf% zT-hr!k_kzHPW*M^TdOx!RT5!fF|yxiz@*a^8mOagP(<5UAJ)=t^}B` zlU;#?M-t>#y>P_Tf|V<{C~LUYeL?eqODFx$M8&RT+PSzbS6A0%^g^rrc89R_>;lF` zU9(I&fzYq)v~ka4Wdmy+-q-z?R3^H7mvMGM-UU2YZtc<2{WpDrH0F%PW+n?wZ$>%YHHsbE?=AG9RRhYy;oO%SE zjkdF|N^(UpkqWb$LLtgwUw$O2cO=g(X!^QkzD+c;Z|}al;23b8RaAB5mJ0#-v12Ah zl@BMqK~VkbWOoaYgb~wZck^Q0B?NGK-ZBEn!)c_<#kCd395}AZ;Jj=BfRx*8r+(~% z)IU-$8t8UhBEhm(#GLpMpn4PxA1GdwQ~XH``kU;XTEpcn$pxj$x-Loe(@3n61RIA0 zV0qt;B?WHq-0-j{H5zRvO;-y6m#xM=g|f(N84#=bJ*@NyK~>agSxV9)$=jCxp>uYP zNC$I|*SzNOUUe!^G+bK;O1A17SR9TJrnhmwjz@2t0Q>K`cFUCqe+6^_JoZd|lm{UR zzH$Fb?yI>-SM^pe?CfcWR%Bf==7MuW3hMIH2!n0pSX4FKX=_PELo^j0(|?HhJ`=sQ zi}-MqafGnfV611!$arI zGa{P==NwtwK_q+eypV<2$ggRQLaW_nO))GGOgd*IBx;S_TWUi#D{)n|TW*q6KIm&# zYSM^9W5Ro5j-RCLeLTE3vOF!Z=ge9^n-yv*qx`3}(JretOExUsP!1NILO~y86^tJ1 zi@CHI{cacWz#Ee+%LL-2e{uG2+gG)0t6E;13%KkFQJJA@ab8m7XFb|=x0X~Rq@0Zc zSfYOvWjHfYBN+73H)C;tb6oLB3V=;};GIq zd0`CYFeaRNDqI5U0fzFis{%j-I+^W{m6XdWo>!H-h+G@-lzIjP9lCGBr_y#Gn-Vzn zD5Ai?Ed<-CF)aR3PUvjJtwj6oA-)}(d}mKkZlCn|F0Ci0CBZ484aH=ExA8G^d#a&C z6%l_RI8PFVy+o!C-??y^rP${o^QnXkEBVNHGSMBmw-~Sa_&M38Ja0#G0^$c304KGH z8>~Vz<74&;Qlna9zJvnfd+zJg05(n^sb_LbVH|lXP_1G%68Nj}(cxn;k#)@w?U*3gD*e?M7qtC*ff>NQp8 zXodD^&Jh_Rg3TvMJ68b!Y;Ojlde-`%P18d_>0i8Olb=XxmqcKE?1q(y;}^$ODiQfP zQ7_uh^3G>}45g7eqn*2a0clrn%LE{_?Uo3s<*PrA$7YCL38DwN7viSa-!+d{7~qbn ztY@#j3BKq1yZfWDd9wDV{Cq`+?PtFQSH;~f7c-#mc^i6w-bxTn9^C5K@BIdZ;djE7 z=3HvEZb8eXOg|Su9X?E6-C<`H+i5383NBC)@TcyZ1zUFH>o&jmGvU>*^5=S>jah8A5T_^V;cw$tckH zJ8a-P%=+M_m5lQ9OF>6+CZKyJjkx|brk+fPE~IH|FHz+B)^aI`R_y2J_lA3Z1dHp& z{rfJ+yv!HiVkYNX>pHCT?e5nb0lMp<3)^$vegAbArG|P%fWASERMH91l4i5fUuAgt zv9?4Vf9pRugX@QzXIIXvmZmmVcTe%?7ljN;OUYB0r}t)nHYp8RTGiym>JM5T_1pW=m^pX?nHgb7f1n)mYC zX{CNq9pDbQIjN3gQn!`r6R837pg+~RK460Ds)FYUQlJ>~fr-daW#ok;F&hy)HllUDrhRNs|1< z&f1=O1SI|AAby|^*E;ah)HhGs;Vdw1YuA{XZC+Fd{(h5qK1wag)hkq;D(j{z+sseT zk?t4Kwc9MN{@=kKRR9PFufE+cCIW5a>(eaTsovwjxs(2qmRm5rObfODb-O2-@e~21 z8)TWE&Dwg-PFhISsZ2YfW~e#>T3yXR^L`oNf~rZ=l)3(nLabmwpSj%W2({#6D4mTP zAcri*JL_luFg9y9^ZTd#q$siJ+X!&4zEEVH6}XeSIG3*lY}6)3p*8zTQ#F8&6^{$u zTVUgBrizvSb+8V5{%sGot*V>Od;gU+O_7k+ef#k~{?;TQS_?J#us|AAi+2q06Y#3E zEq>1?+#&Wffniad`YeRh;X>4W=_}dy*UJyzNN3gj7(Q4PqBzY>=Q8~YtKw{kr4~_b zhzmAxXCzRtWeL&5*YLiEDsa(%n5n3%k&hz(p;BvvofPipV5LXw()CsHXddb<%(hO5 zGXs+1I!Sj>Z>Uqkj5Qd;RnuRKCNSfHFrA#+t?ujwsi1OK)qYxJU$?pRiyJ48sxYCM zby$~3^y1|8woSR+U%=|557@Lj&(!;SLo1G+v$iRKq@D?@8pO>#4Bv|maUJ5;v6-GI z!KM`C1Ho_nyJExx!)HEYB;Z5pc(W3~M08Y!!GH zrrt7N`ZrlOG}L!;%f0i%C2n~#omF#V&4&`Z=p3R$OA(ERJY2%CU#$G>H1S!@#63T{ z?&3RM1DHWr^!*ZqGmvF?exE-ekIz!#?ryOD0|b#zcfK~4+UJJ&44{wZjHj=b@(da9 z+!IQQTggls>%%nJM9&l>whhu}g$PL2<(+FDN#&$}wn!x=!Q+A%!+Cy$Ks0M_q)?`L zE!(UP`2s*$)HK82NX4(yVDQc5_=YGy+qmPAYyZ~@UgP~F1hSZr*sHj28LHTYnX-vC zEJA!RNbeK`S*#e(TrXC+X@JEI`gC_&tNNDkSm>vl3j;9%>+}M1tNhvL-taO>9g5&n z#Sq0VZlEWODZ;)@1m29LD6ci}!Sl@!^HNy#R~&^M@oaXXNW~RE_81b)T0N^8YwAv7 z?-9Tr1BB7Jc7#(;q&Fv6^(?4imVbJ7EV@#lxIC5W+l{Xw;k`2zMSvj-5@PJY6j&GL zVP<tDupwiNu**jI##eBt$_+i)}eplVDE2Wz1!Kr zVi#*{AV~F7yl_b%(0=~oUbVd>5T!n6b~Zv9)85tNeUJxA`!`4^R@*a_enwObzfWB| za)&8YsoJao&OEnB5k3zqRg*Wwz06hpsLQV;xcJ8(2n@77 z>PEiGhT{Mvx&MtFR`?AwZsfv#{o~P|Gy+~otGxKHpWXMPte6;B zFAjAut~C1Ylmp$DNv~@_4jsGi@YhK`y1(<5nDphJBa0vN78^T9vwa z##{^Pu^DmMI!u!t)NqZwo$5tk$MZ0P?#Rtz7qXKK;OI8PzL7Crh?SM{r)N1+a8tiu?t(R5Iz0OZI~m|A@bpivfCsupf2ot>M7 zwu^m8 zfY-**=?e}wia(te5VxIwh2{IL&-^B*sM~Hn9Sf*jnmAj5m8D)krEIMA|j|rNvI+qh7wwo z7J3OC5s)VOKEr;0?;q|C!<0KW!_2+U=bV#E&(jAlg?kYL%G~alV-7hbeEZJb_v@3M_E^sEPtegEVU+uNBr zj>gXv@wVpIs7TTJS9o{59rZ4(n5`GDMi^E$0{#-(tpqq<{&mEksta24f_SQx`FuHk ziM{4j@3$`&4m5u?F|QA};il-LwlsftG3NHym3Vag)0@o)aSv?n27Z28cERFU zP{yS1z{5c-88|A-o|MI8J7qqle2ez!RAgTldE=mc#dwxOgPsbR?Sy=;TH?k`Y*_mf-e4wY#}tRwHe zqTqHoW?sSK&Eokj!0d)}=UbH>92>Qc!5-8aT3xS(PGjFDy^`bifpG6m&N+{(540$p#yWzwELl z>1VM`-zjlUn1A*$IMR%)smWmvraV=sUwMlbRsG35ZYuKAYn9D&)+4K9@m8@<@1Om< z1*!m!WU)#*u7?x--kK(z1%w$b>j*@@^-GRxWh?rL1KFnY4HI8wQnU94=||H$n1MN@ zw=r3M7a!M13LRcvnXk4m84kgeT<*0-(bBM@$QMuJt7U7UO7Qb)Om9Gyr4`vGm%Gzs z5*zdkXU8@#YQ_$DcUygAe|ZHQzOa~aGM@YVDXq3JDeb|Hk1s;|IMKV$D-NF%^GZM% z$J^6=p-o7~QBM=K2wn*Ws0NP5jgWOe1BXVkEbREIAF-PkFT!x0Pcn0-S$(8r4bN>A z(27|;ObB{rajJ&1_eRWO2IX?=R{mI8iJj51LBY{d`e+Sa&>Hrw&P;*j#O^CGF7GLi zV);$xK_8!|2E4QwDTcEcWhfOmd}~uFpUHbH5E%HFu33YRxAf%5``XL4ZGAG<_})|K zu0Fq4?81<3Jkt~i&9N5tY>vk(3>Ig)N1{a%c)I~ zGPAn-`*KfV7WQ7ViH?cCsdD)kTf%c#2-y==2B(jakb&hqfx$SVhufQD)sJl*&x*C> zt4>?QfuPh^P7JQlvJI2?FK}YKoG7*)r zmq{0kF_xxd74!8SbzP zm1-d(ZP~cD^@ux@F=lKG9Viup`epJ^h##e%^K2}*dzPz|O`^B5IM7G8sNwHc3SfxX zG%bR8J*F^=av2I@t0EXZ(!?Ts}5w6wR znGIKEWSmW6wW@%$2I?9SgIN?xD~&ZKvR_uRJ%u9$B8$?i^5Jw3JO(+LB>`_*36;CT2&~DT{EG2-AmpPUIROrC#p0422sK=U*zm`_;byriqW+vWOsE^n=6mD=pKs3o`6xx)= z?hEgwxJ;=qK8ch4LT6t5-1}g-yO*LXs{+3@-Xs)C&>8U==J&0d0;$yw-6<93yf|@R z=*+A6z5fm(8~#>?4FzdJt$SQuriQ(OZSHbo?~m5(or3P7=r$@dIUvE>ni(`0q%u1t zp0zO0y=D4pvHRFok#BQhwA#Hr6MziSSt`alH4&<>h1iShD(Nz-SbKN1AxA$ANB`Yu z3>uAkhD4()^h?Q6sk+tb z@b+%}4BZ>#9tB)-@6sYHJBO9Nv)CYNJx}4OFvKLFk6VAbx>Tw(j=#p@IPHCfDOV+QnV_ad*)PicoSKjX>99IgmOmNOjkY2oLg zq>w7uAyPsHt3y-R^)dEnTjZjn8<00%0zBdlU~p#dVCHLIt%6aD=aD&FUsw1$Q7KQL zh8a5HQ^)8kELNfVbC_pmW1b`+8xSZ}F^`Re4%;+RP2w8a9)tQ@D0-V!SuEs&Evak% zgS^Wby=i-MI{Hz{znO*dOp1E0|}YhrhkM^f*^S5LkT)2x{@>4y=Qn(MdN z?0$WVgZ|cPdv5sHVl?9u95^$LGjbCAe&iMX(yC1-Nr&hLM+@-Nn^IxTCp4xRPAEGI z4;{}m3fK;R?wHdFWIxW#;IG)7Ly=?dZc{2Igs||PdJ+eyA*=^n8p(G1L*>;(t z7ow`N6JTw!48hBgb0T$Z5G|x`lJ^higpE(fg8o}iJr`xz0A69Y%#z}b)@t!oV;_q@ zF|=!vwRvu`p#u6w|Fiq6fR_rb^>TNo`Zu{({i4wn>gBqU)uD03O@?wB&~s3270^N@ zf%@nCI`!cELy7AlU6dVt59n2y}t z74pn@$3d70@i#_QsDEsixp(0A(_&OPIjwGh>VHdf$6sEDF#L7UH>?4277$jF7VL zn5(0(IwdCiV44LSHNe(yEaqr1Ake5=V^lRy*UWsB6ud?8obv!n1CD#2h}^ct2mXhi zXECP8fY9tNiYmPg0508cK|Ndrs1W6h?DUSDc5sAR=mw~bN+hEi@j~V?4ihY8Qwu5| z7kUON?oj1|F}iUbpg`*6bxVMNYXeMwJ|ivGRTK@cz-m$Y>Qio?fc5Fss>k%d45{Y+ zH&kW$!@w1&Fh+f*_u(wbyz-@%UIVgO0wtxBN{Z`7h@~;$(0s;SvUoDS)s*7u{3h(* zxmP6P?{IKx#}U!FSMnZwGErg);oqH=#prW@J@IyG2ov3<3oNpS{a&NrscU4`f~A&cI4NV!4(?JRI+H42hO~F8Oj%Fe1t@Q zV^LKv57RqH#(*u~$Vo51OwM>x&Ba)c^d9lRY|BUQhc;%Suf}M-3-N8jSPB#?<1Dfk z#(E!fO+j4avC~4Z0~ahSnwlcNw>GG1%GUS>4I=Om0X?z<{C^(tT5 z#onQ{(49hLVIJ@jPEBYX^s<-Dr^$6t!w|%GD$YEv2oPU%t(KAwjo|tT#{#7IlQbRd z_W?#FEos(#Ly7%){h{&GRR_nhVW?mSC4LkkhwRU@0vbmzKkwzUalw$|TAlkco>q%H zHZ*9}lmXA?u2te*6M<4*sAuNIYy1IkVq`l2_6_d`;6@Ovz&+?4M1UEK1ur$@TPTbO z%Q~jE)|DTfxxz*Jcqp3Fgz~IK574?S7DDTioPu$%bDm8f0?-rxO=Iz+J>4i%-UaEm zRi%X22b%)p%R6r=+Vn0^_G5xVJ?`JG!QTJQQHcAIzwcux0^o$#w~BgD=&Y^Dyx>Pp zc0JIU-Wp3>*GiU2djqbW=@d%v@-bgD?4@9#(S#0A^KKK#(;3{DmyC=#f@PiT&LX_g zj9Xi}f_`E7UIQ!}=DLu?@>!dU)WvS+BMjBv$w|`-^*8|9%6Q>9mE809a-_V4B;?M4sb@^KZc)>&`!P9VN zg2$uTC3aZR*zMr-QrxQU z!7J|7m%{+IgPzCmz_jPzzwXDqhji0fDr-6f`yBCa{;c=~2gOzJp|ewS69`4)0i<*m zYcsqI4ut2rK;uo4s&OX=kgN8D{^_975fFauIZP=xGLQ?O;Er>>JqymEa3AA| zwaQ-SqEW8_2?Fd5g68A;dN$4ICf`zCqi(zp;hg2^L46#V;GQ0!ESx#2sfTzKA8f?Ap>KVoIs z%A5m-C^H_*=v|)$iM?ATvx?tyWrhUQV3FgemdK#1A*A$} zkue>6tX+*7Eon#!oAC&`f7bGt(bGbboZe5_YE5?0a75&+iH%&ZzYLUO_ESK0RAh$}Nt<45mQ7k`q-kPJH)1{>43yol@> z7cL6*TXw(?1gK8=B7$nk<8hsAa@!X)!b44iW%hENy^6@orhsah=?tB1F?G@VX^&FUF zwJaX~vm*)VJ~hh(6QEuEkn4z1&u@76wMt=Iz?F52N0SQWTOJ00+n{!h^uFpPi{+-} z{)*=S6`f_RD?(XgYffhY{M8Ky^I+ zUa81=2=tg9N7f!XRV4Lo^u_PhWk+Vg^P1FQm3VMfK!6h!Jhp88kM}&P-n|Ta>F^vGU@wK3xFEC+!6^ervJuJ(Wk$ z!N+?H7lFJO-MXbR&;J0_aqEOKA0TlcK^ZX`*PMJDa3Nz5+EAPf;CcGut4^T|yjwAEr)f7aLyNO;J{Khfsoi6?WZL;25)tJq(VkF$S4vdROb zC1=}TKK``!yYrEU8FScy{AY&tC!QqH-J_;%xfxsl+)3Q_WMbM7ZY(v{uh-C0^aeOL zLIUazR7)H_wR{f2Ob$YjkxySrE=kYB-6G4P_)r>1!95S7jZEccp&vqQ3vBV?o@w>+GN7r==!_U0e`_G zF2I0V)mh^(?fs3Px7$S^Ty!x7>@UQ;kzqsR$$+^6!}|l7@Ae2OZn+7#KhBFQn;Rhac1+Z-KCLvny9#nIwYBz}F95mw+BNmsC zKDcm=1%TVi*a=QWqQ+xfdD1F2Jx6BYbycIc?x!mj++ZCH)&bu8&fGsB#D=+#w86C= za*i(R5)=5MQ*^m&NdFrE!PHw05q{Y&nP%jdEy!KPjHW{q@94g6KKMYO+-m|E2bmx+ z)`RZ=I2Sq1`W#)_MZn3)LBq@CfA&lJ8UN`Vc$lL*e~Eb&N3Gn!IZx{SP~l+;f7yU3 zk`UT_))~%?HW}gfRbF=c_L*f*EX)D`hyIJ>y^pR>o%slYHlwFe0mc>549)@Z+#PJ; zjY@AZQ)RtzzQq~`jWq+jfDNN6K`Ck?Q-=*xO$+ck8WmWDVsBR55F@cZ{GU5#J`X(&6NI6Dz#H2oB>j?!fME#; zR%udi1??^bAC;eb1q0!Kvz%=Qva|I@O;vUljdy^70R{)>SAVN=w2gYIj4)k6rJ`+| z6Y1`5QGJ}aLv~T>X2{y$3(I$0D`Cw3H`{jjANfl9F~OQREh__u4|;=Utj!r&GB*Y` zoqKE4)?BsAcC+)=zXv{p;Ya7!-M2i~@8yec+!LY*oVfQ61}}2-3e8j|-cpGdLJ1|= zNov7Azq9!d6zVH={%#BzT%f+c9JK?kY$WFMOZ3%pbFi9cPYb#fOG%mHjb5zXuWh|3 zIkkrb{X14=rh?0$jsRj#cc5K@Mi8%PXxz_SpLl767z%=;TlpBmC6lJM{oCyZ9)pMO z{(%oQ`yFiu6p_nk&A&CiasjV#6Ur8HWWVp+s_d%Fw?MM@Kd>9vl&yFAA~cft>^oY2 zdGXc>G-2U#V7!slNi$2HU=hR`B<_&Fw`qQUsdcZRs?^pX!z`T<40L;c{JjgAy3Xgx zq5x>JvtNCGf4*&?s>trLr5~O6K)e2Cx_FlFI+7>&{Zc zZ$znU07*Vy)m~+7@8P`rHoPXQn_h}cChfl`!~O3L)Qd8Q69unp=EibGOQ$g&K1I0R zeA`JWVLCT+CV73VAL6$2jzrTJiit>y11OI9)x@*03HCYYsDhULvo3vYIeOA8t$@KWftygtE{V2-^E;v zXB(R1NUn!=6{BI90L!^+mE)~)o_=hT#o71W`}OP2pTcLmH!20Ei{<6wJ~YY3mnsUm znA@knQHnJ;U$%8Q*^Z_lyK!IS0l$U)qP5&;tMdWj8YeYI|Ko%hDeo*DvV2>!qjXyP z-r$!sC(^k*%->dYmLqR6m)ih+vr85H39~>Qa68533Jl)xzMOZWjb*!DXs7x+21_r& z5De|o!uaOEYg>6_$hIn{J7y`^LHh_wcdoZam)jtG@MJqf#6i3|xBr~^JsX1!J%EA{ zbFXN-RY}zsK?l-}cSPGZ=m@G5!cx1k-$agA*Qm#KKNVyjrTYhW978(`vnL@?)0v@rGk zV+J1%uG;Gxf$&mBIPg;0Z?1jW*~IP^rnDpKwIWD2E>Bb91Jk-N0nad(9m#&VXnpf6 z+TsOQu{OpdhlIPipvy?$ASQv7A_4ccIqE2S0v_9o(c#)FeMugu#*|8~x+Xof-V32*=_3LX{%LVB`7Hr^32 zQTN{gjv8%somQ9y=4s=uGbJ8s8;cdBgdah>F|?L``C&K;F1A{h@C3ZY03Dz*qGIkd z?ng7rqC8qSl(caQVVGuF#A_`q07ibw!9H$57OIsT_F&9l8IemPj-iA+CzJ~uTv~x~ zYWD3LX5aF((<1-^JGSZDDCluW7n@by0ZBQaTbPxa`^F-!np10Sv@VNe()M4Wd=KO9 z7?1qR3SSWD1jGxka)n=*MOuKpxSEusttn4Nc{;!P4=?-mhKVd}XZu?jai@zkkZIfS z(;@Y}C3tY3QnRqY`hJcgH1J#&DYgx)>Etfa$K8Mm2GgdZmislbu#DENF{4D|U*+cu z9R9Wek<7BY!KXF~T7<8ih`K65fUUtUEDrt-#^kij{b$r{R@?vD7xO&yU5=5sdKS!pdW_4Jq1yV=glfu$WH)j3g9?xYSK-w{fyHRU^J z*(v625v8OZvtgV!>A4^|hpY+6gEc9t6R;-DiXgyLzuSeEbK~#NBVpQAK8>TEcnZ1r zW|dp4=5baz<^5eq1edJ#O>oI#FSJ7ikMr+1*k1iXzjhLSAV$N>Ku&hU#Ly;CKofdo<&Vsl9Tk! z3_WyyvSmD~#T&806J9}MEEQp9x^))jczDg^7b-rZm7h-kYhl$Ic%Q?!B~PL)qC zyCSZP*IrSt_oM(>K(w6-%>lWSx9915XFuo)d>Jt=bbKj&Rg4d(_ znEMXNnP7)St@zmA5R|`3uz?pxfKOO>I%OzJ+vVmc0>_)NYl6WZ>pl*tB+^>N3~6+^ zIJqEHOG{_OQ`O3gS8CyaKhxew)58n zOq6fCfmxR!K`szVJ1G#9p}D)R^y;YY8CP9hg0h1I`~8YVZd1SR7K-jp73Nim#uGwL z7ZGQtV>5u(*y_Dv@4;ZJbLxqvPX+85?&t1OwqnE@@9)kAH!SaAsFf!2IsNjK;5{6a zMxBw!+BnvY^ib-<6}M^$%R_BXV|%x=aF54f?U=~-_bJ~hu`1+9n7L{!Iudv`B)Z#&b_kYvM1#Fn>37G1#3y+W`c>M*i$1Vc#qo4||b1RhP*3ZVHm z$rTOvcXGS7C;Y3>P%gKo-wyi36)0L}}fIE(pMM0Ty`J>;z2pPKy|wvCMwIDWuv-5yhhLK;WzJb&fb zAoAMgrnf;w1&1&@-N){F+NvyRL>2iV^|21o{<13O3|;&QXYDzg)d?nVzOhS(^iO!` z`KYMuq!Za3?iEixGgTEFo!V#sZ5opXI*80_xZ%;Rz&x9l8f;bvP3lx{FMWx=)V=~! z>WTKV$?FTYss*F0>1h(9k@Qp0QU4WYp~k61hwea&rD{E)$#CTe=L|#7*cg9;5^*r< z)NGz!IqkQ}BOrT2o%#VTdcy>jQ}ncmzR1h2Zh>!t2D4|bjvCwd(_`XmtVevI5GAeG zYuuZxZ+Xx{qm%r~F!&6dN?|sZp0;K}zm}Bhu#UjeKc>w%HdJ*hoUNEj6Z>9RT)5TK zU+pVeik^^e$d<>(q$vPKKA^S+hTC|0IHC+nw6^_QxDBoh+-WUqX zz?LReTs9&J7AV)R%XFAhRWYSg*BRkWQem@dZfy8C!n217EAa*zyTx-k+z%eI<30so zh#hDcTWQ;M_UIzeHwoDbXEs^*BPlYto zlb)tI7AfT7wwjQVNl*A>*s9@<=rS$9QaazGZ{`N}S>$-yL;YZ3SN(sUacl8OpNlh+)LV(Uutfb%5S%bC2h}ezavjh8{WZw*~OKO{k>v%q6odvldlWXgaS-%`` z<(x>uCp=LRVXt%5GIwH7fpWA3su~|^?f(r1 zdWq(+XR9O}^37Zva7)4i;HfeF2|zS4U4M%~{wi_zX0iJ-50T%8NE-P}eZ*-B9Jn`u zR8@<>%tx-Sv5WK+m%x0~DT^%92tYdwkwq=Epqj2YQvCn~MulfsZZLYvt#T(GWx*i? z4e+fP4}hRleT%H9VStV7?~w>$^!31J>Ux}T5zA-Hnv?xTiU5!hMOexcWI@`9Z*>Kq z`pn&x#{#>21)w}-my{b21M#V%g0FYc855JoxOtiEm&rXj3j_5#;S(;d>+-FnU{jlb zN7Uy4E(dzyaQgYmtz;m*hKi=Wq4K4rQE`@d_Crx@Jn8e-irN7^AumkCZ>DZ)K*{NI7F@Sa23l(|3l_IMChf>bJB*Uid{o``flvZl#up%%;8>W8ap#F z1Qa>h%6UgnOb)qG0-vc6bJRCvv?gl(07AU8SOBcSMhyt%YVo@RAoADxGxI{FoJ_or zPs4}?J(JH-Cks~NTXWoDTXZWq!2vHQBibB$n=*QC|(_g6nYRIS3{EOgF#Q2!PaZ z{8-*tVLq~{`p95!(vWfj~Uv4^UPNalx6seuyhpq=+{f_sXR zsu5#e?BGw)h8H$u15%MJrB!>+^PvHxYNpE04z@is;EwJIKB)A`eotK!n z2kl_fC4J9ZL5g?672Od#C|th(5L|wjIndQHM>&0@>sRcjFo+H-a_DBMyyLNNEiRM` z8vXrj@4P)G(tNS5*1z9Sl9HMkLvZD^PkS!EtA1JQJrM0ipI8ZuciUrR zIj}vK`2=B-1Q}n=@4fSf1*Fagwdxvo0+@ z43=6#x}=;o@HQRk_A-$X;_K!~6et9@flt(jp|4JUCCS!--(q)xH}?jbje#e&cIAT1z`K6k)sI!u9oi|Mvs$V(jm@ZrORXf-gEuJ>f6Z zc7$I2$=3N*rVg`!g3nF3uI&r7$J1RjGwnnx_b`VlU#4Kdvx6yV_Jzr{1rE$!RX3iN6nbDJ-G&tzEV-1q zo_-N#(aVHq+nR$E1}f>#3*`Uq7^qrMPZBe;y0Dm^I4oX!D{QQ%HzI~H8L@B41?^9@ z(m=IJ;#0%4s)J;PWtJXFP9(2HZG;m&{FH5r)z{t52XTSC#Gc^?!l`vDR^l0UP!pea zW|H`4@$19~*p0Sj>biC2ddV$5{?dD_-nt6=qqQ~2DpIZfGcE&u)LspugjDOZUoMM& zjMW6}jccka}0{RW4 zFPX@2uy#Lssus{ce647eWy8}S_C(9u{EeLEzCZOW#EP|dS)j5Kd$pUE?<3i)_3Qjv z;q^gbmYPimn9dbR9G#DQICBWMti5-9XPo2`!bXP$OMv$^XbjA>+`g$1_wO92QcM26 zop*?nzxV13BvZY3ocU)>Umt>S<8~Xxi#Mkl|2+?Wm`~>?jjCpe-o_sk0`N$+8#`Zj z{9=->wC~?rsDE=7S$`4xO;7DO1h|4GV1LP9F+K#sLXGLU+wrBBgJt{YOhARs4=Ivw zY3mdP_A9V{4G*F(;UQy~0YEUUC=)d5mA8P%VaZ*m1D>ss`HiH;3V$qnv@DRDJ9qx? zu;1@P0(X|unjuh>IVuXy)8jSykpHx%{I>%=-YDV6JKpwyvG&QoZf*$lT(f#>3vwNj zTfF658(`dgY<1)B1E*?(HjhHiZMNQKrR??V2}gw=)o+{mn2h+1d|=yEum6;OhdAKq zDI`#IVRTDV<9`RS2q?R@ZY2E+b9#CkOlbs#H{V#sU(NEqy(s{hgrxJqsY-bX4C#Oi^W)!7%;`Tne}i{=4^pXH zkL|k*f)tl^Kas5Dle;@7N8U+)4ygK6p*mgsX!M0zMGG06nTRd++z(_EAI)1knBUWu z1=fWky!dxZ0X_{5y>;RMgzx?i3|jX#30qSOxixEoz}riS57;-nFwgS%2X+o{qQ3?V zp49$n{bYfkMI=^yP36)BDCK{sgiAkO^4MiM_`rOXpY)za=b=;rcvQd_8XcerX|6z# zr>Fc}XP}iLm|qR>3)|l1%*)!0;|>;Ooj}P@|C%kHamuXGV5=o2Y#TrRp7HxXidu-+ ze=WtggSR^M^z&eZ*X|P*{1qWQ{Xq2P-;)s0cxsee_X~2ThlY~1hZvJ{D`#H#Nnh?y z>ru8j*g}RrfjZr_@I0_o=MQ-nU!gC^HE+gI_a$e6UzSIAc=u~ ziOD%YEZ8wD4jx3zjD8U$FE=b>&NKV`_VvmWK%HTSgp$;OE>!Q7bG>tiOvFLBFD*|^ zw=OBbXJ8ZO+eGcZ5drbPfo9}2bAEKQQF_C zCp$YZnlV>7VHDDRY0K{G8s}bxbf@*imBQcC$32JATKo!N$2) zV9g8p8M9sIb;Yq);2)jFWM40utb>B}Ij~MDz17Yy{Ja^akNg!#xd9-hPH^!mHN6>R z;#`b0jC%J#a?;33XtO<<>sydsvfo78rDYM+HAjt}t~C$gK7UYl;W%VLm+OS|zkC2} z^(nyD9NkM~fRBRvcgS7c$bX|<#r1M&HFHe2Qjxhm@y3 zD7Xk=#qNv{@cc$wVMDlO4*^tQPbgA#yt&MD&42bZYyFvYxFc+G~P znx`N)U2;plz2uhUm&42JAcjeJi;#=dAZ=CYB}ZazGZeo9Z-%#QtjxlEs6qL7tXR|a z<(wQttO_5Pw^yc=Lu%L$zhJ__ajTwx@^r6|mD6#80z2$dHrnJ=;CP z{TgskS)j1e8RUoyt-OzJ+E9{E%&sbajZnZ#z%#kd>yPI(9sy99p8W*Dp}MY7>Q@mQ zTA2Cg@}$SvL}mD!7z~MOrSmHk?+m|_2lCPrL>knoa zX$7m@1{~VI|0e3$`CRr}vfl-{ZSr0TVTd0wZxcY(OU(A=67U)yPPnVV5yiJ*W3dt2 z3Zm{e#GSK=dIL=~OYuj5FW35`?1PJ#*KZS||I|ursj>SZz*Db#1r5vJG|13MKSxJ! zziTB-->&E=YIQ`A9KG1dFhnXA%VAq z1b@7DF98D;G`|pxL$3L1^?nQM0p>@&8>T9)-1C&IOPJ)hWSa|V82RSdV<(&9eC|Uj zaBJct+o;fwZk67?SN?<`pW>aJM-C$_^~z$B8DApkNATestqqvNo-&V&Cv^ zPP*-XnQ?kCC|FA|9i0|MtBrHN5w+!`+oMYLW~09| zPTrJGJLW-qi;^;(P^PeqwCf+Ro9Yn#S!%p{6j16Q8|iVrUaCx&(1I9n={Pfu?^b8i z$8602t`jc>q^*y*|FhdwJFXe4eq-QqwrtoXS{TH1xad3Tq&tWKUtI?GL*h@_)IRyM z&I9Xbp}e~B)GxCYr?FhRR&o^Od{Gkc-Qfk03>@=ri~DU8)tKkzym&@yQTlPz@OV!w z#@c@1NRBM)l1U7AzkwYXnq`rzl)q0L&Wsv-e{v#f)^zT`mN6Cwqg z&HCED9ehyPWXUs_VG2?@ zR%08+lbQH0m9@*k4a_RXMwC*fn|W^nZdSvwaZ+)@OX~6Z(nj=AN2KWOs@5@4>2X%l zl5;y=>-E#=E?GjOBHllKCgbT+hwQL*-~Q%Fh*?X+{3!c~p4>23fLrK@R&yr}#8lRCziA`yByj1 z$9dbAY$5DayIfQ5B{jY~dUs?l9+{2yCp?Ayo;ZD^i0sEx=L-aCu%G&}U%O-MFDe(g`IkhZoQqwcO z-4soxknZIYPqr&-6w_mGALw1l>at=zV%iKlQ^}bfx{3FDcN}+MrR$f!*0-HVc3z^? z#uVRWoOB`^c7ag&S!fY>e8om(t#9>x$tPa#U_v_9qN1F?7@vz{56ccX_PON~b6c1R zPR4A-iDYwo-Xb1GFKa$`x)>&ze`Xl?41H0biOCIxG>JFy=oe2z`lHJ;lfqyE4G9tv z3HBtRJmQHCrmj<3`;RhubXuME&$1T-qB|=qq2y~x{oy27tr%=ACd$UCe3O;1>6>p6 zuGQp&!Y*0HybAiu{N87rU8gM3zRzd=;EqzFD+!;Qa^wBvI3i2)Hgjk0OA_Qnn!A+< z6ZYQjbbaMl09h-$jKrn7oEqOjoSj-CYMoQ#vSMhMx!acjjfhJ>`Kz!MaI!f>eW!+5 z-Hwi(NZ5AU+MiDAmGzzWG<;kDA-9@62ggxDkMNt__-B~d&~}+Hb-6gB`N0w6l`W3G zwK&m}9T}t@H2E^P=*#f;tvkmBpLhzMCO{w9N_rcw_X-UwD0iUu_2H*n`SbI?9AE^gq#(-nv7LBQ z;Bd8FW!psK9xuEO9{J;%&J^7^D;~-VARo@`1oN8e`X=K8npgKd0a;(DVxU%nlO&=oJcM> z*GKmqO7ua`X|W3!`LK+SqVTI&Sa9908y7$7HGGXAP;24F;l#Sd7(m(Mi+XZBzTqa{ z2kt5(CgUyLqyr!SkC&lG!P+lOFUrf{3Jf1s(4K2V02 z-bZHJTC9aUL|0#Gn)*}&zQ+ma&!Odunez8^E;p7zvhv)o*V0VM@9{MTE=J+Gr1c#v zLC!RWISR?+7_qfpPWOE6pSNQe+T$exb28Qc&B@#u zN5^10I9>0D;`NfMsANyPzwePc3+Z;wS?8F`Od!3qE=0+p^7EYQn|9o_{{4Aa4<16s z*Lh8N`HmF)J`)RC)!hxkr`KXrCc7K+uw}^W1GI}4Qka{BLtL6HFtNEE=&UZ zarr}_&PZg5Omqi$={{ElhX-+Jl}sxqHTpw!!h!#yL9}gCO{Clzg zwbxg}M#xs)3#@U!7kZBd!$=YWj|BrDtyrd~GJ^ZzwuZMF#(tdNHx;SXubc0zdu1iE z*-V&yLLe_!Cb({IaxXL=e6Ch9ywZO&q~JRW9E{YMAri*Mz&UlOX_~p3lH^yRfoFoW zUf%~h5lo*8kuPdM$dc63|5kG&!pC*#XM&EV0K1IP9}ZXZbOH3JF9CaUvnaZms>-Gk z#;=ed;}H{8w5dcwdVt;NEqliIVxQwG4#+!F59DHV$QKYr>TXp7iPD+5r`LuUI>t{M0xwhZx52^#GDMZJT9VfWZr7Ux z>LYPBDy*CwG^R>m=13Sn6T;i-*dHQT-ETz>k?E#;N(I6x;MBoXjyPBby6^o0xu_pe z$O|E>cfaL5F8l5U(sfA;JF?iT6~R4mjgYq)oeZ9H;W8NjWHbS>L% zSU=K3H;V8;Daycm1?J8s0Fa$9_+Ox>_?Em3CjMc`npa#;8f0`HHGC>3GSa`^LsoE< zU$$!Mat;*CN==dS@i7~^;Aum)4uHe|;ZI9r`6fBBVnaZ0V01N78%G#s>e?8G z!Bg+Ewbu%Dj&{`xR|4eAK4O?=g%x<|V++(d-BWWKz8|3Aa|Itnx?p!b+!@<49C?T0 zCZ?LwLI?EBUGMek^c#~m93a<`1{Yw*l|=77RDU|^iJ{PGXRlcp{7fnDq^BJpjC}0w zrmadFL1K&>08?CNlpIBOC-5E?n?fwws)##%k)K?VL*rl_2kp6{Q1w(*SwlzF8Q?W+ zu7xPfD$%n9hrv{;7mZk5vr2~hdnvLVO4fC?;O)(T!hX$au-?KaLo-04T-YZJTQ^YL zz#}Y@(0Bq&$+MdwF8~>LCH+8ewi$6=?DR1W{Ce+Q4cv)PJ_k3n9-I03K}0 zYU~ng<^O4HcL=;xxLYNcG2Va0{Z(#)f?Ty+MRz~Y`@_ocDFqV^AxzWl(BgbyxdB8! z?jvq;m#tQ|7Hwef8qzOP=ze0EtiGwUWnanP&iPF$D2c1_d^ z55aYdPg9)$1EQBx9K%7C2ZF#@T; z!eD`;-k|^)1T7v=!m`clSIyrtv9MOQjLv?7V8K=d3ldK=0f1)R9PVXOFb4{Z?>Ayv ze<17mOy)ea1RO3VGBSizg*+PqoG|_7WMjOXoM=p>{Mqjq?}6Sz zh@c324N#F(6~*kM;v7WzQBY5o8U$dD*_k#e74(esv!SBa`f^et1m1?E?)SG&nTR5J z^2t0`yc}-_HXh;BQ0lWs3oscP7GxWUq(R*GzY~GQu$5{KB6u-8M6)K!EH!iOVSf?n zJ%28XsBNTj$bvEmqz2NeT3Nw{Xpz*1+~-KUkM;C!F)^(L_(~_3-b*5lR8;I8q#7t7 zMDy4si!8Yz_$ z&Hh_H0CQxI({8XgdIFX^4aYnh9J11%2xwgklt1=^jOxd6PAo%qBP!khVp5GLm`;5T zFH)boxrza?OO_Gr?A_#!S(lHJAsg%BRxGJuQE8www;*cai6q1{`=KU?9>eC84(Xk8 zWpn5uA$3uK!_;1i>(l}SI}M@ldZ*8=RBokPHv{)xc&|~gP11<{8OJ^W3>mU0)_hw4 zn>c`QqBz_Og&B+a`;4|%(n;sEu`+g3+tjfI2kG;dQJ(V7H~V{F(!QszIg2zx*YcG zl)Mimt@C6XC&A-NN-^ef)$p-L4+2hPVV>}KTzRniGXr~R;RQ$xCYrwL2YDbe$;NJefhPmtyWPcF*T zg3I4Vdi1-A&V;*AE2)oYfehW)NlTxQ-_gs*!9{BB8NdTasoWvtU>?MdwCTQR`ca^` z$o&r1T7c4itfj%;=?m}$c8M@1&hs-^MDXK|T#%ohhc6A=I|#6wgku4Xq?S7h9nK59 z523d>7H_c74ZDU#6a8h56{0M9`n;*xUTVY)d=)>s@>`&sv>_zAt~ZEKT8BdpGoAcs zrts^!L}dS`eAu7#nhCuf{MxbgkUP>>=b*2gSJfUJdA^55R?X8qbNOKyLY z_K%v!A%;(t^Tw{`t4#Q{EX?b+2GMmcBevX#`-<3G{qPXlYSI~u1J7w*b{sfg)sNad z7ak2Eh=48rj3=Xm90Ae))lc*0dz|v!yu0<*=BeO1g0m*LSKUcn`7EU(3D!-GU4p!L zsB21kvu`^EGnD3D5sn?~U^h7hpMnT#^TqGAMZ=Dxe_j2L{AB8Pfaes_u9f(22+5rY zNhZ&dMz<2T38&D*fjQFA&$ryRiBWa{0oZk^fIH$VL9^H*`Z8MA*UGsb zSZg2ftEHtO7twex=^cBQTqW_g;Aew3Lk&zE4yy-j6JPl*&+LK}CZ1y9HL*l_$pj`Lu`@5#YaE5ry&++yD^K3V#p&k6+U zK#pQY;Yygl)A??;j)7Cd!Gb_21y!`bleI^db%s0LPt9V0;5&xyNM`9C?VVe9fm7l5hpD2^bE}in2T2_6U6w!F5_DJ7vp;}ZUe{k zqP8sS4xYfEAWVy&^sra*lKNFvZxbL&s$+Pt1O$vuG904hb5k-wdQ@6AljXc1pDN04 zZIB}q+M~b&;^s=Tp!;BV$oxV=Xp3LH`7Pf*rr4`ck?xO)k?m3FN3kEV@`3QU!=uJK zQ36`1l6o(QmN?lPYU*uD)NxQHgL}DPIs7VCN3&oM=jZw3e{pgL$SqTYysN-HHrD8PJ6a(EKrvqyZ0yT9*vgG_{N(ST*K^ldxyMY^GE}CWL=hvwH z39JL$%yw!C?W@aEF;I}yI)}4$miHGgTj{w|U2*orke|Z?lldBMrILJl3HH;@WAYM{ z3|qqBj|0Cf&5pXS>@whJivYJDZ}v3SA467X!4zphoNN5Tn#}$f`GRd1uFtGY7X9)J z^;)hubXj9Kw=FOtrg^2*|t7XX{h3ybeqyefW2&FCQ%ZK}VO1# zy~yc}n6bX;P!5`%2TI|CSw!RoSyj`szgb?7=V31JXq$&Rw>DS4gGkEL^z@QV+_J`| z#MiE+(xtLfa2lW9<2&yY0$0G__qMO!yjr@Ew-%IE4J-1Sne5>I_=)An8W^sm9tovg<)2${A{ z*VZNmj#j~T8G#Q!U@C9!0ySuIRuH2ZqsRDJBtL`WbNoJN-3%V% zz=c7i4;S|(5AS}F7FXhkB3YRuVuRxB1T|o#ak0g^jnt+FLFNT5C})yc{Ph_rb|z0+ z(iuXs4Ol#5cj0~19?;iNB5d~YH)YA|5vBLIm^tOogl|j-0d5@kBXAw8rg6ak08JF? zm!u%sRpeP3eOwc4(xp3VUCVensunS}??m6W^{tHa1i0OOmI8&<1{Z>oAB)UF5Y5SF z|Lo9{zfetHfnj7_!I!7YEHB1zBR#X00G$BwoL_0P_;2uC!#54zL(K0UVPxEBd;uM* z=Jwa86*edRoSHXrc9KqChZf9*Cid~)ZEcEi37b1zD?Qt&aPZ|K2+OT+TCJiw`hQMg*h>g7!x#X(K9sG@p<58p z5S7Z!u60CBe4}9Qc=ig^k@IqC58lmVyeUEfhA?=|dDIe&v3N5@Ps7S3+^T~A16obY zuPbow=sjwIbD|WpqDznyp$;BaH43ogg&GAEy0H&JC*a3D>OS5D9#ns?)jF8@hmbbI z`=PalnxIsUaN^B8JRbF>tJP&lHCi|xOmATjfv;>eLG=Mx({PtKC>9_GvMhK*d69o9 z*{l(0mL-axYRc2n#ZNUt(M8kzC;a9Ptrk;w9T(j!vNmY=r4y!YWq6U`7djf;Pr|R zcUS^;83HwhCM>T^4#F0&ypneefwKB;^Zni!oV?mg;irD8Sl;J>IT_EhyN1?g;bd9h zcM9L=!NBE*0}R0VdHjpE8=+%x$L6Ei4Ys#yH7qESzm;oS2mi{lyR6Gle-Gn~_6cV4 z!*JpgP-(uxArUUXAqBL)dv4jmx@HgU`+X*Zott`uL)ED4LY&0%xmyxeBIyAjB!jG0 zp+jIVk%eof`zKgR2s(__V3Y$L9@)52_Hf>(OL5_(d(oq;|Lku0q}bDSFhmi~yl~^E zc(N=1;^glhH?1Qcr>_N!*}Y@2fHxc)V7ho z@_n)SE8VMz+Kzvm?c0|gheYV2QHWAa|F7b1w{Gu?LhKxRXXYaSVtkizX=v^1@Q6sw^YnpeR;>ejb)!Gl)abXR31h-xG zP6G<>r`19ga+W~lU6Tb`-91aB5x>*nzn==UVdGdJ>~i15YNSk`*M(Ah*XMC|5FQDZ zU498rTs3icVX)`wRM#DvDBg?Wd0FK_BWB!i3&Vb8Ie;=sOO3W_2e~NdDs4;@LmWbpZpbqAl;WB5FEO!l<`7Fng?s%1jr9hVEB z_iEDoavji!?oXzrol#gP*`dc>m=0_j-{Hnny1tq-5-CpAVbZFG7oo0H6ok+e%!@FE zZ;@SL?IX-7)5f|mK0a9veD0D~!vFMDmCGR9dYHkgt-fJX-%breaO(nC6&1dnI`%@- z2AeYC2O+DGUB>Ok$1N@1>n8r47H##ij1bHyI*o*{n*?h*2RL_PQR0 z_Uii*MZ3n|AN@>D+Dy7L|GlokMCESA^$0D=%2X1`7_p~2-uVdq?o3X4cX3HPO+5~d z9&#=ozwsqI#At{7okrcJ3GKs#LiuRCp!$;w|NpI6YaIY%EQN zGr0AQp;(Vn`_B3Kkki2rN7>ccgPV!qxzR}Qzatix2A?8v3u^`4S(Z!dIR`5LF^-oP z{cBOx#SN#t>(4tS?5tR=FK*-1*nKCT4JA-+P15axT!+obiTSDdt^GNal?L%fVO;_V zIfU#U&c*ypR@nKD>*#J;zaCHE=kUm?#0j38d~p0T$Ta?NJeMjojJd@U<6tz88@E3zpG?7Q-l`XGb}6!;z0X zI-Czz^LM#Mi(EWvO}b@*?>*PQK75Kz{;;uxLl2Gk+%noq%%2AwogyWZC6wh?ucaFW zVjc_!X7lS$A*X+7B;?T2Fg{k%R(V7<-N~&9z+n zz+r-{Xg1uJgVX7f5V2O5g}B!!D|woP2*XM*a8Qc~q+x+OHp51(qR*8mP<0H%9ezRJ5{I=m;BKXXHz z1B$pdoN5(iQor7*J}(SZXd?%_R1yD5H(}jcy&2HbQC9oACBm&)>%{_1pu1=cn=_QC zK1^Hmdq#{vPUpuD;Hn8uXQHJ|PnQ_Q4OygVH{~G?$lMcNv*3f}^TDYM=;}Zd=QhrI zL~I5G^;~**rWL**8~43SB7DQv;E3A()xe+NR?f~0Wa|ts3d(COnJ+m6#h#ELz|DU+ z!+~Qx(^;qp(@58A7NhORcHG|0{{+Q&;wGfTQ}wC!*aH?rS-|2wRnFB3uOme@#{#~P z2K}nFn?G!M>EwXZ6sJ?7mVNgYPiu5BEbcQ`y?REL?R+OWAao4(9qSqA zg4OV}xY?EHOV>+UZvB#tSiCn7rk$042aP|74w&}DpUt?W9OSdTMRg(F)t{>`J@`yIpQQkX!#E9)eXN;jV0NfeT%|*d<-Rc$$uk zqqsO1lA1K6u{w*;$(H8hU3XX-axEjeavkYiAue>*YmB&BsJ+3#;m}!2z{%=KNbrgH z#niMw$s9sIH8r>SG+F3_;znqCaj07iUu&!fMXpD_P!2L|haStCQ?SzJu$|)8_bA@= zm8n5oYi+&1BNN4tIO$j@47;K>6CBF zL`zRRk%IdH(uoJuer^IcbhK{g<_kRi^p>21_@_uH`SAwZK3d7DNnXJI=iW?*qME zyx`X~nLc=6NaJM@Li38+&9Y`Nf4!s;a;MB$V&4n)v}XZL+|Nl~b%46fhqTo4mCiR; z-0c1aVL}`-q)zDS0NfTSe5^B^{)NmFoUon(q57-y7|@Y<0ACEe{E>`l!N!OaTmvYP zlOv2J{k#(O-6qtO5}fGDcWsr)2vDr&bh5nfHn-G$!E*74e(qRp7m#?ASkn~9EnkoP zsA#7g82HCY`EMzR5hXlfhPNgsC0RqDObK)SpT!b+RGADVe159i!xWy@eYO4p_6(5W zh%ubePnd<+0W!SS2kt~x11>neKxsermjF@@?)jl?8^=T58V52mMnIBqW+{jl0sM9Y zz;E4N{{~C&&ah_?oh{Af+BdTkpo4pN@BVh4im{svg2@!zExK7yOoZtBI%(LYLX?)-%(98}^xVrd*R@kQ_Puvd<(aGX+ z>yH_L{!T;qZ!Vy_D!;MC#7MFpu*b0AlwopC|TzOJVAvQvi>P z?MeqjDp%wm67xS!c7ID5S2RO!zq#Q6cwx*8C#Nez;(V;U(*@HZ!}<}J=gHNNrs`n6 zjroIudhORk6UrhuKPw+eh~IAXiVkOHdbL}Ns6efRciup3u%Z-3;TZT~7sqCUTPNQv zI=~Ww2`8C0Hh`R^@Pxzonh5(#!d&!2pHxT(|vlDk0srTcrq_G%UBnQto;V5h<6>qSoq&V zweqhNlgT%q9UR_C5r<;+k{TB^SAwQt1Q85K#7J7`akYNY>CO9x}4u)ntiGxpq$hmg4)Hg0~ z^MralOk%96Q{9yt)RRXFkOTAgIKwI`6;cyTuJ|#M18SA|MChV}gQ5on%A+a#V8~S& zSEN00bkLDv18LU-q}}9Dw-8}!H+Bn?*&B@E~Qx!0LeWg#g>8+ zK+~0B9^DL3rRtN(i5ln1!89A%dr1%gxGv+-(N7vNXH4&>pU?XC?h6oiJ>iof zI)_Hv7j6Zqt21Cjtlq+ zqqD?8M72+?3G7DEg3xq={c0b0QoBb`}iQrwrvQy&IDl!QiO!DK55 z$-@0H>PBFjg=OrlgUyh8qGl3RXCW1 zW|4<+x5I}Fc!!X;bj$%fqUwA#{3I0sN#I3AfLXxG znhg_B~w!fuZfY>R>Civ_C~$gTvS#l8Sq zEGkNRWFiFSOp5CN*1R-IuvP{Crtr2lKVJ1h0vQXrp%z~z8FMw))tzw0#RWGSq~l?3 zJ~Xlj>+b<{-p#o&TJKc0t~vzbm(M`P zCsIH7NwSj!I)j=#SI6&6AKK{xc1dD@eoqxvNF3 zz0dz-801MP;}q7`HQXt`jC014wsSys?X6n=wn+f|f=pbpGa6;1(npZeU5~_O|Csc} zK-UuIo)_r$PuvmJAy{T5@$bc`(>%OD`n{ck*0)|BGFpVZ-TP}+2@HZ9`xDA-{uuQs;BMS%$7%)MMJEbuN5tui|5kI)U z2$033m~lePP3RlA795b4EvDup4l>LN5^JE_(uoccw+oT|IB{?&$BAF67$c$&JWv^< z3D=-$j$!~1lSospE>G)Q!y=v1F}7MmW%%p#s(UG<8**=>zoZ+dYE23i5q{~Bb?HM- z+u4IrU|lfB%CvAdU-@_D2FEkO)nPj6=|p3+pOhYxTugqRFs+XtERXFjl<<_O2Q;`l z@78{rhIdKn-JUm@IM7UE%Cn)VyEt|hX*f2C49<*oIpaSROQIpW+IWTbPl&?2G~H_I zg6}CT4Cp2CPlOLSI&!R|giI?^n7C^eiVfAD28HAPucJMz88%q6{K}N5;!eM%#M`GK z)%|@hse2+Etf7~uY!9iu&N%&iUl-WMHTcXaF+D%RuR1wu!i0L=d4C>pG{3_w<=-P^rywcLJe=7W_lOuyMaS!>)MMmjkdd~QFMTIwd zaY-|k5AsJoMLD*Km`skHbH@7?NnYt?DuMjkdz%6IFCq9`efgf?h!8qfdQqWEFUdY7 zE-3jLHC?)}PK0Y_Z0EARFW9#5dWH^Vy5&<1`c{2v$U>YYy`gfZ>giKssV;bvLdld~ z$~oks&Cip5QisBB|LS0A$TlJ->z!+ENTY{)-$idp)`-w1;1kIYNwcUh7P+O+Z48FX z!L2ci6RK-Yc-Ml$_YlQ&ix*^UNdJu}S3DBNnK!f3+_gMNcc`WzcdGyN(;5xlZ*aXX z7=PNH0Un<680m}7y_6R==AN({-L8%XZF+dxJvac}qE7fORo&W}ApDu}Ivnfb$WhF% z+tX7u(>espgEmw_^QpH9G|6XAiYmSfMLXY^{H^^(#B0c?_m+mBPXHNQ9-`4py#%Yd zI($OzSlDc}WBpia6kBHuW;EQ#&ao5b8nllWk6X{ExLV{Dj&|3JYY}zDOnZA?Aaxu( z(va$FKkhk;Lf7!G+zN(!Kw}kRXQ_!%x?c%I;Bd^69eEX^pkFu9gGXi|c@^qgAdxkg z>lz?{mCB1M8b;}oCD^Wt=S^wckqdQvqho^rLwX(b!}>{w*L;ry&YfT-gL}zsj%5*# z5S**vI~K|f4)Y6fwcEkrcbNEhtl*Kad@2)zpXY1y!u((hp26H$As9ld#9n1nyW*pi zP+swUB>47EyS?tlD|Hn@#EeLu^_`p>>JXK@cTRc9t-wQubZ|V__N2U?EVut}X00G4 zouP`h;b5Pic1v!?!(ZVwJr4p4pW5$r$2^ybzQRp9z_L3~snmPZZomyAA;T%bP3dFK zf2DLkqvH7x?#dk4bS19IkUAh^8OyH5>YSejev+$$R&((9_#loW#-{-kCoH3U`0`0c9#(l7nv=J0Z@=slYwKvgoNt_?L#LGn}W zSfZb9bx5Qqw|N!w?m)q_9U-B8!FBU+sF;s%B;fL3<-g`O(mlX}4hXd+`0lLTt6xCK z_>*FS`R#`Bm+s+`OBMA#)T!v`>P9>xtH%~Qa!QT&^;-Ps%uRNH>jcN#WO4P&k8;w# zk#D%S3i<_3bJK8W9PHg7-Uso9MTT)M^UBih5_Z2Ez4T=JX23$X@y2lO6=k>*zB4bn z9S>yF%wgzLgX~nqng3oH!p^`d^SDFci68H@`@kx%?AV~$Jf;%J3^20t!jb2cncWJA zUU!|=a}P*HdwVuE11y=QJ$=-Xh?j-4oSP8+%1S&kvw2% z_IoRc>*V8~23z($Z=uNEgmIP`iJ+F`jCjRMzkQ5m6ZPY6Y#EIIoU}9slrS%S9|ft`%LzMXPw?kC|& zV>qAiXlrA&5C^11kho$+105TA-liaDCa7rdME}j}vt7!lgY0=HkhFk3Qd3v~d5_mQ ze}l&nG&gpSvXqXhP|-WFyKfk68JQjApU^Vt^Di(v@~N}RXSoI$@Xj=^hdAhm`t97; zH4YmsWb5qmaRC`mp@xRQ#HA8mzX7+5|8a9w2>c5Qf)_pj@D-@MIK8+&HE5L(@NiAM zyVN`%yM;;|m3d_J$+I6Nbne%ODC$evpqGxZk%CKu^lFf!Fmz|#8uVUVEl07l%=PG8 zkZ6I0Oay%x<&Xv;YvzmW5~M3;Dm>8iG#mf}jHi|L?8@YyOn9y@@QJve&5a8_T3b1L ze5PYy6OhR2r+Ww`nQc4xW!C!wT}N6j61(?3Y0Z3Kn%R`(_~zNFcy1 ze+G`N+WwX8E6^wl3C>?@pKG5wiRrI*bif6E`@2nqRMtLFIqnU1pL6@pq-=Z}N3kM5 zX65hhm0xDAZ{+#6Uat4kqSqv^+ojV-4*Xm1^9gEhAMZ&MpG_VCl>Q;h4#>t;L&>wN ztghwe6i|vwJHbhMa9|vW%n9E(QuY4;o(mdd7IurJuIO(9Vc4SfQaK=ytH5Sj8j=qx zSZOCq%j^a>T`7Sy*hj#lKz^NE7IBkk%TK2KZVf~4R zaq9bAvlP3^kz882V*eek97maMPbxZ|PTBDW%&5Q&tZN;3n)k=b>W@3j5O%>*bP;n8 zj#_S-pbu2x4$KM?P6=N?NVeSv;~O5qP-ioqjFa*sV9`b4^i*Fn{^|UT)iir9i(2@fx z3sGMmF≶)-Mm4z#KXJIaMY7lk)oD25zoiia*!U&G_lh-x_Jp!*uIjvHaeYgu)SP zU&KG((Zh>0-MqWGb!paFIib4UtX%~@n$}|}oCD#lnz_n1wc$~U^|xlaL&~%Z1af+d zHt&C}=B9FgML#l%h38=z{@0m)h#Y)j>r^J^HEro&eCKIrT^fCOtz3~qIV?r5B#v`H zlcEQb>BWiC$j5iWMlvAHGlW0gKSq(rfe{S@DvFvm7f7Bz7Nr$7jGF-VIJ_b~@SPOw)iBrk<<6X|j2)JnvB*8u}(k3F2X zMgMMoFbYct-Ey_yhub=w>`sK6sjPfRxvVTibYMM`Fl+{xLN%n@Bc1W#9?~PMvWKpCShc^?Oo9mO@9**R`Zpnv`pX{B8u~BH&#etB+~xz z)R3~w!^CnNj;%p0YpL=vgenH|aN{LQ)|`vlDu#e@z%GEvvwQz<(Zk5l&->L3Ic7iI zMu8xTaGNSGf^(I$YNFC>k+QQatc4mGYNfK7eZ60&P&|#vyp#hj$?<$30rurw57Gu8 zF7JCZG4sZH;vT}FvnYCfFf3w)bZn9o;1@TJzILewo*!_lPhzqi48=eUjQ<(>hwjXjMs9#Ovk zjWhOa20wkgyUgfP;&~D2O0Y-sEHA`^D8NECc1js}99G{NiLp{i%DJwg1L?XX{3POg z#A-jvf-w&6S^LPfluB~g1KKGjtI?f#0ws6(aUib4q{2bt`KSQ4&Qm8Ijsh@PSr>=>(B{-yH-FXcUdj^ z!J29h`MW_7DVq23@>2WYX*1S5v2D5`r)|{Z#F%xXF1&eN(GCKuwSK{mO&1G@Nu?+q z6HgWS+AGlit4~79+FwhIB8-;2Gm__F-h(1#D3ZsNKC1AxRv)wop<~hOx(4)mPcEY6 zI@sWn#Qd#}MUYhLS`mDA|HUY z!?ok2n(&jBA&X>t#jcT*zGJ&TY@Qv}e)HvC2t$Y@?6+pU4S?M!WAE4JZ+cfq?pQij zuI5%AF5+J+KrmserDT7*-CY z%@zYZ@WdBD@Se{8gXY!q5)+a;#u29?^`#n|6i{LKdkXG>0%vuHLD3`ABxqJ-d*k5) z+5G#vjGG#&5hW>37rJLWOl0n^cST{L6|P)N=pNv7Rp!6{fA+4rDK&h+6rWLOtG*_t zDi$?Oq!lz;k$MwjArKG=xyIRv0z?(5nrbf7khL6p@@irtl*VJy?aA)NPv9=r3c0Ws zF*s|GfpJG+<08S=DHiwK;Y)=VZs+N=Citl7l`P4(QMcl zC8S-Quc-b$(%&Nmnc+cs#ydA)Ry+82Ch&a;7Z}GhMy9x=zQ)(ho__v;5`I)tY~s){ zr4W(TT7e0zVL38xi&o%aMP0jSb0muWSQA=7LAtA;LV zEc>6Wc0c%Oy5QV+n2vSEvg=Orb{TVg$95*Lzl_;eg{?9gzjAg)J>pfSV|?d_e?#Bq zIOcV-=}wajO(OC#9rMgy{;FFZI5|PuFpikaa$M>RAx{(bx}_`sKs1Z z@^RQpOUy+fqPP>%5F$$JSkZT0@Nag1E2`(Tb$|wdU+NEo9H#;^;mDGSiQE%im7^Kpy}(NRR6(1mNH@o|LAh3Hlj z3&bY21~&0DiOnKnLmtt6kJQHgV;R8=>8~g)wMWmz91Dx}U7n-Yw7uDo(V3V5Xkr&y zJ7WjZeZ|B#5I-90@yvz9Ev*%V`aD_7XJuq}@!~URD|W(UT#k&F?=19~CZ#=yXw7!q zi_8dzl`A_7gQf`vkdEp(`7e#pY=lN`2efN@9>9`A;-{GAm!P?!2?(XU-x!*kTpDR3 zs0T1s<5LbXH2&YyocCRr_)xbjb@-gwX=!XV2LGIkPSi0PDv&jp|{L+FO8<{1^wNops5 zZSJ+7`n8uwZqgGW5ShPAgDznh0|=`9SPlT05(7#D$_Zz5d_Y-D6S?(Axj zp7x~X%1RDnarWcbJiJ3Utf}ecz|sA|Bxfk(0S#L z4tCq8{Hg`Llw-vK&q_#PZoGq%E^&1y;(rdDb5>@TlDNV}eZV}UqC|M1;L-B6WJ0;m zskWny1x=X#@?F<27xcnRx_6I)1e6K4vPpP++)-IV`XA{n`?!0{iQusT_)JnV2#LYJ z$CYC)_+5<$-3#W?op5qe1venWw7wO+lOfGBPhWTje;7}KVBrK{biG9&XX6$x81`@@ zbsW;N)TnM?_VgRcLhAv(_u7g}3XCB5Bmsc?12Shjjz4=2sNJrDz*b!cAj*% zjQZ^|)b2uj5wAcV1hla7aWRf~j)vh0^Y4QRuXl1AL*axmXrIh>$hW$qryC+AZp?+Y zW@SL62$r|%p24%ps^^nu?iwuiqyyCEjV#krS7r~*8^LB;IYE?%g5 z_#ln(<y~Qk~v3tBsp|1Pu zty$$(M`c^7f<>6oMPu36UH#gSyefSmxrmR}d}3l6xn}Q45fr%yF#t*Sn+}iyrznXf zB~ERp@2gvZCMcSx4EP`DuSk5H-NHitvTX-nSOkKtAoM3iK7>fyci8FyxgW!CMXu3Z+lH?M_P@$5FrP zPb(Aci4RE%Vr=j+W?H$69fvfqkbA0_Nooj7Tvv^-#1NGFRt8yVH}@kyXfS-`;0Jxv z`(XD<65ndmiG#xfeGC;*c{ZPi5RPQ$`Iq@=Tkf}(g}6B5nQ1+acD7PPaju@IK;J8W zq%Ktdqzo=nHE9X>;lZ#8BfgAf7 zs=pOjLGyJtlBX)RolU$4pka7UmN@=!QcemA-+H&E64uks7P@%5{RgoLh7TP+X%M<8 z`qQBWjsS+W(->YGQVDaf&YHf_;G8^tMyl|A4AYMFRX5hKU(H?8Pztle8$(%Er3E-S zXi6s*$3?fP3h@eZHXr({iA&!z{=@CXRN-(t^Vda4>n?k8h1L)bcnmL`CLEbt4` zfwhmjkB&e{Bz{m(?^7X?8lxQ@e5Lqf7_zSGQWpFmud7J|GMFSdedCj(fQe)XIhyP` zHqz%Lpd-aEf)r5N3K$sk%k;c|t&rjfz!l*#-W+`2 z&Y@=_ZaX(WVi`d$EzQ^&MXs{dzw6R(#K`sMcipM}fYAz{*Lm7Wu^*@3+Pvc%85Gd; z&cmy*@=|h+D}<%K`*%>`;QaU=sD)4|#@0Qn0VwlhM+UhWole=TAER->sx%d30lj%u z>c<~oH1Q3H*g|bvU=vN^e*1^z3|zc;zC#me(X}iMDwSex9y=?&E;O%r?feSE?_4rL zzofU27)tPQ1@T^EyirJU9Ax|Jg_3|?CX+@+pn^z*d};IjFt|@ACBZ(7u+UP@*NKva z;tdOr+7N>X0laGQ2~4~4MbR^bwWm| z`2=Cn0q~^MfUyXxaU}Cm`b2QD@UD*#c$DCr-=}F&Q$+C4W8%azae~GNHpEp3yt&KM z&t1rdWN5`wUm0D0k5X6aA*c{tR@B!E9$SKRP=*eMB^iSbiq~na0=McXNBc8H>aIOu zf6Wjqob7ei&KOF~E^pe~7O5}L!kVWD7#sU{MHml#$Tnr#&7t%WpU@1krq>1R`Jp^b z(LgVWamO$O*FLD)-Ec&~;M4f!dV zSkh&XLs^bK1uv+i6qL~(TG{-#TJT<R{r%+SUJKesP11qY^6kQxQ~H= zN_}Lb>g+nXe{#G6mtz7+rMJ`ndD3uaCc=fuuTgcco1jaP#xt6TXPQmALw~?c1;@uz zkp6YwuX7YU{Y%L zxS0P~Uvyif3UirY-tC$w-EI+)xv{4%_`iz^L1nd`ru*n|v_#xy+WI@oHWIy_DB8m6-h7jZxWMGKQ(A(=TgPD=6*lYS@)_x8K!fH~2yXUDe45ZA_X` z-M+Aq1CXAF6Nx{+T`zYM3|K2z_;ilhE}uOuYDZ6u?~tksmE$X)8pNl)-P`584NTMFUCxg5qC~k~z2Y&y z9}~n+yb@1(Nzdu3-iG;3WoRc^(_?pC@TZFNxNrd;35~sr@TpdprYXr56 zc;+yqZ8EG3=50%F@TVLgZA_`Yw#(lc2B%4k@6SJ6RJ2gm3~qw(y%B$hzIS*0RLu6i zkMOrGoF)lhr7wRIDfv0}QQX$S;$1O6ttWbGrj@)*#$E(?IaR=}><)rU1#BL@R3}@Tr>+*F8#lG}o|SCK7#c^lG$dwp zt`?YiOS`es7r9DXT%#|1jfxt8yQJcgXgwBNrV{b-vhJgo8y{_rwa*<7DX|n6|0+E< z7IXARANShSBmL@Kf>qK7zl-S7ZDwBOJ5@(X4~sZ2j(NE0hSaM34DVaC+bm8@mfgNo zw_h@PlA9*HV)xinU7?%p*2k+frJKF2p1)Ahsob*Q#jCPpo|(aqE0CFRT0&i&JJ3UI zz8IM)N$K2?8v623F&Xk>8fUE+w3y@fp^tB3bntcu%j+FOn7`aGCbB)VlW)PCs{FTy z#1~mg7dO*=mi#=yZH;^)lZfi;-S2jxAQ$n`LtP_b(vzY$8r%BMGBGbpa9a;w)G9a= zgLW49?dS>lvW#P2B{EkleHyMH&ES+5Frr?V3>gR}fkJBBl&eIWEP)KRMm38HPfVLE z92F^$MXONBWrwWZD7VlJ7SmiM3rdClbg;l2Oqa7>kVSmot|fr#>!sJSskiCS3!fv=Zl>=Zo+RB6fsZk#F0N|I6+ z1r{^xDa%Z+Vq066l)tza?EjN6H?S@E(zG=MV;v~ zn+slrFh{`>V>}p`s+wr0=#eBL900O1EOh(nv{H%^_DufQex73rKfcjN6ZYIdSVOMiq3JX3HC7; zFUa^W!mU!WvcL!0!YKlzPzAwU3t3f4>DY((1?}8pk=H2RZ2-Dzh-muM+kD}8Z20~0 z58LefN9ALJ{tq_1mD;smMeUdA6ALpdg*clpv+{f7)PjYdKK$wp;o)VwD@_^vS zqgy}<91qBT1%TVuH%iC4n*ny5e9bKUkB#)W-F_#-Xa9NO40nA3fOk-GbKPS0IE?+Y zFH?MgaXa_T!2*dKS1&$)ybw3FJ1J4F>5K>pMZFb!ds=0-_;(7T7;`C^g3&FWZOsB1 z-L7xv{M};#i}(0hArI$)qp#88eVm-oS_mS|i=(!B-AzLJ-@@rVi>r<)psnshsv+p4 z?3RIANc;POgFwmEES8v?JnhLm`(t;>${v;7Wz?J=w=i;Q_|}j|4y>h75sbo2EhM~) ze2h97=FT0wIi|m56wyVu@f)nNV@Mi*a9ePxz@o+%jfxX!^}{(CrTs0326#}5IjJBQfK?(tG z$D-er4i@+ZbmuIgIGNkF6X`34k9$jTli%S z-**{CzH2lSRPxRn{P1AkB60eAv9FpN(}s$?S}wc?O+QZDQJDW%xzixJAjfNAC zQ+~bp;X=R9%7-){=VqF5NP$hUX0UJPd~}LF6<@ zhG4$59AKO;3?%7St^aF1fNR(Ow%hIrMa}ouwugY|dRiA_0K8r(blF%8Nhc#uCsIPg zF*^8iB2eKDP+!C5@IUBlG!GPn>gyO_83PJs5NioQ+5ylEe#;+qYlSJu!7^{x>>F8&V&HT?bb@?*<7mtTJKjvEz(r(m zbZG^Oa6$prRUH1aZaJA3Vz;;J0;v})u@kpJp6xHZ(^JK$y^*Cb{I&s@D)`!lik`qJ z1(`K{ggsWcU!7Wjb!dt>6~dfv2OpOMvhiUiK4>uiL>F(oIh+y&;;+kIK%LuuOR(l( z44=x_%C*Yu+@&K_kFI z$FCqIC9C?7IquT}a!DLK-~#0by~oDjIBN`^RscII!sagsxV^E@^!=aA;H(>jfF^>k zIa7(Td`%tuElH?4_y^RzKPn{Qs&SZ2n#12vua0nzm04SLP$}Q)i$nHI!0fVvQC0Fw zy z=?f><59Dq9C^bJmAV^3)bR`+6{<`+On+x%K+>b)IC{kQ+XFAwI0bg*k?V+aAwBc-r zIc;#x0`8cy2iah0lcXJ3Jk&B!+nO7i74;1Gy863#WhHGeZ%jl9da*?JY_ZdV#)UKiSqA#KHP!SOif51 za}k&W1Zybh)vd{4pftvtk7nj3rKeu}+8g=GIm{}{VSCj0@aSY641c3_(W5=& zs>45J&Ft$d@OK(@Lo?9C(jr$^V@La`vv#AYK)>_%3N}0$-3GIGG8c);>3YrWm3m7b zYPGFZ5-xI_P_!IP%@a7N&E}ZKbW@ATM>s$4j?P5gE^8H+)#U>Q9K-ZX2-)`N8nK%L zrfpq89r&2rM|3UcgYWQm*WH>$;;mXfQ7VO46sFPZxA97PD@^6^;J*RNW&0dV=8yfS za8K)MkG|HCCe4laKkf8{;x$AEB5SR~q>3D5^)#YdB9A6$l0FE#RwExYgDy)8H0O&` zn|YOjDGi&t2M<}ilq%tlic*W%U919HHcu@lFY9Uy_nz{%9rY*x`kT-9-@f(SX<;El zr$A}HSs;)$9RbRu1@C$v3-ZQea&a8p5<<%g!w>qY-7`_XIj>Q}8lQ&W z_~|L!kc=XqCY8= z6Uu%Ju-8>HAeZ8z+6$O${A0J39&xwgOI1IE8M{NEqz0#KS!+Uk~K{KM{X zH$lIB0o;_v{mm%3H6hpjbT{i?R=8;~b3+tr>mqF(-8Pn(6KV>?n2SJxwq>R5D*#L< z=8O#@7#knkT_BSC%^F961R^L1X^Oy{SyHuw_Z_V{2N?b@H|Y@p$H(2QU#xLCV*Urg zqp5PAhN5!sui!zc!4!v!sT%1zd=POi1ZJ`A@LjP#V)5~i`}y{N%7qp)u2C%VcKY;p zr__!9)e*W5Bfz)95q=L6QuB)!77|9v5W2Z|3lWwl&qs9tvP$yTg?OtQ7b_eSYjeCZtaBl=R@IP9Okw2@XZ2>K?>T{SF>TCeB7%}gjN>J_w~@7FIGtyt=^b{8PghG zDhmfw2@2IcMXTOsgYP8sThTCiR?(Ak)5$WS(UYb5eei8uo&1J+;Z=U3X7Q%`AaLiM z@d>%O%iRU=X zzu4P05v93~VIaNrHr|0@af%*fb1e_n7bjPz>3eiFl4g(v?4L`49=1^~5J>)9I-*ox zy|<9=j&&+IZ$s@Upam*gZ}JK1Yv7FjGJ88=W%`9;Fl=SZ1o(_-o_jWbzvW@^<9`X?Y(fLOe zC7$=3drtQjsSn0A~7qAQgIuRR^I^!K(j>QAE_R~bVX zsa{gHqDh8(YYn~_8+S?0kRpXi3uemRtH)-UKrC&&01+&~Se(WGS&;uGJ9d7u<%=N6 z;ySVXR^#V#1a3op1($l=u$b3N(JYk+90tfgkkKu50*ua1snXm>CI-D`#{H zGniT)QxF&SLF4|9%QpF=jE_hCLf%5J?^DC1 z;I7Mo#z*{eUOhYCd_uY&S%F!D6~t_~qMraW^B4F4T7T7H?Q0~7;b4dj9Fb6Rh~~Q( z#z_zXr?OwpbMXD1xY#ui=!nVtRmy`DVpdmh1S|1AQYflJ9%y}8zY%xj4we{rqi16m zBT2wx{<3FrQS&knVH@18Bx1rvYJpRBe(WwY|Iq(mhriG%b% zGCk>p{lLHhN8*b}kRql-?lG#%`tS7E%drPD`x_I$lzrmt#K2ICEmshs)x`-jw_3`B zzy-J*Ig|(x&u9H(K&({@Zuqq3dzbn1eMk*JKF$+kp$}~x{#)H@ zb#WCU^J%d^@82IAP_cj9^i1s5h1BahdN*w^TI!PxpWlq$qd5KTl$>g*D!*Q+qFszO zDa91h7^^5_^}mO%cj5xPR%=`UeH!F3J4c;T-kwb~6T!+ERy+2~1GMw{Q!!Ds`|tTL zo7n#ic{GPj-@8-&_eWR}bpRh@LDazoZ(3Oa9QSfzb^$L)b6}FIIkh$8CX>B+Y?FG@ z{|b1|2%#{NN^9+G4FWyvM8kFU9AeMu#yj|Bb`cl_F8?|W^%qZnJ`g3D+S^X@Gz57k z#PXY)+w17Co;|EZDPPyx33J0G>)6%E=+{ zwhh~#fymBbqs6Scm8!)tNHFvfuT=)6vVIfMlp6^I&RiOpH#IN}z>w_}AFzh3#1yr<)zD}k#$m&#v+~94z zBRu#0`i49{k~)-`3q@E%db!40O+$K6sHdTTiuKB_`IKv%uOoaWOI-1`dS*BbSwQ&x zYP2w=Y?A}S@tONPOMM(B*Bnl-ljqM#6b7VKV*X!A*B#g7wT3Ols}=GEzh*I?PiYJla&_cdH)m50+CCw>`!)2RQ zrYk@Que9(bi)qSkxffDqjd$;nYO2p4#cSwnI|QKq?vb+5V5h0{Ie4?zP21qKsE*P4 z!5MeB4`?A~e(lTs-l>_N)e5vNe*N%`L##@YqxZtJ9GE)M4GEI@%&)F4amm~^JmZa0 zAGBC~F}*<~i3b?7@juc6>~Jc52nUjjE>bdjvNYmZ>*>4A_Rbz{X!~J$8l0AOSuWl9 z9D3uQA1C9}j9qX!y{VRO=bDA-wO6fyPR;H~tsRcIh8~28-y)r)o4z-9AzKbMV5Ey2 zk?1QaOHB#W>x^wjWA z#nAjH{B`;0-@ViNq(~Y)Nol9(bWm*SODoo@bBz{2ARN%H>YOf1=zOhJ7xKMnA%HB> zMx9ZDDN8%ix@Jc8>qTH2el=Gos{?d2sz5vI+9;c{WCY5`ve9Q!0CJi08Zdeh$8BCT z^6wShG-!cPr2t*~stZVtjLT{=t_hEMv=h+1mbS<`q?t&`DpPBsScv~reGw_Kzj7t; zvSC9{s-<6eNZM^jTyHkYWverOZ@(?}FH-wq1_# z&aF1zyEy+|g7ZceH~04iL{E~6&2yj@mi4@S->x5Ey1+T4J_Qd;tgARGB@HNyy0Rfm zuwmqwT;T=O_VNY@@9BorfFEZ}(tASf1%zYKBs1yX>95jGXyG^d0x>QKNt(4a*_CsN zU`CFMt5xDLR%r@ME)hE|r&2VEzB%>{b>kL3oT_k|PmEg6S_p`nz(&4uQAqKD7D*&s zd$X_>tcf9t*+CWYz9a~dRU?EX{mUn~#akWI@L@P1+^-rGeHV)RQ2ZiE!<)>H!CEeCT1se=#`U2)~kQPVM^Y z?U>mycH2iW2LXjOb|AI4R3-pv#DAw0PilAmB@S;nt9c;(0IS3Kxq=lR=p$mC#AWCT zDZfEV+dz}+ifTW=9a=(?b*e9dj$l?ELdbS}l=O_oO;wafZ5wVHzR@9sRGA-(iQ@GG z&qb6vjxGVPs_ZP&$2m$7hH$h^;hd*KL5v(3E_eaixP#< z3F6CHIRJ#0_8|I}eJ*v&9w0`3OR!hxhyYu`D!}TTOKHC?GtT5Gd?O(Kq0?C<{6cgY z^fCtf@eZX5^An(k5!?O$pEU#A#HnVT_b71M?%VB~nS_cUw$Ds%q0i`I-RwjeQcn4Q8>E1$6WGf30zoq3(n zz4Fvu_wWKVbHQt8HanblFDt?pyvrpzX1i~?EHV?Qw^{%G)vf6%5c$cORO=Nf? zLo;^}cpw04AWE_fAK{%{bJAVczSKQ5VPkKhUsd*1dm?>uYi)tQ<0mfAS@x2yFnggk zS&cqD@3q5qQ#38~asRn+U07G4v-y!p`V8ADcQ zoT_Gi%E4J9pLarlAiTU*Iw4rsyw8ZtLcDc1i%O{&fMZ*9s|ldF@(F@u>dRl1r}p&eC6PbhJ$Mr3Z?hwEKmpG+c6ibrog z3cC0yiS+YpCa7~FO(@&NkAu%H?!E23KIm8dn8=Nm-sw^E@wlGzdAMg=UTkOMkw7bY z^Tk0$V-4`c8N~eYx7@>Lt~x#`~z7a}%B2|h`%?~}7#N^FAmdwrA8D}Bk6yr_`j>$%??{xyRxr;#{v0t}w3PkJ&zywz}txm^8tzYH(&L<@R^ z{g79F>^HadBT@s)wd#Y1I3HWB287*j z>$h853ixi`h;B36(+Rfzz={8q(N{bv{0uJizd9=R$oMxoB)eG9c8V^pgsvG43s)8o z)8nK1Bka%{Bvj4WHBDse&DuYEXG!TN3aK-2&!4u}E;FB3Yhex&F*x|wMXscqxVq8R zzHnm1N1?@Y`}M5h5m~r)ImC&iD^}yt8}^C)lwJJ3j|Y|P&0x(8Y)#0B%=y!CVfJx1 z!f$*|tgr3-w;hFFKXJ^;U}X|D-Lx{*OplUc&c1F6b#D*W`xv-?YNhxd@JFhRd{3Fg zeWB8Mp4^3YPyO|Bx@uberv!!p|-G~LnwoA=@j`$L8Mqeuo7o_9z#Ss z!P^$~*kbyLgiHy=jcD(4Ahhhcp46m}b6)k;%clCq7x zy=?eLun>ClqRO~Gv=>q6WjYnHkrZ)~Vi4^JT5khtm6*dye(1$6!z*7S3KQwu;6GoN z&z%Hx4uDah6jWxc zm$5nJ@r2EByO*(^zgG2w^plgH0J>0B5TOECv2-5-(n_?aknh_t1v@Oonk{Qk%Zk8n z6fUfig)G-n4k7syw%0Z;OiLuW4}Rdof;a7vU3Z@%S`TrtJ&%023&%~YJFCTyW(qoV z5z5MRdF_q3H)^n+e#si*1w_tLXD^&(4n(G1$ZI(24IX(*xs`W-- zB!;g7%0SC|7;r6=YdMh$U0_CG5th|Q1tz9NB-9PlN~ysVWbQc$0MMQl#4PUd{4q$# z0`Uaa?mMqwOI}F=pg}AHEH=}c1j^n@wf;N*{q~AOC78O@wgn=4y~t=9eap^K$A!9g iI@t7U=qASpLNQM{$bAaioekUFx2mj{$$fZe&;I~*z-JBs literal 0 HcmV?d00001 diff --git a/domain/consensus/testdata/reachability/attack-dag-blocks--2^14-delay-factor--1-k--18.json.gz b/domain/consensus/testdata/reachability/attack-dag-blocks--2^14-delay-factor--1-k--18.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..1ed8b6727f3acad3294040163334d389f86a40a0 GIT binary patch literal 122825 zcmX_mcRbba`@f=u5JF{@aI#C`=opnG#3?e5J+e6*jy*GytRu-zk%VK$IW`B!CiCFf z9NBxX-|M_T-^cGC?$7yHvpTs_ z+kWZN#jGcxw_n;(O{OvZUGyWQ_d}zKg-Z-<>xJ7LlCWc+2wt@YXLaX1=Zxna%jc&7 zXUFIJX94G{=X(K%&gWz2Ta*5$73aI>>!ath=O^bUb!U_3ljnuQ=Tiaa3a9%Wz{l=l zK&kAh^BH1yTj6kb@(jDd!(edU@@>`m>ge>h^ZvOE;rSTh!B?_VP0d#yPk%d&84XW* zcRKv4bo$YDjO~{sQoU{Y%`(~a)^#?Me}_f^oeu|PcV3?N(4E(~1f+89zGe5`>d9cq zeW-79t6E3`H&eP6mYs7NkbYigvScUVJvCpn6PPz}Z%3A0(jlArNTFsdfqQYw8u@l# zGK$e1+!&x?+<18W5NR2)v%=2W!iTZG~pzD6RErS-y5K@o& zT^k{!POmQ-6;&o~wm&cz6{e;Q_4=WrdG6b8@7X>+_sB5$SUB+Vv(tyAzmIGOHzqGH zDZluUQz_%zErryLo@8dTfxEPC)lz`&oqZnga^X52Nm~2cDarKfF@;xR^Yo;gAC= zKli$Plrc$Z#1;9p$36L^$E3|DwEbI7UEb@PGrv;IHnC^h)Oh&Azdz)Ob?w04Gg-mA zCx}GV=BJcqCrNd#0=KTr_WZlKwlP(=seSt@`HK?#_Pe_G5k5oa;XqRA&M&CDrhwd% z;^_pry)RDKF@(CKL2|?Wju+*Mw|g*O*B)enbQmJfql~zERALrRwmmD8*v>qVyML-S z^sh<}i3W1_>@EbrlLP!C#S-Wvxo7GmWaO4y0U-=$R5<0n*5BDVPZ<9ZRCIQtU(y)h z=6ZhN8vcbIDI?{Mt_IF3S7h>$%9kUZ$peMn(?dq5<(`b|Fvr1`Y34PpeEcg7oDw>s zrR8k<=~%$o*sxB3it{ZoSG{Du;~re~cz{+;aq(c!i8|#|oyhaCYHtZfxg{8XYo_w} z>S|`VXP)WfgSy{&;?0UN3pB6mSLx&;7kX}k*IN2!z0OV$Ugt^qW1H8#&3iH?mz1-6 zGsE>5)EGBiw&vO8nw8Tcw<5V`w-*ZJm}&n0aICnT;ixZu)hp ztyesi^67&U%{sYuaR;ZF#*6e39Q@K0+o>i2XTF}|D(Wv3c?Kw26KZd#s7d#D9a=&Ig%{#P&HGg!JYYeS)AK z^a`;vxZ4$1Gdw|?v_C!hZAzF2h{poIF2W_=dgwi96%L~OQos1I)cR7tT$R<=c~<3m z+Ayz*Kc_LPDr3KBr@R$>t*9w=FWwQ+5N69ib$xT^8aJ)B()4rJvSL$eJx(VPy^Czh z6SU=l6_CSY15Z1v3wrbus;7Qki2>PpK1Xl5{oW zfZM$FW_>W$jAr6BG%UU$sV%t6jHb1aicT-pON7An<=f&%i?B-&MY;PL7nBLKFu|+e&^IzHtuN8F1g|r9))OvINUiQm?kir{u7~L> zz;4R_dFU%6v#)obUxeY5^%ISI^8p_uPyhZsU+3goH!?}8R9j`?bGUW+Qr( z_0_>d%FoL!IYW0a!CeytA(O+FPzGN+E(;;T7AwAh+!j|zA3y-OuJG{_bP4~U)Z;edtmF1m!@TJ;f+SIEhESyM01+%{i zo#51U16HH;GtCQNQS%GaDWgbO6Aj9{b8w@yKDWFbwjfiW?G13-6@*?5hKbq;WT`=&>Z0*yu1Hr zpi)yFUVR57GR48jslg|6f6rTTs(vX8)@)o@nI6nKRy{U;$|I~5zxkZjq#D@)?*lXH z6c6WR%9+!L6<)U67c*gP<~XUm+8kE+xKI}uL93YnYaci06yx&H)F#cO?zIO}9)odB zAG?g)NoaF~uHtOX*o(7Tl7EUtif)=+9${L0VM7S%S!wS3Y?XVPZEP*XJY4rZE-%x? z#9gY;9GH~+8<;fw4nVD&Ci{PWJg;gsYPCQAoK8nEJL*xtAnC)^B!mk>S%@ zg{ucm)G4}@e=Ao9*X_kbi>7@N3oo|_-Z!c?E!0gj%_A%i_WmiTEO%t(sJ-=gTbuf_ zaJg4S*D24XUu|#+g7%c89ex){bQP`dupLMNH47@k3gdX;t&S9X{tV|PpwLw*OJcA z4H`w4?R3)Y^9T(7RuaB5tMvzN5U5@;C_gjBgubcpajDwKZ0tjf=D+;|<1C?% zb+2xUQXrxHD>S8AF9~*jg6dKbpa!|iFwdJ#2tR6onzw1{#RfvnzLI)Nd_yQ7GOjDL zI?Tv2zR<0CqWF>l;aN@-smug7@rLmew0aptD1tg{siO%Xsl#a43JdJMI#k-2H4s|i z*Ci(3cHyriUY0{DQnZzz7w8)x8Zhka>xWjme0JH?T9qS!y2!WUen6e`KU59~CwNWP zEWYp}Y5gKYY9ZD*Agb;TxNOp%p;7W|!t_w{odb2sLu-0SL!kqs!sgmFa}dGMqcN<& z1YwwOw!EL46RcSo^_aZZ0vg47ba&$x5|Xb%>7mNa-W6bxQTRI z4<}zN^Lqq<9&}X-FAV_n_JIe3twxHJ9G>b=tc|YQujO&2G=ueR5F>{DtznK9bj}DT z^rQt2kU=n^F)tA|71{NsIjn$B{5Gq2$^$J^STg8+@N5QjqZ~2xmUMFbDTp}ws#dnji{(#l zrToaEKUR?gu33gd$rWB$QH$sYBI&vfPNxKmd=JoM%eSQSEtZKGD$3}L&;D+C0j!-G zdkZ&d%wfTt6ebdgR)i75-f@tG>61c`%)(pQbaKd}fEAx3~EB zd^@@0#R|yhNr{|W=Sol}(pnr+o;bc6yFz%|GAN%fviebo7NqGp@5*?k7*a7(Jhl?F z?rtpuDNh9!bY8;bHqii&c{Rz$R~!R_#2W#JY49@IJzsVu-_ z$@$261Jb)@YL0g*t=fy>s_I&6vH;rD>;%ey)$U6G)~bhrTrds5;>LmP9Ug7hh96t3 zUy>i!xQSeO;A0vs7udVTX@cJ?sk;1?>$r`(=$(h0AY?Co{OOTLh>6S>S(`KuU*;b62|GA{~UP?naT9p3JRgp80j9IXMXV{EJSai-puf zWyddgI2V_$TyWoevRtVZ$>q~&_~e5yb?;+9RF8UAx{uu*9__||(wgVUt5=y#wZeCo zP#+N#q3vtQ<^aMfEf+3G$J(d@as^c7Q|ylSFM)g=DNa~nFhe@<@75m-T+Ya;pw6&d z00E%o+=N#DhX|3!1#9DeZpK)1)&0T&AGJbKB%X+>gUZ*77I1D;gKs(ho)yEFt zeq_#g^$(lXdhq1%*{7dOe6w(r zi|G%UXTsfvPsEH_mHMrzCS_8CISH=OrZTHYi;lyDHn{4gn>Q zQ$%^%ZYi5xd;g{enqu7nDivd<2EMDINZR^R7)n<|5mp?!-|M9*Vt$#tQ^H+KiUaEx4(V%rl;@>DbA7ZUhwx%z4I1cpF{M z9&V47F3R9!c*n598~#3kvZ|Hob7uP0oKVHDl(07PbTL;9GLe#_mFe+|rM8Vlz+A7E%<+*{wug{t!v&gJ((>V^C(LmWsXmuYrj;4tIP?U5+|5i;bUV zQD_`SvxJh#UjJ9GBQcSIk;~e3^)>)Wl_MzECrr~#b;7NI&v-!Sjt{%WdGLxp7L0w z#_FUgN0d&`v4RPtNa2U8G4V5{Br7$TYFy^x7Du!=g9Cr~k1R63BFk5}xWl*O0dY?o z&H?;VF{kP->x7-o!8=_{6=YHm$e41N08DqmwPSa;j+2ia0cjTuOb#0|nEM=-l_=1` z6?ls91Hw34CYy11)D7yruXlenPjgPzzd&Fn5-7(yn7-wtUj?uP-@Vp0ElaBB-nK1K zD8wrB_;fN6=HSm=O@HKOyhy#x%xrEglUmA2(2t%H2}gXPgs91EGD>ayY)3zM66An`;*!u)aTu5ghAz~{tMM@1zCQY|8mpT9Q#=yFKSqKLb@qPP9FdE zB|R<|K~vF@q$W0(%CH2MD%_&%bW=L~v6*x+S88{v`U+K!y$-mTrdm#+t}wT-DdKd} z?abNyT>5=#3OZ@7>CCy(IEdv~0rmjt_pod#h2e#|!@)a>_x*3GB8(=ln!7y4NEI)q zTwv0`uL~gkygN1`JO-T1hoz0qndrfvy?GIqu{WIrnR0vzVbak@Vsz;pd`YOK^Qy`KDq&fD zxca~Cb2^0)4P+^aFQ;XS&$#*80CMGemqIu{{gbdsMH3Jq0|6Iv`5KI549~p}(Q20b zltQ5D4s>4?Dx&Fxv6T5ccIZe%24eAXg4kDG3a%(ywzXApQb!Z|_ZA0Ebb-!xv49f#q755V!@v&aDB?DJQL z%p(sH5;o^(6=0lUsRR*?1!a&_WdEJY2+N6W_0W)8d^hqk;)cLt>M7r z9Mihp-p2rb3Mtl4&0Hn9IX_D$h;#?8zIzhi|KLxA;}7l|pqEeLp?TVurrx^9yO?Ku zU56SZ5e-u185A`f*sNm{ANKYvI?OheZx*93Bk?Az>34Qi?`<+ z%UxtxF&M|IY4>vw9&|o{VVz#ffisNJEN_?3y;YGBQD^H4`bPiVm$ZMswFT69NJJ9#&AM>7TN#i0Sf ziQA|sX9B&XNbRtl2sN6cHM*U6H;N9{#(Mo9?JXCXd~8wfr}$>F+i4qIYS^tWwj!cy zGlk&<8xoAsy(G9y2&M>c$naKt<$>}cpX$@R9I*$=E?WD~i+?``45 zj5Q{W3PcbcN7wu(QsWCP;LMb80m&3<2ln#B4wu%@w0YNe&Suuwi?<9fq!dulBx+@o zCvPk??zzfHR20=1GPsL52=gQ@^1Fx(b%IQ@d~qpPZA-5H}zV^8dNCbtPguHui42}gcb5~)`+ zpUzahmAt7D38WTS<~ZV~%fQpGAxsrT%dm#sf(_TDdCS?xA!nKAn4;Z|yw~C07U!Uz z0n(6oePdc@5-yA*rGE8@%W36&r~c8+@>vfKSRL1|ab(nW>2m+EJ3UeKlgLvBX(?am z*!F_t;jccHIz`6kkelWHkZLKfs=ZK-V}%-8-%74OV}#w+Z!8tFaU4~(T-T-O*4wNc~K3<6G7{z)9LCaxkQ zu_vd&;{=hljm9-DW2IWf4kbTl7v4*d3QDT6=nqaSyu0;a+f)i7;ek_5lN9n(z^d^S zl}j1iq7yUg&cLZ7{hQ`jS?QLZAjSGM1h|YkJF_0BD{S7SE1F#!UDs!Fh*cl z+t^#=dNRw<0l1!+^7xymMyPh2hV2f#bsNA&_j zd6&qb>9lgALeY!kxM}s@Xp6i{l}-%D@pGdGP#zDxVkmLiuL9EBxEeUu68!*5T4R)o zgj}g#rJ8Dqc7YsWi!F%J7)J*-4;yhzS_=_iw3kb(5J-07M*wC_MkG=%cE>n5aCq3H z{sQ4Z6YeHN0>nv~PFgCm(%c_~Gog8E-IimJ!A^syRwUklyJ_m?KnCUY(5x4><%FRc><^|kqc z0iF^M&!_uH%Y9S(WIDjvyM9F;Tqwnw9eiLK?|m_F9F3c8(AW)O2*xw@<5qu3Hw>k0y1md}4B#_#=jX z(dA&%RMDI0gJzV22$K;!BQl?C)A|Z-+~5KfMN${TbCN-_o#+EiF8;%k%vKQdFoX&!Cc3LIwT!D zIW(~%!*nTnyPVnw=0hq@l0z^2Yhc@>O7~8Ukt5(qK5=VF)e2zj#Z=kp(*?Zyku0Hc zG^p5GE{HOHiY-RV2hjbj_gC%}XpB|@HHRj-Kmc5UK~qANl+#y8~;?C z^XDgO>s4pR@0Vb+l9%NU_E`kNX>L#}yF;B}}H59aZ`M2#+)mlzxHHBx3P&VHDJG|h<7P4;| zpo-Yu47?&V=*$(CxNmeetkm%%ERK|8Ed7Y_icjACfs?n>VI&Yy1v9+ROarB18+~?W z>L*Kg@w+d&leIzX?o@jZFVR<4H8sW8FFohQMrcOgfbR`E`7Y3K_$jHTECU^r6NYmv z?Aac;QoDx88z;|A0_G~KmQkN48SS+v;v%i7u7=w322+x<-Lrt z64C5pb-EeZlokqWLDiel7~KK1%j?P3#LKKMqUp}2ap&~tIa|}IuU?sOa88Q}(K21U zZMajFlQ826Sf~;g?WRt=&*^*=BOW-{EeCi^p&nDIe-5;E&Xc>BR>B?^0qlvnz za6C(5(T}YitStr1O!N}!vuCJUdv%+)JU73WpM)v~yVFA#!#wN_FqD3)Z~H$~U&yFx z)Tft<`TiI@3-9a^tK#*1^3p^X<1La&KWiO8^gSV{S?L3xXzlss?UVcAXXy$Ae*Z?J zbsV5<8faiC-!}ukabZKbFH~C}?VbNK&0*B`t~D*=6&fKr>S+E8c-|57X@}wv^e4bj zd}Zmf`h6r|XMfQt16pGZBTf)Y0pGfc=Lo{|10i6~1)T1-}qMPfw9?0)1v*IE&y6dc@^k z6UA*riscUzT7^y&51SKJUD;)zRm5JpVvG&h1Yejqw`+7-2!F0{Mq2|-iHqHE8;;oDk<$8_Bzt*AcyDDCqGVlRL zChBM}zv=nW3?)E}%qo>+Bg%}Kt0`Ls6s>WGhZJA8g^3Yq6F%DAAbw&A)>vRFW;LUCzSbUCs9fTiFR>(5@qZ{teWtTWEvy?OncJOQ4NE91bLG+JugNDW4^hqicA(Ig z3C%BAHlD997NGc75p5k*_9+3@BJ|XF{#mg=tgaReFVtW*|D{+}Kp$(BAHg)#bY)in zv3pR|=BgkA%a0J1C%*OK##rTRE^0g7%%k!muO2asW zpa}Y-nV~k`l=PY?UP6@}Y$-b5e>fFLPv662Zglx?L zM%u+v67ulL2gw;Rpf{eP`(!g>f`8Y6!LVoU3eD5NqBid zHH8fD-n7EAp}D(xp928GhR=yKMjOHO2UOChS-*17{{gtw|3Xlh1spy>{1r>9syf za=vDpPPBmivv|qBBSQ1<=22T_eoc=;4zUz zVe_Z6H!_qkyq=$%cz1kdO|r}i46TO--j)cI=x56pq&f_32rc~Ym8yNn6NB0)S%cQt z$&1P7IXLQJ4*;U~;&Z{U6w&-4fG%417e`#zN9V!x1&yN-rb-Xq6^ z_7vpG^6)^Ekmn zRGg;(+n_;xD_mQ9kcIlUlAo7jwUM^@sn6uurh$_cS8bjkUjkTGJU*ZKfzI09x<@=c z>=6RO%JC)!A3rc3e+H1+lmMHFn$Ovk{1p3KQHnHrm3s%~C)F)%zhrA8jdd|T%s%wA z%li4P!n-hXP4*GP1D=mp4o9*sJEl5FMNo2pQbgT59Qw4S*1#!l3F@)xf;m8+I&*uA z`@8u2B`#?rmY}+puI$2FJjViFR!G*qG#dY2}Q}-k$GpN{6 zkMKPLz#L^N)rJII^{hTcUrB#XBUJue3f337-ajuiyUDj}KKrzuUnBO@;+~8( z855X{57i;rE$lv+stahBW>_&2$9ZP;ONDj>9O}?!Q66#whWf7F-qONvl@9%EFFgAO zW$;RBM7_iXF~XPQL^K30V!Jsb6ewJ=^NY7rdDg>}ke^Y@onMT5PG5&q=K@BvyXo1! z>_hOY6<*wzg_+Lp}KTRwpjqEOG~{ty-59OtXY6tD0Qk z&5Uq(FoKbGL>Wu1si*AxjPmLKVw0N@!*dK&IkK{&`uhZIZD-5MvVWq~k9t~aY~#;L zT?|Gog*yS-@nvN|J8Q`y^-Foy%hMWGknD^6n&}e)ewY9HsAV0Yg~={{qRhp4l)0vQ z{CxR)CwKJgNu^(zGNO)}?o#NNu1&xZ=6msc)$8%;iW1Sk-Wz0u>p#;=9fAc#^GyxRb4)KKmtiXJBj_>8E*i zdrCr*JubPFB>56ECgZTG=>!n*dG^bwTzi!>bC1vL^vIK$KWUVoXVviM-T=O|<4YE> zf!H}C<>Q6lwRY*^nvDR^s?XokItIk}tro8AB4PfOYA1vWw-qgmeln7Aiz)||Q7m#5 z#o^(k$MXe+AuQ^sC0`sRvbf)rN z3`<41NpcJ*Zv1hyRh3&pn#G7%m+=Bsxtc8j0HPx7k(&SsFOd6lv=Tu?jyRVgE{^d# zta6r1d<%tT1!XE%}&N)H_Fdgh&9%5QPs3;@X!EUTwqIx(aF*gRr zKFlsJsFeZC^0Z2nEl1#v?q^(e>DK01pkuc(gyWXNNh*9P>3~?BJ$5Va@hCaz`ON$_ zN*)1dKvCG7idGLA7=WeXc$4QX>EqO9RygUfaTvtqw4k?F!|G&{E{>{4YM548My9b4 z(jPfP3xn2kVUCHnst_V$EZwVp5=b$ds2!9jtjwiW{G_j2DSZL#~&z(VvaTo zL*;5xM47zRk{`AUdgY+%QI^?VrHy+di#cv~xUp>d)zrZ~s<%GhBaAK*yDvB;QdA%U zkKtOgtBFtvY7C=NYwWC01%PvZ4pv1qmUcWI4iY|1{rmxgSX>?k%?OGq35e!Y$_b97 z+t`w=`}gtdkhBP>A5WbOPuiwFzk4_y_iDzm9~~)nmpZXlvD}c$@Q6XskKAtW zYIw6AtL{aeQ+c;-;LfCt0%r2G&ljxv!kh9q_Jb#U5t0?cMOpx_NEsuPU zO*8OeJcNF8LX})8-I7Q*{G7ti; z--Y2zpUez46s*SHa)Yx&P+D9O9~f*CsoBf!j?CX_UYnvqwhn!MZ$CU{;cxU=u=&q& zY>_*h@EEnht*ORRW`%Cs* zJVLFX&J>e{!nE|V$SLb`w&GGngVjlF>AqE-`>hJ=^t-lTQ%dxUZc+%sn7*5Vi29-P1 z%D?VrmhS!c4^&x(|TuccB*WEQS|$B`CiUX{UZKQRDOr~aWB{I{Xu z-^;6Rt=t9gANIzH%)XR!R@Th>U%y8>JNl*acb~h5J$F(X7}nI4HLdRM%5yQ-FleZS zXH~xM?~5}=tS`)F-c6XFnsCc{S5&dE3ivyGs6Yf<=`kvlqi=$q;f3GW`=hpS0FyzMt*B(?*)IM6|ZVy^rsTE1Qe8M8HeDs&t2y4li}N{{(`N>0F~l zK+Z4eAIprC!K7tIIB6KVuN?AmrUpBt@01E^OIiLPv~exGj7A7-N%KEQCAxGEguA!1 zWopHC)nRNnq5d|h&mS&!CMB0@jF`E(rpaV?ry5$z=ZjkoeV#+Q;=S_rD{n}+s(z8d z9;Ei=YKX}L$K`!LThQ#Hvs1~3oVp4YaOpccQSYj>;pPoFss6F4oE1xm%roG}_Tg2) zJ0^3lW@FCK{ijEDPsj(JwKvsVn`|A0G#aK|@0o|M=?ZIQ(2WW{*q966E4LkPzWy*m z@VMQRR*hChCeKe7NUB5#CN0keBL#d{5*y!(xaXyn_^iwg4Ka2-6qamEL(xN>9IclS zGAuXJG}|=Lt~n0X5Se;Ey^lolKuOI*{V~C(zyhRz_u=c1Phx0S>u0~Ty!+d7*FL}X zaQ(gP5uqIMHZPu%m{h<1dCAi?FfW`$;qkNO=fmBQG|hQ{B+tj#{TQurLDt1NArFBB zAK(=r6gW!{G?iTHAFaAS;e^QLfi3}Y z+4#w{-0>A3a(?D$MyVqa!aXtcMr-QZ&_tzkj+nYmvcs*fQ6w33V^fD_d~Ku~0%F~F@acKOS@ ztjzi%mp$3CCUVyQ3$AsJAh+*~C4E}>Tp$lhtkpse0-I?)n>&jZfvA(ijQza1Df5J^b5Nu=+V4>8b>gNkQ@tRE{gbBh1WE%3 z0nfnp$mw5*!a z;fLnf&8IFZRp9H!ZB$U(V0P(-y(AOEBe6wW_Wi2$OO=@}%%U`4c4~}pu7v^*Lz;M3 z__h^)a0TCik>NZ#%T-qst7g#Etc^D2sVG-dt!^$@RsHVX_M$klbX1&t8NO*qIG9F> z>aw$!sY!_&8CHqWsIyDws|B|=(=V&~DJHIPRAQu0BcT^`vxMJ30astND@8e`<0r@1N?8MXFj@Ri{%1Gx$NyEEBfX3 z5TGNls8Q~8o(WG+@OmfcA}@cLujuj2gd2a#sorzUz3osy>T#08y6Y>n zngK$5MaGRZHZuGvrY0xz%%~(`k@V3`<#&|~<#iU z%6{C-1(IYw1x`+i9*tl8<T8kQXw~=)?C++ z@{sU>Ay0_Fo7M@k2vh7#n;QADfj}Vs%iG)>63w0_p ziWYFL@-_NwQU&zyY;B8TXGzstYJk%ecf}n6WFoRR z?!{@kAylyO#OeefRdL80wLrS|um{u*{9vZH4YK+Ax#9af;P5Z$9{S$`5}&0z0^6P_ z3OK;M6|T3-W#LOS0)hAPxq3E|4S#d?VP*yaDyY^H?+|raBT2cbAuF-;A5tQeUa<0Y&A$Sd-&zzWR`$L=Q{=8=%%QPI^o za`y>FhH_VXTO>Bt8Bv0@n(XarBWcuJs~A9~K)OXE{*kUBa->i&re{0}_c`vQf8o0tO zH5}4iC^CPAD0sL&9lgybUCAE-A-beLzZWwQ84l4Ropteg$_{R*Exe5J0*lJ^jdE+K#k|c67w(I{F&+193(nzO8fN%98Y*yU)X9NdvaP-mrN!%Wg6_j06 zCvEbnFHRfozC?I|b>&bo++tcW&kMsl2I>w(T+rTG4zh+n)A`Jxb|@cIs(f1!H;pZ$ zbUwDEI_#|zZ-1>}`tt~4dWcGl8z#Jpa5rsfT5L$SEB>BL_g$`qX{x>QrGSs{?aj_U zwdthYwCoK}RNn^tqE8lDj#yO7{x6J#H|DLwu`a5#?jZ}&k&8JQJ3qsH`tOdplEK?` zd!t5t2;4U}QuEFdbz8Ri|47J1JW8K?8{-xoZZUE<;@>nC;1NK~2R0i%?#C320io4p?8JLKX_2v^NST z#}@C(E*y@o!$j7sZq=coX?40xvZ|cMe)L^hvnNTK89<2j_a3(JsPY&0DNqKrBRcOY zL?X$3&Zq91Jqic~$n?i=hg;Qc#XwSsK8+_oCan9^-;iC~xK19rJ%8qF!hZg$7HakT zii2au!g0?!Re3oS!bHxmeQSBUPp!D!>G};QoiITK{VCIG6aB`$xbXH5T!mRwohmgS^;Spl@)f*Po6T#Zk?Gk$&PbM19@Y-*8S}LQ>@r%_?K{v`>j0*SYFS6 zU_YQp$(WXN`YBRJ$yDwH%j0Cj{Ww!)?exxx--Fn(9*xTO=d#(nc1Nnw_V6fMpuoFG zg74bfr0ZXR1W0vt;b+@uMuBpjtc=JpnbMQz3RNql*~6J{ivUU!Lnz^hE`COQl^NMW zh6dCF@A*!C%wTJXIqmnI{(kjJez?Luj=rn(woTiydZk$VK)t|0DLMUdtAWpd58s8? z!fj3h8`u#tADo{Og~=7*;fK5As`1mf3F)26dp!cAy8p_A7UxBu;eRI-n64Fnz-%Mq zy`F&E$?RRB{siFGzb3K?)N{;7p~F%8z;b>Ku3?j}Oa8xs0^_~u<0Ni_s*D@E6O4Zf zU-|Qxo%u{o*w=o(6O`reRGs%J2PVdwuzZ^Y@HD=2zK{57r47%kbSDN#oqSJ! zSKJI)3YTb>7jUl+7ST<|AZJ#ohJEGbeI<||uzk|}QD-esge{#B)M#6{y=o6s7}5Gm z071!AGoS>T)1o@bry&8*qU7EAbLtS90#vBElXJq}|J-FK)$Iex<93tB1gZdX-Q1!u zj}0&1{A+u@5Xkge*ijy zMp38(l`r=;=v zz-!5##Ae5yGA%~swvx9Kbl9|p!OD25`kX?#5G1-pHG)EcTdJ!3FgD<7lvBjl{= zKVG$()i;3GrWZ`7stLF&oY$J&gZ%ussh`LBSHSCFSr8Gq$)JfoFWwDER!q0zA6 zf5xEso(*ku+AAx`$0JHCI?D8V60-IqgWi2RLL?R+e0Kn-@2R{jeR1>UEhkyCGY=PwAv3TgUTUqm>~*@pLlQwx+qKLH%D}8xGAA=q6>FTmlc~=-h%2v<=LJ#Z}2vG5}^_vuYMip{m z)^g{ai>M0uRNuxLPNPa*s_0{~L{u8T@M)<9msJE}5}m3ia2I z@bZu{1k%kLVKe=BTjBVX>}ry5qVNBs2v}v=A)cqm1<^8L3e|~6p$uTmSx9oRtCDOodcIOKzS|0SRgZRREZ{3K;-BY|RZo=(JTfQ+{4-*zUu z1X11p-&U8?It8lxC}MueUtqzmncvn8S0G$u1IdOa%>78{7)btPoxoh~iayHT-4wA| zw13^$(@vi^`I!4!pP^2-w*6Aw@rDhdU^aI%4c4r6x1m)?-FCj{PdhR{0Wp~DiBKmN zs~YReI27cD+loDt`dDCC1;p9+RKotK${PUqr~hnccms7)6F%Mla6S`G%#~EpQ{aI{ zg}esN_QVbZdO`V@m!IZO9WkxE&$(nwz9o~7nXU;gqc-z%tLzeD%UxHG?wjO`pc`~r z6hSiGLNFU0v=I=w#^hvq<+=Sxs3LgS+SzEB<_+W|*bfWU_yZ7srdLQVjtcF<=c%OF z<8D>xj0l#wvcveX1;plw@|nu7{yob;4Og~{oqYeM4ow-u_7Vc7PrW31+hykkk;Cu<#4h4#^0d$zOs zR=Fy@0d~jltGHFxTvx)jNnM6)1oKIL?t8n0%UIWYC(@BqNeRiz^4IUgu;B6jHr&vX z3-Z{9bM=W2-AugVhj3R_A3fD_GQIhofgwx`%C?opToJcG)OX9?Mqo=jHN>*j6`I~HpadcDanb;}of&&&Upv3&<^B2o{&2fp=DM!e^?JRoYp&Pp^}IhHk0C8wd)C>7e(WMR zSXo-L@98TlgFpT0-k$ifhLXD7$wg#1MdGl-Na%IG=J#(!j$~a%Kp-mDz2G>r?TROGlTs-+hG; z7m~9aJRC)bQvX2B%JEuwbqJQoG436ee`}D`^oj0-E1+TXdK64uA{r*`6NnwMxsapL zty)5;^|x4r44#0yIP(JWptayiOFE1i=UoI#Ce!KGF06NQt~V@(U&;LZDv_K4+XyXB zP_bI;dlNaBe!SUvz!_)G%8w3@Y7c{YN*G*)UE(9%#>YG2JzdB$SCBd{ z(VYcL)J~0AZw<330N(a;6E;VE-fxWq&)fy302`71yh~0gB;@rVv^f*7aO^nzp}W7K zHCzPK)p>2eY629B+e2f-=Kx{t-S?q0;a9PS9L|NEESG)i=yImPNfxkKa>+Zw z(H`pH-IS1$_U2*+|LdpcTI0?0Zi^GTntUh|IpW40 zj7{S`(ZO5o16LtSNl`9J*`g*MIlkV0WVn#===D=&rUU@=s6s|b3WBLU?~p5$j)p&% zNo{fEN7LdQ~|dJzs>r9#Qa-6RQTV|(xPb7`FQ5t{^66XmW% z0yt&d;o7#z{;^9d;mUjB<8JY~X+azB>;WZioNDpe8HVo?^-}ryLdw(^438a@gZtb? zXHN6*dh?u74u7s%oQVvVwPvjcSEr1tyzS@T4%oVg*vc*)H?0|DCCM$51ZYT|Em3OYZJ&`h{uMUIzjx*(9&ncQ;Fbpg1{x;L* z!i#(|1s6FOsL=&kh`^Pd_`U~Dr+>g$-sCFHS1cltp^Wq?y!}#p2}|}N4>S!xjv47z%%8^gt4(Lg zgl1h1eV}?_c^bv*?TRT6i=iar)Xy6|wH+@T^`Ok_A=~YOa}{dxkl_-xQ8sPTL#Ixo z9KA780UG~Wid8WoYtG#E(jMQ4E6Q2VER*t?Qnp5K=Dkf}mU9)deUPjrXN?|u^fc-( z@7d#Sl1pXJQ>J{sR*YAku;r@r4ovdR@jn-lq4Y4^5vVDI+idkU6 zc6;vRSH5N=-`}HD7dxgIrAuKFu}Dtn4XlV(UalrUmqwlMR}$Nm585rK6{|~CFZ8xJ?WV>TfLy}bx)+U5<$pa zfwiLUHzkE`L6kbLp`4DB!UPvEcJ6AR96wVo`Uhulm`KGW2SdIvbwv;#7=>1I zvmjW;Rvm+a3c5xHX~=F(8&-9F)_{2GA9Ed352n6|{$xXib)oB+3)kik=D}m5c;G{f zCr8)4>$_x2s7l%wVMDp_uyTYQe&*<+z0ku`((sbJ&wkb{yGtNV^K1?Dm+lu=-49B% zt@JMJzP;gfIS)o4xCZ%D%1HebnK5;PNT0Idxy%+-wn3Ucc}0;r0$mc-zTu%e16{I! zgT;{$QO+}t zhdWV`bY75kk(c+3j#H-sdP9(n=Pb?~()ItUatu;eQ;%f78rH244xfIkNMj1JTH)~$ z>EgmdG3ImTO%cgtt0be*CR0d2zAX~Ol-4<$di-!p%;TYF-*rUr_Q(QF36;c~cP_j= z5}pZBWd&YWO!&02B8@H>VH#B@6n_3KdA?C}Y~T=l_rx(hNCx-leex@Y)Y!nNgNMWp zc`|iDd+^kA)T#kS%6{_iRhon84#THXF$1F{4~cx=^8dQD1uV(9#>AEJ*g#K@^NI)y zGho_|-(fkJOqMeI#$r8)9yb%a5_+z$L2x8CRu+|N;EI6}oKJ|MBPpL?vcybbzF{&{3Jh;>oSLO&uWHzf{oW7j-A9xIx3HA#7KMwN(-64B(T zFH*&Qu$`GuqwY+R3Dt=Rj9DJtPt@D4NT;V1c#VvH@Q|og%1ETJ@yt3M`$#Uc0Ojm~*UwfTU#dxdUIN2!o?h z^VVvsmh}uyY?y~ffntU?1#fT2Sd-{VG@1Ou@Z#t{^2)@#G$|{F6EzQGU%`@*4?E*XD&b}R72wnLzEMndwSl zQ?Xi}P&KkaGV7Y5p&T+zN2#8VMnx=2_@r#*%2nlMtfb%r4JWQj!Y8{H)Nd4>42^7& z>NNr^ZeK$=S8Tta{i8KPn+kPxw2~}MKiAzV71uxd=Yq9bVjBAqvz_dr_fb*t??v1Y z1Z8~;nHRGHH&;f7=auE}1J@{od~+R(&{{_IYZ1uZZ(CyriXE#wE5f(iu}#AMg^64o zT%L&*vv-nFGHGj*vWP@VuuUYNYn58pK`Jq6n#~;n8Bls_~{o$N9IWKZ) z^ar|ezP=HEAhL~>_?jEL$Cuy+Jo$<`EMnZ)?e!HCdYhL`HPUg7&08>WV!(=e>ZV3! z=H--V9bsv5pc-1X&MN?0XTy+|&FTR@+oiHU`8$l*EE|lDHMCl4fnm(v*c+ zc#)Ti9`%qVz*w}r=_G}Y=Hd}3=@+ZJoesQk&Z|2zz$EAtkYG{)V95mM4TK73|1qg| z$Pa5&PSdxX5TC)-e6FWYlKw|VLl)+L9!xz_51p1kor1#F80bm(HkkuF!OE@*E@$kzb&X)S#$rHobj8*9NWjtlHF;WQrZ1~;Yn}B6 zCN=H&w8J9L?uARE9%3*irgLeywHDZ+=W-G55gs||2;!a^=QRN?_K7(<-f@+71**tAX^+!pg|LgB&> zyzvt_1euEr8&j)p0_aAYBxt2WM~i5}$Ph=U&29I(?ny@1rDKl^XxGs6QoaI9`JQ_0Je#vk6GHZ-lXIolHQCYm{>7w04=|>;}`A zHq!3%klZZ8;Bah-S*A^H-5W@g$=-b^A2`m(CJf%>{G+R*Rxv3d$eaiLlYWrQCedA) z7fTNXCP%i&2yr=42;~b_JFx%kWyNlGf$StliI~Nk0?8gSy(!RPK4O)~@J;v%8I$`N zgjtx;_<(M!>NI`jd>rEgki;fTX>xBX#bG#}--~#j<^vd5r{SVy+X3N6W}p;1NId_eAOC-``kxvj8Z&I%>+7ro$@}VW6&_z(Y;$e*M3$ z0WQ7r!DZYCrfH|g%!dB-#95aCE;oJ-P4Pj+C=WHrRF89Rc}j*%ER#h7r1a%|QY@4j znuWNvxq3X5o;R-WkwDt2U(8!K;?LC|fpatOm0@&Snq(t&9hHN+R#Jk9JIlx)+1Um& zh8Mm5hfP^d$Q6DMw~+e*RfL&Dsul>g#7S7B52qg^cPx85*YHb+K=pQwo*F>gGuo9v4 zu?Z(PSDEc#{;pp1IrQ1{=tyrQWdryr+mDn33~@xKlDdh^7Wr3EUG`}LkizGas`cl9 zJmarw^0+L2^@vo9fHYa#{imPp_Rd-cCuaY=`{PyLoZ(>5KaJ}a_$hR&6f|)lB8u(` zL{U|FEc%zYYgP&B7w9W0*^*;1H4E-P6MZ!Dqb0w#twH!`k>N6qm0Qq#=u6wDiZv7N zHd$~#{U%L-_p*`y!?l=O@Si{GZ&j2#P|~U*$lxt_$QhDbD4CqHQMw0!6^rA`%Fubk ztgU{XpOkgEKf|+VUZP2pQ85uywBT;;Ppwc+iC0reBalae8X2*#b;dv+!U7?Z^ zFN_rht}DqiPIj2URxaxP5lE9)1r869MYNkgwLyiQyq3PolW=j-UE3eMsDh74ZU4~T z(hyxiO#rlf+^Q*{NU{k+Y8 zO~gD|fTE~Zw(hzbpFoz5cx21*hr>g|^SVF%Xe)tk6-Sd02@qr$ zzMqJB%FE}IBI%W{!g?w^t6=1jqBG2{72?L+`0n1|2h$5=ueBBoyhBSne;mXxI77DQ zzLVOs!l%BFQ%11)IqC%_<3RDLhOc!!#DNsh3O%eJMW`(UBXR$*DIYp zL$z=>n^leG9>DA`g4H`{G?ylcZ9E<~KeT%>z2K_WDN|DkkJf%(VL#+4IlFixnsH!~ z;3Cv3o2P5!q!vJOi<=7gt9pdt*VYAc0^|IS2GCGBp!&Wy04OzCG)t5YmH3J%H=mM> zfa@jwv23xKZ;=&z7(l7X$howmNtvIr_Q;<%c)E_U61etTiPiI*ev#+*WHdO3Id1?^ zU1n4~xm&4zPc}%d`7hCzqb(vAw$x}B1Vcf4n048q$?sl2qzJYo_?o1hBx?T%BYQ8)a1CV_?VYN{MrNU`9J~! z(o$ukW-E{#Cz{q@dAV4wZ32#kBVX11gXj`tcet%d0rxaH{z2`RNmvqJ8%yL*$gO?d z(Q=)(>Kj|Ma6)Mk&`pcLuFp5qxZ4gK>g9{CF*#l|wgLI=kZ#K*e|=azZVzZn<=BGd zklFrk!}bXsfzLzwapjoIiypTYu7S$nH=8tRqW0qx@23uC|6J~Dm>2gvP%%KAve6Uk zT0|swT9%J~<4;3mq$*YmkD$$`w%VLt`#O#9TX!(4-RQJ-} zfVKcc^(vd^HJP(JRo04r?M5b4nNyhjWnR3fe1nZfVmz(3izZ>oM$|_^=Y22kFj?#N zN7Pph*8tUQJFqYe`qON%a0;FTxoR!+hBI}~C!8I%BxaJI?w zA6Od@5Q+{8x@lW&+6f7R7wbjd8tn)}>ZH)R2sbD6*wOEhmj67sMzI-~Xf%mpd`3Xj zMC5K)7RC3q{$C+H(_CR#?u_pk@w*ooZ1pGmXCWCY_C?{(F0 zoYvT^ZdKWfrpO5X%g=Lp@2*$cp^Y`L7CDmEOS*p>d$Ab3IKF&PWF4hc(dYs5oC{B= z)ei&OP)g~+fZoGRULl%FnIOC#?L>=mRt6vfaqOkPczE|_Wz=6#1*pu$z4ZLwR(KS` zl8eX>BU@1ZqQTx~%?*bgVrq)qcbcP{PT>Rl`F&-yg*BNMBd7MQt$k1!nveu_NpQ`< zk`FGMUjGDdC+sw*{(Xu~h)3&-2+TYg-1budVTtdZhlUHoqKcN2JuPE>l6qUk4m%9} zS%mgB*Erg`o@tpD>(^ZE08OFoOoeXpCEYIsOo|#jg{tG{y)5GDwDv&L|4YqZ6SbR> z+TW5JN2L6|pvkp|7Jn8Yao{_QH51ZOa`Zk1_I|#pD6cA``12zDd z6`NV4d(J|^S%!t?XI_hpO-2qJ<;;xZ1;#{zQ*z?#Zby#3dPwXTK2pE+<|v*9{q!y^ zjf!9?h?Njceff10%>m(}()pvVM2@CF@}ii54ZLx^6`%=x!$15NTTDhzj+h-AvLAX> ztSf8**qIT#mI2beABFCD=IBWoxQwkHNcXO^ z%$KlYUp1v!%P`*YGlcd6DE462?3=1Jp6>kFzQXJT26v(eef0*4E<;-3cfAp*^)EC= zY}0<|>@~OD(A^aazZU&s{_xiHmrE#!OIEJn`^}i&3e%%-5(B_v2x{Y8(u8W5rX(5V#=a2$KH zBPFiQ_+Bl6zkSEmyT;Miys^3X7&WE(W^nh$OVy!JtAs=PET$nuTN# zsvNW3#Y8@A*4i|Njy?VVL)87oUe|dq=M?3~J@}e5eRp3zWw{hcdy<2rfoHy+oB97L zH*1iyBRsB+g-Bs<6-l_?5WfP~z0Tm5E=|8C_v=}#TWR$^p#j20TDEatib1J)@MdlVozqBl&tX5hE_GVk{>6nw?PlflE_i)gH=XSD zxDM*h>Fs9pk+<20?c$;eJsQjo#^+`?JH|ENl5U_}JIiP!a1)lulK=E8t$u*u=F0dz z>#r(SsLlZO1y{8LO5Rc`dZ^29v9~&RDBN`#Tn!Gy(}5bk{t_oHix+?W79Rr|-khsB zNPDtf$K;9{nV&b$Ym#YYT4&#rN zJL|j-b~vzq&d3aIoU@M^T`V`Epi@gVhnfM6R5Ev{$zC<<12`Vu1Hxmzz>`${)ba)FR_g~)x&knU1S#O7!BNJ&8i}2_td8RzQ z+ZA7Q7w1pQP|GkVYy4z6t!X!u^;Oeu7FR{M-fMgA+b1&@^7A6Xsa|8NUI~IL;81KA z8_?)P{da>BUl+lqk}$jEI{MSw-CMMdcvPS$7?%DK6gh?=Y|EH6OXS`ed0T>w?4iA= zsQ+}q%KyA=6Z=!H3$Ef)vh&Vfg^wi4BiPXolmgAmL6HYszW{0A?JuAHnDKG_t)T$o#DW2`6`+5mSixIgZY)Ch4#kpX_euOqpNT|_H zRK*9%MPMNXTgI9df5cZ#O8=<+3%F-TNFj2}i^Q>KfLm(=lK_dAdP-r6v)i#awNqh|CVA}|+S7~4D$Q)1^ubxh;$X2lebvhrV zPSGMX&A^Gl6y@B8$5&VhYww+X4!Ef5#1{$dZ3LUze9ItCr#Qp)m~~7yze9?Uf2O1QvP$Ahf#B5?Uu6;FQyoL7zq_V_zA_Taj>a!*-3N z3TE?I?vtsPDgYq88QXwySvFQN{W64;UNJBMX#fNRNWPXO+h%HX8V9@p%^^}m7ae6C zvZ~jWnTg_g%a`R$@iEN<-rzRk7c^J?;1#1`^G|`ks$S11iSpP|1O#qmrAEV>~;=$` z^#CI3!6Suj!Pn_*+1m;J?}?OEUz1v9Q$9c?5q_bxYG38yr{v|wkw)_`>K=AC`tou> zXG8EY`B(2^A6;w)3##HnMUs=#0hti*|Q)5V&XW&i06 z{14p$5?^nuy)yD9O?|L*9R$<|DKn%3?^%O#>RU=c8)ly^x4$UsSElOX$aKU`pX@iv z+&7jQUzqgC5#vEaT{AY_yP}UiWwS;iJue~(^x6e9GkKg7>fV8#)=s^HX?@pdtqA9U zh<{NmZzTE(+QRI(2_TwkQbvDCzEeH$Ej6jkd%|5AM9Qdd$jNI(#BXafoE7b!%7yEC z+7)Rq(n$oVyE&;v*}0XjrLDp@=1+XGNY8Y__L$5! zVUi2IXMM`2UD@=38Pr2$J1{zc8(fO3>V;2?g?!+Xt2vbI?9`8L35V#!xZVuXjNqU* z&t>IZG}UeRd!{S&;{R4tEqXEK{@zTdfJw0)yM$)uA2YRq-a%lKaH%(A|17>W*e>V+ zXp4nr2Qej*0?MeHGuUZwDev(8MShhF(y~1_SAF?hU33caHG8^11`1l%#fKs{G($O} zzvcBC2^t;G?hx&mMD(H$6%;-SMM&{=D|sOr*^ffm*;CIb*j=V{%{T1oYqPp~OV&YW zL2W8T+R2ya@gHY%WR(;+r>klnu2u42y$?h@n)88D6IU89$30lL+(L=YAbr&o>#g3L z)itn1LdD2e_;I_fm#&ryZ2?}or*u=jb)yw&140o6ygVo2a4U1L=)uOoWsh&`5S5x6 zyt-^%x$uWeB%+MHzm5SB>MO02-PPM>pXqrc6`ea8p~ly3bj~Z{MS+X zdfG4A6;KLg$^Me^(ZYI#L_OJi`Q;I{6HrH#GNL6G45LkGfvrfBtB zq+ME}nVL&Lam&@5E!no^FyLYB*H*R0sqIE9zPhH0w8$VDNTNf^zlk3G&dY0|;}oV$ z$`iu=*e9jG%jZ34Y2gd5r}0lq!~1F7{16dT6K|9q%x*m|t2oVl<%W8r#gxzogdi8p zdo>3}t{5#(_urM#-ok<fHlw~ifF2k zU`dqijm@={_eLBK^xul;e+Aj^cpZ=J0#VWw&P=j+YOu!(?Kmy~3R%B;L@oQyOIJ;a zW(~Kg{h7CiyZM`zJ*DYzS7JVnKdZ0=!D{sU!z{y0HB%~tY%Wm6gkY9DYy2S_RAT$F zu2BneE4^et%h-Qv=##aERMo=XTI;E2EFbq;C1d+;(F@~)?-l`8`jRgDfZ~`MFDO`o zWMe+pFoaYj!^u<1r@BXXc;EP&QJj;Xv@7hbzenv_zcN@@0tC-$&_V7Q(wd(r%JXa-my*g*soOoy=_Lir|X%OvixQ^cPlo(WK!}Vk> zxI$GRXJwz`1voC+0-@KUGouhEmatGb_?UwF*AN!1pzxnD{L#t)PUn0;CBl5IS1i3% z>g(tzM9dx^GAf7|8}0Yhb5o+rQ?PP|5r0eSyf!HbOc6|HQtxjXYoUVd)c!I;^6ayt zx%x87Sz7;+kGChD=!+fq@(6nq&MESg@K-#@3S|449*#y~55oC;Q<34L(vh6>7#+oxkc{QlhGPN{uUqmMcciOwh8?MhUtGsK>dlzeA0*~8$Oj-Anj z?Q@4ORUJw_5+TCeaXjmM1o>{4ltq{!lp9tA+r5SV<*z%IMujsC2b{3wh7-Y(;khPB zECxL6#=|ei))bs!qTVd|Dzf%EybBX{sJpfFg3A-Qj0c^9m)N}cg%gWYBkAO#sn|Ln zj~OL9;%7$jl>YBT^Q=amY5kxJS#>#)<=+yOk_@Hv1sV#r=3`XMtc|JIJ8A1~aqZDz zjCV$5KCT3BSySJ5|3=D3OgGB|NFUW3QKDuW0Zo-YJQ`Oi!JclW!*RH|Mug$zY9pn1QQ-ZY9kZ5=nfOZ}AzQk*KX5=D!gWvUt|i1~LkS4i z>-S{bq(n*^3+)Gz$2cn>kmjFHU%?xnz(gsV))e4M#_;$+OaxY-fr4`?su$wwh53o2 zO3@|oF=y4o&ReqXee`_BxA=W`1ngheuzrf2(`N5N`d z4XAI9U-}YvYg8}E9V_=ip&O67jB&+4+{Rlh!m`RCRqJKJ!UMee1C`WK6 z+zyW3HxH~cU19qLZEF60%frzsj#f}jX`Z&YwdDVUkBdhwS$r7Y%Lzs4k-e?riBrRJ zo>&kG@3SnpJ2CvHC)T=5VY_9vI)`M516YZ(sjIK&k}OrBRlyDfS33*=h;cd|Z;x?Y z;_ph7zHrczbOmE52g2R&khi>Xn!Cz!(*~_G?5ozTaNs>-%6frA)z*u0^bBX0uHXgi zju8sz=x%(9GbVc-DZ;V!gIB@O)UXl}t3jtR@vLc?ymJZXBO;TV#4W-w7%5XyskGPm zjwzVT!#pQZMuYn3Pc&0HVVX!+$j4`kgGJ6RtyI~dkcrLFZ3O5-EQBIf@&{nKO)|wW zrK=V`z)I`G+)|)b9Gz=NBqFX{*;38ZAR5%EIKeXp5D{Bj_K>N6d3ou|Mq#DQLl&$Z8b95Qtvx5J&km^rBX&+|# zAg9)%HU2)r9mU;&Z4CJjL`8BM2)ZG!On0xF43DsY`OD82eI zxs4^`H~}xsrp}ki(kz+HZeWZ!3lL8BkwUi6W3I*7R)pJ~A~rpG4SH6}w~6>^PvXwW zgc?}4Q4z)(G6Id1d`PpKuY)6D9n^4B?noa9XxsOBW~n7uoMZvfiNEDZJiYcVw#cCZ zFe~eOfLX~Ey{vv05av3E(&+oPR=aYZ z2v~*2{{_ggZNMV+55~01|5&IKqgj+=$Z~I5Zg$H%SL!@SSIlQem`>)7IDmRJ;el@tW<5k-UXQeY4+Kya$nZ)2|oI>Qwl^779E$b^oT*>1-0w)fMA2xrd&y zoxSz>MYLL(xJciYa5MD?D%dseoR8Q&<;7?=R?C&g5pIt~+1LL=yTG+edQ+TdsRA&A zJT{FXJfEEI&1oASh(|8fLrOF<|5C1C2H{vV0Mo_~TzSvmiI=bieP-KtdRpxIOyHVwK%?q9Ve>y?O8L?sZ#$19 z9Im=oZZvC;pr2?9Zplt1FV&NEM`Cid;XoayE<}RLnR6$u(r`mB*AI9p)Txlp3xg$D z0xC_wG)(v9kAMkXF@M^K3RWw1VQ%fX)y;dfl`oM@?J!yMDpj%68omtj$8k;iT<-0JE1?WPL+f4$2(^W(E zF?>_ojTUv=18CN&*#qNP;Wgb?0Wiqn7t#d8LsU~frfL~)lEsZjtjSgG>wcBgu8y?! zbBnqu0kjueYShnhjFqw9y3}1&3eDFX(XQcd|263&zn%r$y7a@tWW%pl@ZLav7`aOoV>^?CCwApnv@AI*djb&WvuAw3voFnAA zPb?LU|FeSQ)bCswJ08mPto z#PTldh6gA}sqy3sN0{>YeEQWrmMxl`AZ+-gifF1J6`a6%#4ovVl<&M`y=3u_YQ!NC zo`-zlHF=NUsY>N%+)@`5;Wo}4v7wioJz(T0>2Y9UNJC3XVd2=Ny~_6|-f%tLkGHWhJv?Ci`1(8H+4ShE4dD+sy|;g~fnXdf zb2D12BD{?YkqHw`zUJs4r}O@(Nzf6`4C$_=KVBdjm%LL&3emp!S@sZ|P5m4$%|*oc zApUkv(~60n_6tx5QZpVC=1q#8PV`rBP|GGv#T;95Z{47*DmeUNK`>vkJdkRs#>Q}0 z(N|Oj&!=g5!8*u^Dx9Wsk_)ZC4laL|h=y9+zI4izsq-uCk{~lS`mY*1x@q4;m4cdD zb`BRiy>6K=9l9%wNJE0vVb^oFLBU7$a}#v!Tca^%_a<_0fya-pR78q_N#sBQD*i}(=MI)v76s7SnUz&`h}=4 zl|mYV5t(r-&#(EygAmx%nzUHIaNg+UpoO{x08i|pe)g{|55|{+WH1a~^&Q_4x1Md< z9DZ#!3x=5%fdJEY#T8)v8oMoI+y6fLJ?lCUmxi0BkQsIR0|aLe&fb_oyg_%JS?Rt4 zAn*(C@g=KoJ^iMeZL2HRt`pL%kb$ma8)4;JYPH&F1#l7_KK7De8pTZ=QnL&UOuGVbDhkC}UTB`4xPZfK2`#uDmY$ zuk!c38$%dtw%@(!;4&C&3_n#o;+PGp3;g`SnM=Yb=rN)F}b1N3k&ot&E5VmR98~v{H;wDYgaXJ z;Z;BketW;4dYERh>o?fP?R;MeHnH@5`g4_&(9)s56}Bu@Egs5@1Wo-1rc{yzgVOU6 z_kC&iAmUn3J^AzIcdvgg3uHcn=ZG8mDgktiC*DV^MUyTr&+2ebifyK63xHbudVHjA z;@Eyf_?nt>Xr}5Nb*pCSBOiw0BP+ZBctC4AQS(DvrI$_er8Ts$Ng!MF3FYF(vk*w% z3dUEhJe7;9hTzm%8E6lAunNrXy>bc5CqcuGQ!jd1A<{7Qa$V8*9dqLV z5zYH;e#?lbH1+Ihx4H++6t>GCkR0p~0KZtAGQP!+QQJz89Uq6p zvhjUG+tPDD!!r4$#_JA`s=4~IUULJoW%7Ly$b5?oB)JJ}J_O5NL|FDol{|2k{V3k{ z9}%|{X^qjyfA8e!B01^$t5VxsAw^}&x8VnP2BiC`V7D}+dE4z}*~$D;bZ`<8KQFt9 zD0FrIGXtX=9OzVOyzlcbfjRD{=L080vmPy^0bmSYWDFc+C&#za=XW9Eoez#N{YCC> z=A?m5=1cI8Qa49D=h6$ez9c_a8qvc59uoi^!n7q2t5QPijD=_GM2t#_d)}l^MAoCb zuOZEW?{VvC0NPV8H!gv(9hSA6zWXp_a#qR%+BdmPZ6BXA-5;K-t|y* zp9RuwBR>TZYxi-ta>uI0b|iT&LH;3;fAp2boU`l ziLQVJX#HKrz5Yo(8D)oaIKP(N1raUV%n$K$MeZPPt6a#@l7(>6_zKuo*?xVP!xoEk z9{O#0>4T*}o9wo1;k{X9(a77Y5Oxt#-bE(1!5v(I7;OH=%0}(F!SM_$Atc$F5#&)q5@J85Pb3u3d;q7ix z-7TI9rSE)Tp_3_ATB3cnzb4lO%fCqY3iDrC0yl#Kf@gk)(_Z^xFg1ga(+kBMnY?Bs z8$plcu*q8Ut-Qfz{NWOVF7~)&q0z+xfDGaM7+p{k7J#79Hov2B-`zM%RcZOR7Z}Ya zW9}dTOvDUGm$B$|L)_h$09RR!e>uhpU6wYb`a8I4<~Vno0rVuCm(vc&$A;74tx(&)fhkhnl*^d-*OZ=E9#$s`7mpq{AQjJnG0w+%(TkW1m^2L zNT(L$*pJy3HufjRk(-b7tKGZz1Ohfb{F2ERVwz8i-Wl6psAq6Pu@3Ynr=A5Cc@WLS z1>dHac0v}jyVZV3^j`CpNs8k0LymF6g>XX-e#~XuzK-}TXKsC2%7VZ>-^fqB z?Po{wmj|a>5)7lX{zas_R~+I_6nW&mStdg=KtTERSp#_fF08hk%y1j)hp>(9Z3D{( zIioZ<_N1K?qG9HZyHISH%ZdfHF%p0qlfB4mad*<(T>N}4==C>8(+>{W-%MM#aRUNN zwah`ke0tZk3S`}W>bLQ4<2=t;uTv9%kv&Q=JF0kLX*IqlWy}1PZeTwA>6$Apr7)vE%V4eV)8;G!8UH+s2}(Zy_9<=v zNp%?0Y+7|A?=B|%>O~j0;Me3PERHUh8_3;q!H=y~a2hIMK-)OQD6iRc#Vydq+k1_} zze?CSjl3?+$SdR<`_wqvvYmMkWTOUiUq7w7;VzeAqk3sPt|&)2OpwJe4YGTc{L~V) zpk%B)lq};nBvIi$ab8?^`-CNsF(m|5 zHhRESaF2ZV{bIriHoSR0rT>^I+3-}0IdXQ2ChSTg%DIMGOy2J$Nx2y7$n!q52rUA? z(X=GNJ?hNmhm^r>kTS7-Shn9$SUlo%X}eiTMrM|QoR^CrO#K>~z@+I|(|m>}?$E0B zzOyWPc<>3aSy%k?4a<))p5&l_qsy%_7iubCi2p|zgUQ+&NE>b*Y5DZji+uJ2;dUSO zy({}hDcU-D^wU$~WV|hbTtFiz_Mt7D@rLry3Cj^%wf;J{ z_ur8biH>_CD>U&e|9}&DMvc$l#0=i|-;wbIg%#_eopX&~uffdtb9}+msiF86?zp5< zEUAYk{3}x1-Ixu0XY^GT5^MU#>b)jS;;fu+fa zl=Yy*duQZg+xl#ihdxmVNH8XQQNCN%}spnkuMd!rdw>AsVy60{8bl z_v{ngFM4(-ml98~k4LKxt-sbem;Bf};Tdv7hBX|KrLF!}cG@g@*j&9IY>vh1EhmSV zi|z?`N{Ff(KmJrxG23wT8XNvH$vC_mMlY{pQj~A2pEoQ`Rbnksb<3w!*@|kjte4(V z(dCC~C?g}7GZx$x8ZHn%u2enRrG3~EkDf}WpPNPP@!@^AMez_=ReP$!9T1*m8k-!p z=<`s7lT^7gV_^orw)Fz8ItPw$?UkiC23zsJnTVsyI}FOhGAWuvy_+jpyCEeJ74RQT zcovo9?HXDhn@qtCr2cu=Xn&dHbGEqAcfmaaOI)y!*&bel$kT8uyB>XDM67sYrI~Ogi4dl>N$8|1|{MX6)oZ|)*tMbrD(D=b#P*7dG%BcAEBd7#Z9zzuG{_VPg(^b5AZ?liS?Be{cZ(@gj#}gfGVB_0Sh)PzQW4LG#AO z0XC4@p@ljF*9p)_SH;d?zWQ-DN+n&{Wc`_lXm5s&a(E42@4=>G?H`{HDvRC|c2{L* zM9s2yEZg2G4{N0)5B8E**KH;}dhPCVkf%q2Mm)$S^UM}lyKyCGlDqrF*)xKBmeKM7 ztUODNapvMXk)&{D8#osnR>Jf7NbOUWuLf~zD%v@rA`Z4K<CPt5c%ESo~|RV#f^s8IQPLlhUEo69uv$SjLEDJX&DDp{Xkl(ftN%)c`DO1K*#u z2>UD`VEJHvAm;V0gyxuC^3|G0`l?sIKZ_^0|58Rx2Ico4MwPlRlz^KWYw^0efO>ZC z<;fIf(oB%s!;_)g+2Abi_EdCpaqz7-+FHq0xv%<u$TjE7+_(=ExE+kIk;q63wMX zA$Ctx-Pz6DVY6r7CLl>{%O2?Rq?Zc1Ryd_23auY*`{F@i&&G#9yRY!SZGg`2!^i(= ziE$WycG3q7k8Oz9w;H3w35HX*L4$^oHPvbP14ea=i5cf?f zl7M`OSgT}vup1nVbpt(h^OO`!g$i;f2hVy@XJ2W0bX3zP6H218E<4TSER$dMnh8U#mUT^WCo)RqMctI472_tVdKecVqe8}AxHOz(TbA9La7U^EN9 zRGa0Rc`6zDOZuvet=bBL)dh%%i#z1wEP7*Z%;MZ2>Ped!jV_-@>{JkXI$|)>Rfr}u;;_6nRqr3@xU@r%knke8bHVt57;L}7MeIX1duDgE&c z*A?O|y-UjU7Zhx(q10)~h60naTE_e7*gOvp0cAVMc0hBn2B##u@=V047}itzH@^=2 zCM;gCcN);9#MRes3d@-$Zx2mFO!QObp>C#EXGwR;3zqnNr)hqjH{l@0CHGnQcF*|E5g< zCd{E<8P(&l`}9CzT6)wM0#%=@$Mru#&Or6J3&hLjqz0cXK$1ooZ%M`=Vo7qFa$jHKIX#|C002q3&At5FID#z#5E1MW;|1SHQl zCZfmmE#z`K-U7StVXWF1B5~FC)EiV#{F{>fY9hAN+vBv7 zi3Kw;b}ZJ#5blu4lWOQ>{rkkm{ugj=16SO&05N&CiL~nBfoUMtkjDnP5E7`ZD&NNf zozs_{O3fCSh}}aV94#B&JDG6ng>ez4`eGF^$G!3tkV^X((q|arW*pR?S8clC1jPJi zy?y9D4HDYVj4tZ&dtu8zfEjRs^b}$Y{E-ec5U{4JrW<7H|GO-^5o`tz8puwuO*Gg= zlEGlq5^TdFN0{Q}@d*9&crRT%WJ$6^J_i@v$QE(0fnl17+wQJJTun>8-x!JHLBMWt z&6eD-z(`!9xOLw!$s^;_6P%pAWr`_AN?w2)hfAuc7a!9bG#&VhDQ)T`mGgZMH%|KS z=eQ$JC)XQ9Iiwjq0r>dqWCb^2LG%E7a)VP+K)>OvyP21vp}cb+F8N@H$= z_~OK{k_lh47bo}0y-qIYV7BP?gsCs$`$mWN6El2XCZ|HRVMEy93ip3X)p%6x9Vx;DmxTLoj#~T9S z&%fVBtR&Sgs9KU5FuZ5x10$~FX=w%7K|TjB(9XQ}cCU=fQMf%{>Iq!EnH?h1Cfe>h zw~)6FrkhD5u<5pK$i5Lv#MVB>)f4a#&|@|MGjS3SFAmiRGIl-N`6Xw(z{r_cvjzf} zv_gQ>VAvP*;aEOdPc$Ex41XNi68HBIa#Np`Dr|>oWBcPN+*@xf2Z6kdM;M-yz;%Nm z>B9I=4D+I?%?s&>YVn8dz=6emR<49?ycq#~u`(Skg9vD~a8*S>n|ZFU11IO% zg^AdX(CEd-co4!3(}-AbkDkSoHXsCO>XfwAcm}6H3$iogblIf*Xe&V*%w3dX9iFEI z)BPWj_!x1{{iTenZV1l$^;|lU6$eag%?0dW#nXYZt)&w#uA~$Ak-ur%ac@?lMN%EY z5jh^XZ)FHTB&wZKa*clb@6;E{>E3u-A`t;(ApH|7Q>+UF%Xj{4>m2Z!5al3dvYjt2 zl34KYY!Oik-;EiHc{G*Y zaRVhKDwofvr~j(3Qb7lzc?Gd8edNos?1jKSRyHUt5t0n7_74t+M$D3kRt~9^(VpUf zhVu+4Pubv~fPm_RT%;tirxwFZgec}?2SCrusF4eQj{F#ecpY2N#x+}9KK!{wO(Aqs zyt_N`FXeo(m8itA}9Hc8L|nIEA*|h z5I5Rb-J1xhMV)kIO8baiv+(GEo{GOhAQI^rhY(|4t@i${-~ZDk0+mIgH@X$)z?b=b z7c6cz;xgQCu2OdWo7_b4H=9NO=RF*yeBj%bx9@y`zt%3*T>$6U zJ3q^%v`3LXFnz6lNVIJW%u}t38ZXJ82dd@mgLEh zh9jhHEq_gD9{A~9*En2b>+9|Yi9SQm9VQHgi8!}1x_pHY{jS^CDwfm?iI8tZ0^&z`0L^>spM>n-oju^T!bmX~jloxmQp%z`4*I-DA(K@qZ zdJR^yHw%)Fc2cO{4ZlAf$d(^B+~JKo@j)@9kMz;i@RpC*I}6meW}az7ORsr}h6V%D zMDrg=rex&oVHJF$xBpqsB8pkNIi1Q6zW~Fc*g2Q*0+N(kwLQ!OwNcP^Vp@gh+jATV5*~dDF%BGC$ z!?E|y&Z^(*?f(3}f8E_@UDx%#F6UhD_w)IDJQdr9s&*G}3F}~-urytk^at*J=#+?I54aC4u9!b=#AHLsz3-Erf@y z+c9~i+>nm@gHq&1DXY@@TU`A7^c!VZTn|B_h>PEwKDvTlA!X&QD=gdY-f^7!3vJ_-k3re zid-F`Nor=@rtHTbu%t@|KvEhbrXM9rq%tkA=P(ZrPh&v<&MFn`K%jwfv6gB$c zqpam1(=_=~@M-(xsWMY8wM5%H`YR1N4r+;^DJ>vno|;}6Ufrx`t>w;+3ti0u(e#x4 z+0lD5HhZ7Gc90QtP{y7rg=HMo zdcAfzcSvX`CfA=Zaw>dc_-2poVfbxiL*t7fN>diO_z%LUE~4_y^WQ+~E$bn4EQLqx z*q!ynAkkdrEbsVR!$h&~^efMUmPPsMh@qmw`VnM+3gh2g98 zta8hii+yQYk(SN^+opTKOoCsO`f`I}@<7$CMI5IdcOb$wy)v`381;zz#Q9llMw%`O zREFWHqrWU4vAJ&?Fl6nFhQ)uL{5hcj3{kEfQwkF5?WC10DWDNk{$k_Z@N_oVS+N3! z?!Q+xM{`)N?jO07$i}8J_+JVaB}aK^e&6`M{cf#&?Z;!1EhrCM!gH=rRSE_YX7|9n z#ytfzt`HPMZqGDUPzC+Pb9=X6{I>Ic-MOcGKHxqvVKxhsK$>cw#@N8Z+4kgl_@AdT zD5{$L59Y?bMbT+pr@)8)+VJj8#-Lx#m+A?pbH8uTe-diUaj>$6CH5ruhvN4oeD0s! zPOqdD^m*L#(R~U8v|Ef4L(p3ak=bOhBM!gmhgQ^(a&Ifpd-?VDTa}~zO|Z)}kX?te+Nltv+kle^osF$kBT{FjyC123q&1|6s;HFH2?{Dp-7F7p8 z&QJ#%qt?z*+?X45Yf1%N-}*OYa&(FL*Hk%7pKctqy8Fk1K`LQ&rBV)Cu(*4+7mSBB z$Getj*t@pD`FFAOyjA(&7s#kGKt@#_7npr~MZrh*-o9;q_-rJ-X_vaMgwml1_)*eC`B zh!eI*anv-H@Z3P^^5k_m5jwdhPw&rf!El3*Crs8kW9;PDyX*O~U{&C~de0|;M>O#z zUd(9gc?uv4SK>i*wddJ{ZJ+yFZ(#9{^9AXKkSDMcE4-}X&36r-?MOe#nx}s;vBWGt zyX#`eY8rO`@vMLC-E~7aMYT*U1&N!GQVwu}It=6l($_{>b;R8;|MF??MVLNm?|Yw$ z;Lw}Y^dl=iPl1ASY?(>OU+AvafO@NME=*>1JO8L3i{; zfIgg4k>Brv#7m=%HMraQOyurKd&Yi0Rw}_YadiGx)kAO z94=I3#|jJPKV6ip4aG79H56H!E!K8N?-nU3YKcV&X3wJQ!ReZBZ;R$ETptl99#R{a zEh?_1Nq!}qzCYyOXmZo>te(CAVrExhHuUgEg|cPA+aTqHu@VH`)Rhdn>AUxGJoaY8 zz2MUh@Y-yIH5MouF&fbrd-v7Aih5UdF|=!~A;K$r1*z!D#-<*Swo3XliK;V0@tC(k zCWXL6_TOxaj-YCKzMq2s%f@~_T5&kD2($JS ze|%s8GU5raYREm2KRdd~Q)33NQhH%PdMiks6NPy+h$?e|!z~`Q*A%4Fs<{rj6)8xN zn!qw`2ViC15+lUQD0h~k(T{D1YcWrqtpKx64{y0135^lJ5Z>F}|tyL7ma9;Z`I&%h`;HO&*u|!5XKJPNq@_5smoD+9+^;AmERTRex1;S)*IT%UHJV6Q4UtE`p40EOdG*7r*je zD8tuVqnI_Tp8g_?2-vNcbVxx>+s7r|477ZAzV#4eR!AQyP3ib~qepu5>ccF)LnL0O z5(I=-hdH%AXpSSJl129%wqVU9Hd*)m_D|cBcrkIeNZDVnBq$574S-xA zSyTAPcbSYciJMkH#8ocQfm9?keTLlRcHv(@9SsMFEmq?N9RT#IOg)kb>MGg4&;hi! z59r_K$3ZW?QzU?5p=7@TBphaBa=2>oQ_f&x@8Fvn8y>1|74U87F*Rpt=xalx)#Uby z@ywvEsrp2t^@pAW`K+}Bdj(xnGjikCsri^K?+Z_)ylce-vxo;Q#sdrZ*mVh@CflJb zuSrlOVzY!|ffSbJCkT!Un8{$QbW-1D!4}Cp1rBxT+?oqwa7=zG<#$V(Gx5i?=q}jO zd=h$}!%J=`a){R<9L&;4M8&CdqPn2lrsK>aRj-0T>hTEaw|=Nhb=YkD=*loTvgF&z zhmo{$0;17(T!u11G&MPas#l$tvNWE-Cpa?XQ5J94YRZj#K?g~DH={ZHK&SRmR36cT%@hB?w(^zt>xk!MQWp(qc^gEW zY=*7ws-mr4t7&X9jl7xXV5p<%+kOUc&J#qwOzr-@A@~|k59hcSxr?-2#Mw@JA0sT> zlnIBnAhz2D++IJTL%e(6_-wLwBcK$G?;?%*7--aMF95flYMw#S*V>p^hriPMQ2-Bi zoEG)tzO~ot3f;UAtoDMdf?G#(wB^k1z41pxzB^ik(9AYPt%Xy24M3&ZysDY{(lRpg zMyJ7pLSu=LgO@P+=_-Os#gb#jhgB>%~Z-+^&CD5 z26UmY>^}uK);>s6wrvSFU(uTx>@~4%s09wt)DF-ppfA$oZSbX=kW~?WGbe~Ru>sdN zQ-3~In)!&^>V&sJT3dxyN^i!X53_5bA1;!v1f`&`m;lA_fDis4f>I`M23V2=%L^-b z*LpDVd)(cdkS#^8a(M&>iq?_y-{OWs@>3Hc1PkY^sAWaSQ@QpOa>{@$hpUMBFdNj} zj?@9YRs~atd(}f4g>@LF-_YCf;9S5Xl=Ix_5hGjS5{u;T?M0)m!>Yv%{^l!iyG{R+ z^vE2`e(0U*#n#&6k5rr%ffE?COfPFAr#DkVHrZ~iMT9#=+&%}@-tN7B!}sR9;AcM& z%vYqKVIxEoy;O9@700o?N;tzB?h`((%90*Fq4Ji9``AaKwT3b^(2{TQfa-j&AeDt6 zcwRt<^k|2f5s!B(c|y>^65c+C?%Yhg)tO-GViaD zmg6v;!w#*hu^iumBO8qNaTFD$sOvp#5S*ThdTFb2jD)+|2SH(?uoe6qOkgemtaRUt-xa6lEl~{FgPfvkP3aYxe#2f|qB%iI8oYQ7|6gr8pN)JSZLvNIzj7uuhV6;QERMX8(rl}leo76XQ!s8Vf_ zX*&QktGevBrqqZ8X_o|f_oR{%ZDu7{3xFSivW`?msCYDWmXhm|&Q*5hLqJ{8*o89r z4+bYX(l)P|3Oz^JOm8t7u4qQrfq$Q9zQcNuQ;Bnw*!2_%)Y9tly_vy6{pC^;(bkGy z@qIdl+01&ve#@XZQq$tU>W_Q5V}!OGbj}HCElRT zHYn@Jj<@U<@+^ZcThF#MgPHc`LQC~U@x|rH`FKlh>C4^O1{U4uu?Zq#4O`6v(-taj z=X85ZZa@hSy(2!^C;At4%SuD;2&$G;cT+EkO?ea@m+u(UYbx7}#)j6Kdm-_aHI&-6 z;ib(RgzlS6<`$~Z_QIzHNXlfk05+4ioLHWwmSj*_-wbJchUw!G$4HL*wsWWa0lz4f zZxUL+*PV+EFNfR6b(4pl7xSgpZp`E8U8&6_VIQyc!ahd#7CO%NYSOn00Uf%xP{kW< zp{>;!YI;}i!N>{GTB3oW>fRd|=)~%-D@3)MSc(m&;skIY{qr2L5V3J~e;r&m|+$>3qP0CCHmZ+Y~rb(*2Q-UIomIDoH)!3v+GuE(>C| zEw!>Ln=8rH@$q{^*{7?@D?$OblOy2P-_Jw+J;BdhyTx{qAR60T?S({l^LWk8 zCkqO&IX$VO^ORT@GH0%%ZLjHIH;NGV-;q4@&Vcy6xyCH|Y`)_XIrZh7zLyK|@g3{P zP;uDzzz(F4ukh>$JiAGXu&eB6T^$<9S6LVF`xW78iV(asl(Om!x$~{{nDKWPNVJ?9 z1$06(5C>*BIxH}YdZTOBhyGbbU}}z|a*T~%p*z#f8PLOw3mk1i^dXY|Uh&%q6x>}x zpM6PjW_v5w*`9zl6XFOYQlJAbD~to3H~jJk-^+Fpuf~>b5X$#fWy8d1vK+(u`{h=5 zT_@79jT;YH%-+fwlfNFHQZmr+H%WVTsnvgTtjqqO1ZF>H+!MNnD~HV9o(gCQA2=oh z+F#t0kk#KCCy!6T-oZU#EAFj>(oJzVfVLNOHgf(21b9F4b|)ObpQjg+0X0_+3SWVT ze9ayhUC5SzYw;_CR2$f_+exG??;+8;^^ zqe{~BiaUs@0*gSHRCfJv)Vd0y->v#^t3{N%)s)&{b5)X&or~HPsl{GK zn+SEBogimijp)E5z)VihfHhPMWplt(G*Kyd^^?-h9xB=%aKf;1A&jx&jI#n%kim^X zPGAg&NP;&n{p9oMA!uwhd)7?gc0maT+Od8ud`isw9Z>xAGAu@qh>#7ez$4+?>vMTX2ykjQpFIRYk@dF3Zc4`O)floZ;B}ZHoBIPLMgmP2AqNBbI@MVzF z>l$w}zKP@5{MI`|^eArpp zPXct)^zqS%3L6JM2?Fc-EQDiCgBp-ndD*_vCI&*E{(ArVJf7OFgNGQ`QInKfu)ji? zZ6Tx?Z+x&*CX2yG;40O~R*>@CO5MGkH2MN)|64Db{Vu1;C&9K5BGy^}0-}2oMfk}& z^Xa`n?A~|s4gPE;v*p()CCs=Mhxb6C+z2-U#Ae?FsNu|z=(eY9qD|cfVQx({j@vVR zl@AiKdAgZ`UewVGexWB+n>(3Rl*5XbRK4MY!!=$g7VHyodW3+m?T$WL_BEJed;hd3Q!zdb_?!I`wmw-)ndI3mFXwovxxkFMX2 zHB_!u5lklm1?Ot$^9>k*W!&90t6A~7L26_+7YAEt2K}_Vyg?P6?lB43U5)o@aNsk4 z#8a8$<1*Cv`O$&%^r6d$Q*19}-R{2$G^f)zNLTNLjvMIJa4InDD0B@+*8!sc4BXs% z8VJh{Q-5eS!KNK>puA8c2fv&a1fPIU)H?<7{GK9>fqK7_i{TlhM zt5GQ=q#2#^6iBj>Q{(soCn*0+nbFq|&rUhJ+ZDiM;~J1?M{aZi5f|U7KRv&q^0WuF zftFtay-r|_sLyyCB-v<_w?UU$A)bI{f3oY;9H^S*H2ql!X|L?MUx*e!{4)Un{n#!X zS5Njc926aB!jAASz-I1>m3PQyUK~z#`VdryZV=Ugw7949Mg1 zI!}z`I^*7z0WTQ$Tafx+AQuZV>~C!2F~k^s>Pm{*i-y)fQUI z4=wlpLK5v{2Z-5Thp9(j*&r)H*8qvf1x~5&->P`j0Jj-G;Do@r<@&_JsS&VI=mA^u zHW3DuS5j3dTPd0<5+zfQPoXsG5DC(#0iD?$N1bt6WuQ^xoQ2Z&u|k{eW<77`%t&Ad zIB3ePB*AfD(58mQr{ERn&yhXT^M<>2vm}Tb2Av(6C2WL(k`CaE&0zRqz*{)mE0m@* z8FIYJ?htX|ohi|XZi;;LbAAa*;o>KgRxWcJ>>qe~@^f~HivjL`NoF|a$$J(TO2$;C zP{*u9a}6}89&|?ys<-v@%Y3E}{`{^S=Yf0uiR5C?mJ3a>+9PoSCu@N}jjwhEbTky; zLd9)|``$packvp@RsjDP9|aI%ZI8hneEdz;jrVAh1l8Jj2S*qpOuPZWI6nerE3yoD z#*|ngep&z>L+JT`Z?iCk`^itfl-TT!&ui#gQ$2X~;R@>C-Eqa)d=j$~j%+wYVCsqV zIGod=>BP%WVp7~&b6|edYl*8ym;@Tlc%ue`ho`()FC@PB+DIDTIwK_(gwh>YwM)KP z;B2h5iRCH~gv^?Ul3`IG66qeHC#D!g&uNt%uFo5*!et9YYV+22$+ z8+F~)v8PmXuvPHn`~+IL8-CoAeta&9si7mXm?aT77SwE>+?<-whZ}49e5+>EM@wC96JRI` zh4QYv`VsfP)6S{|t3s?^w(ngaz$;YdOG{k((-kukL({JFM{P_itP zhDhRHprF@=+6UgNw|>8$(!1a%SZtDpUil`~#{2{fp^^XNh&vG597d6zu+G0*&hGK+J;PVbW|ucb?j=go{HLs^3=%U#$A&VpMV!(c#$43@()+(wtSqg9E?Mz%q28+J zEm>S|RvJ%@PYmPRfC4{d{iNG#nc{$R$6HC^0=dkE=tZNkOI4@b$A?klZot{xjZm|z zBagAd_oUknb2STuTIsoqc?2Ppdfu(nBtl0D*lul zD9)qeKq9$%|HaVTq5c_l|8uE9&-x~3HrHC-(9DvOtQ*Nginug1JhSAY2dD9?*mEiT zH7>Q2p|@Z9@2@*`XK47#lF~z0F*_-IIj7C>&}u_}ni_(9#sF^!13=IbNOt6W8dLP^ z{_uE7db6OC!_vUBhq~x^JB62z!+Z_xlict(rEndb4Fhy$L5jxZRToB3f9)$b#x6+> z66XS)x&?7d=vq_Vg=E7cuKtRQpQ`$Y!>JbSjDOixjpu(89>%3Cr9{2_tpyYezvUFs zSZ=5{WevpMZ}XoI7;l^!iCU_!&GOH$`P5+V?J)^AM&H~>rc%`PoaDL{yCFA5F{yOv zQ3O_AbHn^4#UaLJE=OPd3cL12YT5dyzh3RB*b`hK458H?{tv1N)kERg%XUe>Qp=!~ zPyC8^21(NEuF=--{Gf@2pGxK}J`9=t$Goaqw4kxh75FOjtEsBb1sV zLN#k3pfD437+tw+j;j-2DeBf%36A1|WkUz$GsICWn0 zcHCf8S;EZE4l}oD1IVGgZWoi|24Jx&@3B35EfuWhT%cDZU{BT(-dJxzdJjW(!yJ;* z*O19Px8SFLc`_2a)ObpKa`@9lTcVY#JE=q}y+73m)Z}zlxUPQR8rw_;r%Je?xetaL zuFr&y&h{Mm&M`DPdri>e_ejVJ)S0rqIarN&!K>}3@3)PfpSF}><4tU&v|biYVA;*B zAW3Imd~*&0v2yKRo41Ewyx(*f-142EVeMRuhN4%-e(o)Zyw=pru3S!#fnris!j$H7 zHa5@p?W_u+-|k#KH~o}&+&|{t0R0jA8#kBDETn9aQ7vHh3B=(-@ub8g$w_*cMKA%L z7H%IB&bfQ%9gZn@o$>n~d=qCYj_o`znel!C6GSc!EAM|{9pdr`LIX1;txP6*K-nQZ z=OmpGm=WxM?tx8(Ip5w3LmHlG1qg&OEwoMV-v^1GcmB7zp`Cl075oI?)4 z<*wBIAotxGdGvGVdHTX0OErUXs|AX2PdwFyxM~wtV^jbfTGSD1nmMuRV?k0DcgI1X z1-~Q1(NVKbI8-)R4rOaz-%Fj+1?$YiQ3BQ6OsrJcPwunNxjnmO9e!8dT}P@R z3J_gHc>$Dojmh>lsIjD3zZ}FteXbU@6UR7cGoZ)gd9V< zrviP`yK3i!xX-!w%NLj7GDttE$?&ZMq}|Q7bccfo&wMWX(loT>ve9hgz#&y&H^CH+d5DgXh?zfw3@Y1>L5~uaClS5P<=l@>Y<;m4*KiO~R{_MBe+=j2>nK#lK5WuRI6F$K~c|o(smnEWaN;;!_)698`Nt1FztHdgMNB_Qg1P z_lnkzwM}#9$R#(2MSWn0))A=uAu{`CE~YE(S(@H*BJar&07O$u-(U1!DV_SQBtXe! z30OD+Yr2vQ-E|NmDCy@4&&s3Rl|L(LbJgp{xcVWXM=F(3ygE%Aj-!D??t)p?kg2o> zG&R>d_X?*pX9gZS&A%pM&+HG&*Y*ABR-}AG7gSiBest^cUn@7kEG5?E^oQ}o+3eIg z%cBW4_)eB)iy#v`2#B9coOztaHu%g6Yn-i+%6{EAoA*LDPmBYIo}`IV7}Jihr$u&< zrR45XH-{}AZ5w7;FjjHM^8uKkLG3@-T;A|L#?m?;n?ix7W>2b#kmBT7vVgQH#$OL3 zDai2+EvX*RApHvm!5FR(SYLU-8dq6BN{G#Y^QQC(q{&@qyL;RUbxtyuD|gYKq}kQV zI$rV4jo+~E7D}_)ASU9vWrTVmw|DAq#qviXra_j8yKK-_qx7fwguM-9UzM)vfySAX zHw}DqK%=a}EEwwluK2m6%DxVTmZ!MqWj#D74_kzpyo=WqY_nzs2g`(t(dq2n*^I+n zM>T&x9RdN{Uk`>(Baubzo(j)*@Y&Mf4+;i+i5jyDa>|2`7-7qWYhUw0!{;cH3v|+V zC}9fy=sqSIXeofYd5ygrNaEbG9N)kZCtuN%1nRbnZpwK<{niR?_>S28zmdT|5@gI_ z5qboB@cG}=$3pt80OV{9|EIw2s%PIgx6pH%UdG;9nSbviB3gmH_lFz%IxGLS36BC{ zR}Vign3MrRw>A|$C;5B14I66}syK&=#=mW-z2#7L6GreS)Nf|t zOSGCTGML|k{P{*c!{~_2cb`XIuPup5^s|m;`3_ooOhOrq)mk>z++D1$l|oQV8TnT+ zXsfBeGWA=#QnoGjY29ILY|OG&UC8AN(lw>&KpmNY@6|$b9;Ifhtn!`wNJ-;;OVz(} z8(mUSx#&r2$k)DaPPxOF-Dqwe8LtiWVwgwBuH*VT<$r(daEX*`KI8mwTq2+E2b2Jz zDY!6aq2Jm^r^v|B=1)vGFD?EwVC>QdMKyfkG>a4~23Rm5BeQM%4rEYg{9p=%%1JC4 z10frz?(v90!bs-`_^z&l-YCrQqYqg6?e5V$M2Dr#n=vu>mHkC4VsJ5Eur;}e*a?PADG|L=l35K zlChjI)Y&5r4=i*ddc-g4=zkD}nD7V@h;DJ6pu3Kwx5?CMw7ztu-X;yO&}W`ljEk(E zlVPL07~mQoWYv~fY-pc}hm~&Sqk7_kSvZ{myuSt)U=CWSH7TQbVe@Z-(PN0E1n9M0;Q5-5$-R;nI(%5^#=EIoEqY!M(HGQ%eigrcnMCcR;nW3wXo$8r7M0REc_!Xx{^srLuYe(*7LJ z=AVTkrohL2*wx~n|CaX`d9N;2=KCZu8@f|dn1PTh(jX41n<`I7EyE1b^FRx;`9BJ7 zRD`1nGa14b>l*Jxgf#VLUZ!urk{dWh)!pzBsP^=~j?)q{>4tUN19%Bg;Ap`3L&Iol zjdK>+lvzhLqxT9x739`TI3T=xGy?rkFXJ(5Mllcv5k{egI$AUi6xov_era|$&gSD7 z$Ruz^jU(WmFypCD{a`QKIS$&Ru?3c*+N7mH0MaTw) z@Hpn173Bru=&~lN27axrF(U-avb)9!4%hM71CBQz_q_{5-?m^8HIdl4CuHF1Ht36x zKL7(4?rA5rmK$r`$6dKJ0Y$bD=zRpPK`$s6C7UpPt8Fq>iO1<#Bak3SW z@NiTjKh-7LLk2$0DI}QC6s2!UkT2Nl8ijil5SGKF+1atNf+e4#JZvg9>QE>f-+_ut zQ}XOzx|cnH@S54xivfbiOOf&zl8=KD+-A6qKXSzY7CTa|>hVOVR@S38^os+^S9Q6n z_J@gz!-~BuS~&oMalqteJhaV@8;yP<@@{Ta{6WZGmq(EJ$Y&1W(@XYLO>RJMIg^X~ zw}%u8g@WlPvy4Wg@^DE#q?=Y6KZS*uW4&m-Mvvw3qOw$Vl8JZlgX$>5{ezfUOa0RW zTxGuN?dX&f&5d;70>Re2@w)FdYL&;E+KmyjqFfZAreiODrD{yB6?{O*5(T|q^+-+a z^O1Q#xOm0qE0n3k)6^gd$w{aCfL_G4JjbM-)MIn{r)v#n@C+_O%%0587zr-TES@vh z+%q;xr;Ojz6uDK3UQ>U2(MCP`EzxnUhj3(0b#KEbf7-!!xZn8GLnz8&n2?hVvIinZh|(}nB#c0o}$IQehC(9 zjfdcMY!pK1T-yU66?=NHdqq1HfmoW#Jr@_XrV@c%W9ktqv_$f656Hje zf-5s)bfn*VW8cc~%IDjK9V^f+K;=>l+vu(@(BZ5&U( zDDy~&JptzylMJSX9r&^Ve1|}4YUl{ZjECKHvx|{1`BVRuVJ3{r(au()O{Lv`_5Cx? z_Pt`oS5gbA-krbvLdRqkmlNfZyWw>x$tQIM^%}Wf@iIgAbE2G#<#Y?G{#I|qNur$T z<`YUelU(r79@P~B_;L-VA1i$I--q~JQylpS;uZuk!E)!XCd5;dG?oVeMt=p_+rZF| z;cc2joZ3-w(tS>R9m*b#kWSsN?t@8kC`$lxEzNwxj?=fG#cs0&ts|#;K|9VRs?8OIq4nrZXWv7#q6TqYbzrTZ2!&7YX9b zTmcz$)PzIbRi~~__3c9az=_eDZc3-6#F*C+;rpeV-LxblHz)oNU9+!$L^`B^PmTkS zctZhtU!VM*5$2?OG)e+^2a^cdd$N(~QN7$AV!u(nx%x^+)qR?}*ClS8SPIa909veFB zjPV0!j=CFMGV9))l-QXhaY4?82Xr`FiU?!jnk*59VS0CK73o?Lo^ z^Lm@aB7$zq9Kk04JP5Z~PKc6HaJ zlt=zygYCm+i!|nN0!=T!!tB^xm-loZHC-;p>$j>+8)IGbE|v7~Q_lhPSb0GVD7Fpy zfMQ@#G88YlzuTq(KlY$Y`bqFk0>D>o+7;BdOEJ#g`$;$A+uD(eI72N-h>r`XYxcXD zmJ$YO+87UKwe+K)zadqFv04qlHw((2e5cKFd?=6=x(R)xPp!DIoV41Y4uU>rYNV?zSu1_&UA`I!Q;p?h}At z+@bW#UO7ojd?7AfXC}hU*@3bt1kk3Har4>VE3>08%a1^S40PJUeqESS*byk1*Qoukfu8%mt`W zwl-0-w+t!9uYT@{Hp#2WoBV>KNT}@;Pvrp`v=8)$<}*S-)N?MP9|Httun}Go1pT(a zN%@F)2~VeeJwT*SxF{D&h#!NyXxJb0w&sr0F3KqB?A=p(+iyTU{M^MiC8Efq%<^}5 zg@=nWEu6OK^h-;P{Je8x7oC+$#6eeImR=*Ax(&5@`%1d?!_{!opobTimqp>Z9s#m> z<30UK>YxaI258G^bE2T-uOY!MH4OODd*bS)%@zdlU7#PS0SP)w6U4bo$PP z1j1~pH_>z3dlj5J*;GDYN*`Fgj~&@06h8x!?~mD$!_GJ{5@>HwCc2=i4cK8kvjLvx z92ARQe5k_Kf+)hf9D5w#2YcN16Yq_{PJRYJQ`!d9|7LfjKo%O9RjhkyDO~(bVBe}# z*!qA9n#;tW!%G4B@x*3A5!}s=;voKdKjX8nRKPE}ltLmHMmBzb*d)C*pw1DRz71Sw6~-Sm)R_S8*rt+=?npzDbL^N9onG|VM=+HjClRou zu0cI*1^0fKaDB&#%xuEBYM_~AZ)W&t6e#w6dNFdfc@1#?3NIfd{x)n-sGo#s7do*J zWAUC|JcXtP9X(E|#a{=x62bL*(0!_!hq1)_F3?HMqA)cIw=Y$?-JEJ*?-6TEqIBX?2b zLQKC&0vmRh%tM}@c)GqQ=;3Ht#>j3+J!F$^B6^5ath!Bq#!+FYmE7iQqvq^7gD>T! z9f+H;Ax}8bL<-2=bBrw0WH=`g;P=FKb5)(e*YHM!v&zr1lE!|<9h+o zUQn}eR)NaaFMC|$ghMbv7_yBO^Gvuc91vM>46$!LuV!+%4 za8_nVw%T0dvR>_{>~%Ptuw44}eh`8QT<%br8e&?rg~{lT>$D*sMn}O^M8SDga32A& zJK2WY8VTt8D+i$5P(AX?LY6e+NAM`eDE=CdE96QRG z>?rB^D{B4v#dE*QN~nPe_1r@Lnf#krxnWe2E9Bk3H4^L?xr9+}a(2C#ugBKar25ku z`={{mroy+iTpyy?pMGNT?8MH-xdB<5r^Rz1&{J1f*Azyq62z`fA=N&`4NF^^b#T1d zO~vd}$))u>D_(hg;ju%4Wxu$ZeT!2v{ofguo%Gl2KlSfVURj#IZ55n1gpUUjB5e$s`ejvfZXb@ zC}(rAxQIS>=jL94M!!k6gSv4c_EtaP_CmPwI&wO*Y~s73U3qqN-nSe}E5-gG6F&V6 zH~eMy*)xSA6*t3WzDt)@s<>~oDt!TG?G~C+ijJ&vY52@W{q>Lj8I)7cr-w7w>zm^t zMtN#@a#&~`v)|oBy{D>hHrzm(UNjSXwf7Y5?C^`V6s`A)%RiupBK*@bfFCm^F0M(I zRWrl`P^y-J*sbjHc3f;$E-odw)+&F#Zg;#lrs% z(l~)NKH<~I{|aM0psf{xo4btNv(T6~KL(JJdbK3f(Yk-71*YlWxoqUr_kDy3&fIX| zD(0vs{OsPkPQCHo*B(m}_3oi|_YxPBCN3?&8qryn_Q0x}xZKmwucw?*n`@hIy}y3dgll zE{j%PKzPA~?}XQzL-*`LeRe)H$^t(++~=p=`7Kg~-L2Y_C{B>T)*z5DHX9;OfKecL zcyUeZfw>#*B6&5W_x4BB6VoY;hDu=-W9OD)E6tGvKX)$ICg64j`=s&Ib}S6suFvvm z_uf*sH270@T1CFF%tfUlH`1>T6_9Q)KRht|rQ@DVq)7$TpW0sJYQ7R$UE&W_RbcVH z;oHb}entQaW{ypTzg@OF_{Mdlx{urS+HXc6oTPANDSqs%GKc%^1o`azxvd)WY5Rgz zVX*smM0U0)%1!25pq5wEJ=&=a9hjGmWT5E1{V{3qOJcL){*j7ru&%|m-6B+$G)?^{ zvzJy?{g>Gji$_*+i8fyn%~n>JOL!i!P-e>~wpYqV9ibUO>IBCcD120YuY@y|79qs* z@mwtEnOA_Z$|5%O3(7**|Gw>0)C{wc6Q|p@0mNr|;=ZnjZ{Y93!!hSxNBwS!|5C83 znZvG|@fSx$fw^sxvIJ#dJ6M7yObr^F*dctY@=gEJ|AI<_jqdh z7M$C^hb3fT!=NoD?qs$!VfT#)=+$Xf#k9dOvQSmKA($jAvR9-_(Qp_+ajw}{U~1L) z&)Y{Xowk?o*sauGtB?gFBI~nuJoK7QiE(YS>5i#vN!p~GJKv2*t+YIc%waE+M&Bap zs8L)UFoP$9Rs!Mh9v_}s`~5|qb>0ASyI~V%sO#^dBufnAJlvDguu#t!{|uR1G~#!E{;z3Og^6sl6wR1_p*<_4Ey%C{Ybt^bfxAf`^vwsZpxO; zy{P^B7UqaxW$eMhEwY3tx6Cka0n4tGf{l#*Toru+o);Wa!Q?k)67NZ)A7R)2xbK!V*9 zLHrjG>;`8YwB!j)d;}1)55rn>^ z+fi!vZ9#i4wW1D|mGxYhV7i5`SWT@0<#Nwn$!#n22$s^q<(Jd;`)Bb^_xkS^v|vNA z)Os}jSvA6JpqgUC{Stxf#1o8aN->%qp7&rBw_jFu^=Ww(9u8;Y&-ttg=XK0jg)vcK zq_Z;5%AQsjolTwqTZHAM==}dfP+<(*I%v1gQvm)lxxCAe&{>@UNA16sYGi=F!7B79 z2=g5jRwQgau;>A;M@bZEy-CHhdkJ)5#%4jNCPsl+P(UL9(G0;<+&vbY7fl^eL4s0g zV1?@;DrxJ$d+^6V$b}Gs&s=JdAf<+-+X|c(K9vL+nD=1y9Xb(?7*B+n)f8qyj-)7z zLeN<4Ud5|*IA0$8VD$y=5&R#>j#EQg1~cjorvBtt!ZvqRE~b_o-fdm(cs-4^cXQu0 zL#8oaYCRd~y8%NYPoV>-u#ia=djjR5po_()TvBn{-l1m^#49BnQo9#)IpMiwH}Dy$ z1#d2*AcK89H55VepMsMT_k|^0od%n$Fw+jPR9tD1(taIKhf#Ya5T})@bfM%G7Z`=1 zMIXZ6HNxhLAW!T~`S z|Lbg0^xWj#7@jj`ZxuiXJ^m>2KauX`Sz?npsE6+jQ+#B+=HOzAJ78aNCg48e2=65l z18#OzyIH!i?oRTRG}=YnCfgP`5Fy`UlCMnEfy5$Xo0g4G#^vb9SQQY1di=Q`-eGHL zgnT4qA{})IpR#Z&T`5;H=9C~y>2;dNYkq5fSSM`NI5JBY#8cx*q|e%eg!|Fy9RlC{~?D>Xe>2e-uX}N{JoNN7^+qMbP0bl8OwoWn{oSPq=1HRhTFpi8+>F? z3o4c!$ya`;4U}W*Z=jsO+{|U~Hw%^{!ohPn;QGp2Y$drA?mCH^nl%dn97m;ySegB;nn{g~zk; zouIE<8W##*(1wy8wuay?lW0p~&Z6YxnbD+E)-K~uMQk02)%0**535}6P}=v&{$f6< zvD_La8V7W)72VHSb(qf9ux*%j;-2{!JtzYuhI_;u^DTuI)=P1@?DT=#>c z*L$T$$sf6yxkA!MZB%a|IhfIO8w0;R!b~>+J7!BaO_YNOKrj3FX z9;hxcULZ#92AV8K0{k}j_E|%P|oh3Mw0tZ=akX0mR z@@+(M@Vfy%1_WnrFwB5qXc*v==$5JbksdYza#F_Mf*QJ;B63hLNz1 z`!ldWSquW5yxF%Yc@&X=7;z8!#h7h~SIrSh`Ft;F(3-g4X4I#cSG*suZiCwr35bFn z0OLTAJ*`6vJgw0nLT9JP_*(G(H@-a6QK(>)f!fdjlV@aT=_N?yL-{XbwHL{ET?+zf zA4_?E^rpPE)^9BuGmb5I9$ePLr}sl7+aMN`j@pEEe~6GzkYI#NwEJrdEeT;o_VW+} z0fSL|@f{=9aUGbiB^{Q8@UR~)c1|5dXWMF^W0%_|(%=YmLE1ouRWN*n&%hDlw7h5g z@aN0>f%AVuq1i&uLbMO#XdTyCRP7dP(ioht3ugvTbsLeEBmD9EDXz%U#*2-2g-CC4 zk*}jHm|9yY;$N&8hg|6F%Bb=HO3U)M4e^_5?|Aban`q@C$H#q|^tzuD#e_@c-@vnd zAAKbNNSPq9hMG#XOANN^o9|?Ey~)r=`48Oqy1Yu+Y5{O={dulgI03WSv7=A3r9-HU z7C5!=cYcB~XRd7#3P3%teKRPEo#$9XW-K;ps9)tORQcTptYCbdOS3QN;my8fJF@qt zfFX;qEwjq#g{O#@5OFxI2wA<@8faXR&RS}q(cheIqi#`%{n*FbIUhH(-a$jc%2Rkf z<|&IZbAGQFp8~U7 zEHvxk=GrhW0QNO5looFm@|=TzBW@iVI8I+ON4BlQSg*Bmd_!|%t`3Elr^5#?aulum zJ@IUN3$`MAfQhI>eQEg4&FmfbI*=u|vK;q$mN|B7w24MrvG<8b%{Tn*!v9E;wZOo* z4LVSxqbdof*JPlQ>~0Y@o~#)=458BKFC<6HK2yh*X7~}&^;4siGE2Bmn%+dp=fMRq zN9onPlLtev9KH{7w%a-|cYmxDY;H?G1t1ycqKgm$wpb%;x>6E6Ub~QEP@OCUdw0efGr!`E=zLji&8@5Vh4LRS|YyUn={2+!q(J zdLc?=<6yfpNzhu`b_K%8Wta2gzjY+ISw%AzL9&?1bxxxa;?>|c^3$uXhlDKj0^9a# z+I9=E=ORTqIn`$t4EA7_WZ<>0 z@DFxU81i!O30NJSO@|nHNLn~sdq{_yYkh4Qbjyb4&V?131HBf*&jm8^UR&uPnK#7L z-{~WIT7OO{`1zWT!`bbd@;5X$YDC4NIEnkAkJcsSVKG?3c&P~?fNY^pLf+)L$C6@E zd!9WZ7bQ_pnK|)a=+y4{LscWmg_9UQ12GPz9tklkPR2J-lIri5_>3LQN3zKQqah~B z{+Cms(=`0oR2Wo-R)K2oufx*;0<#i_9V#^C=8Vgr3pjEpIvug&8~1-Jf#@7K5|Tii zKDoOvG~k3$n1QT=;nPMG?o@VBQjj3=a8kbt={Vqm8I(wg ze|-HqrF6sLzir^cL#V`1SohhFlYRb>JpMBQGV0VCEMCr^P$UxMdK(}I8WwMgvcGv1 zCyx)KBx^$MvmkYVY6g#SfXW~|M+;%&l1>A+PYLCqC?XNO zUgRybQlIq9q6^_uOa|3eoD;82*DPSGx6}euYSiCgE_KNNwcNFuuTA4&|ToF`8gSV=pa9BaZExZ zr}^abk)eq}!2|JP>*7Gk z4jH}Po}Je5>&Dm)*5!1hr~%Etc6Civ9)^F$@Q!QBoBIXdPNTnGob{{Z zwC$nq?ndDw*l*e?Od2iFBxN0)*gR<#HFHoRNi@DfbX;zGbGcb#$Lm(GY#Kh6X}NLQ zv6I>}P>nlD?ImB@qAGT^tbOBs;(_EOZ`(%y_0V#S3?}8O>2?j70^iD${jn81@vV&N zM&W8o=hAYN(vqV!e`r+5{5dZWDxUNwZf^rvfI$Ab=j0jqTaPNXrDb2LNm_D(ru%nl zNmsSO*ow=E+`NqsxQY(>$SpI>+*ajHo8gzZFWEBfct@syTm8uMnL1kKp6PEL>0;Rf zCiTH-EqBr&C_DX~x@m6p{_O4D3s}E`cK`j)TSBjq%D zJ?tEhgm<>Y{qAq@nTCalY$OX=nxEFI>ZIi?bi}7R(tG37Y80_!@8F$GJWa4M>OL(s zqxWbG)K${1<>;Bq>K%H}r1*h}rvqM3eQRp9eERm0yNg(#nVrY4&v$wGdE5=uy=;(p zP7^Di)D9t5=gBzb_iF!-sPm3$YUu*KfOKin6odd*=|uq%K|{YbN~9xAP&$ZG1rv${ zf}ny*5fMXBI!Ff*3H{Qm^deG2Z=ociy*YgEt@j6OapugK*|TTPl>OWLq~&_1oKdEH z;#hA$nY@}$T+&H?&SLf;&v zOisRKkdhrVgQ{1`{4G|<>Dmge{S&4e27wDD?^OO4ic}aJv?>_=;oaxN#0jeU7$8O zhvyTHT@qDGEoA(3#bOuTZ9?PKwc+5Zj^;as%OH6Racwa-J)#k**6=pO~}S>aXQd1#iQVNo~31#7lqI$1q?Jzu579hq}%P zdrj9EIThWFn7Bp5)Uk2ixpwXI)J#{%^Q*|>^M#vEq{p0|kp@ayb%Xh(nae~2<%?-k zA371=-**#WFCu9g#FD9m9ZBp8LXBr&_7Rk4dm$6I8itanrkqGB#FTW>V+G^r9z@M$ zSYeD4>4$>QGV|m!!2}Ury&(eq>BeuM<`9`X4ZK*K`F#0~8t)=;F_TVk)PSYwB8`0O zMw1u}{I7FFty#Fyv^4>}(W#eWY#n;Zosz!86X(jbRnQhJ&$~_|elKskcRzTi4 zfA>j*{1>VKchdaUWh{l>DBYUoC^7(Q^JGuRTLonEd4y9$fdb9hh7Dgwb<%l!*O~Nv zlHq}PsEs5t@;v)QIFRPh{(08gS1Mr-pvAa@86r7bm^c5Mox06=c)^))CN@=#=nW&S zXU&KnpRqsK=*w!T$n%9VPNZL3C2*xumb-pG2(ztW#M0%T6H8dL`jW-uc0}Nn)J@P~&>X=|y1z|Bt%=_VaLB@c!aaPf zKFkM{I^3&>^d|ET5wto&F3JLFnd~F%jWqH<7AUakWCi~U@4A9aInN#hwU2KCv=4EE zu-uV~Xv2KOQ6eI^!g@L)43ubGd*(iLhCKEr1EnbRhEROSZ;3{H{G;&QdxzVUm#7u-?w8vGJ7@8X>}y}wSrs1|D`|pzNIrpRTMXFg)o%0HIx;XNR*RETvDtQ^0&f& zo7D=FX2L2(C7I{UaV%q}rK>udg}SlNL)-Wr)d zk>jmV?7S`!q|MX8l_;{3k4F0sB>zt#Rck!S>h4Ebaoxmjb=yzfYyzbA?RKYBX8E2u zg&x|?rLFS|hH9EM#+-e$RD>;$1;Y@c`FW}OZfccMwtsmazXy5mS#+j@nW66AukG|- znP0X+5Ap}gVnbywJ&4(FjRIYGh#D0HhSr>kAfSC}fVOFEt7rwsuw#9fanztPPo6zscXweT{RLg$>eHBUOI@sj zT1%?64Zh7f)<)KLPBz_(*SNCXtkUxRp;g?qou?}14naRPTy^tAEqb}8 zZr-fhi3MJXOVm}V)KG;v%qxbaJ{qt}WKKI~w?w^c$O?Kod+p^ZfAXnBvsEXm@1ttF zu@17>0okUsMEeG2>hU?6aoW}8EsNFNkH=Q%kr~Uebo14heqQ7}KMm6=r0I)sm1i7( z)W8#w4kvo5yjMn?)gfh5c`SgZ45{L@aM#pT&?-jZ^k@6L%D7cbI`YgMk~zMx26Cj`%V6v|)Ub-U#(G3SQVz@#b6-Ev{F;ns)L*CuqA&`3P!6sM!%k{y2lAp>9Dm=c zW~_Fh7+>RN`6EcgMsGOpXYC=-Z3f~E;EAz}Lo4ISM4DPoOnv~!ULqe*pe>;^i zrnpk_l!T3Sv9%fUUl>{3C=om0G0yM0E}E<#@pdQ|`0=ooU^3oLPp9+j*5tOGn`Bc$ zly}DaXN=XB6j>#lnJx?fw1-+@{UKMDejD19!Pwc2Gd#68M|-wCoa@(qEGqP%hviYt zNlca*Uh#~{6B%;w7~-qw4fOt71z`@o$!DTI@r$Zm=9H;BD0!F=buL3B z4cYs5IG4@nHs5ctWUxiD6Z@+*JJW?;yNoKX^l0kVdESp~4)_sV%n)dFD1QIj6>b;Z z;rEKD%>eUK>6dG0m_c6p3Z;1{skLU~MeS=ACU>59}w8Z8s)L7OvFWSVu>QYea%%`FbQ2I~bcqQw@+>hU1&x5m@z`s9P{@ptyS7v#| zO7!i-
  • Xsnr=P-L3+=1Z-H^{z8yikPTx@!5ajq7YF3^BlC^22~1sKi%DD9r~D;v zD@3<;f^rvH2s+;lJlPJKS(9^v_Ao4~n70e=m1+`dymPA`cKT+P|X^hRI>YGd!qflNz?!+h2jcz@NB%L!~Vqj*OrJ~Bdt?iD5;<*1i9WA zh^=O;UDEIA;0{-_MQ0w$e(EG(SeN}y3OlJOTeyG8f8a6Ro@N|+Db%h$9q?1<5`Pda z=d5N@h+CBwXK&{TaiE1C!Rg%L`D6(sX=ae3=h9T|M;gy2UEk(^g9 zo@*hbER8RdNt0Lr$|bAwL^et@z2+IT*p;j|VClWPS;YxNxhv!?gD*oZ9)*hI{F@9| zE}^5H!^tQ-=p4NIk_9rvQpi#oUMs`?mk0Kjr^Pk8+cnxg6De_2gy||Gy(||mvNX5t zcLQ@{iBc*U?VR6R9Pd9aQ7^VY@>-e~bS>{3F*XncdEvZ^t&LL^2s|F2=Mi?1r3+uLy&S3;ny;6Qu07(;+2%5P&r22vU}`H&6AJ z#{0?Kt>U?D7+qi;-G`>Fubbu^PCH{AI$A~=jh~c^)h>{3ia9IJAMI(*teDqyEie2k zU$xCT{b}v2rdwG$tz&5m4tA?|%{HrDINliV>3~rwvGU?Kb-cqSx6A#uV)e@pke45% zR!hOp0fRuZAloYJ#f?&+lshu;HR-h8g`k2U*}g|p;3yQ>&8QT{aV@SgQiWmXq##rXk>?g6*zO|EC==W;s?LWa)J zg*FTiq(f3Pa|>?gZk1wo>S$)edUKS0!>LOs(L2;!=9y-A0?XZ7O3&o++7-K`}QT( zE+&D8I|5GO!^M=hC6Z&m&V91n!c^WbZFg;yLwR+H1^ zlDZFsZSwJ?ydHh1+?JIbIk*(py8&J-_wINeNN2Z%svlM?p}h5ekrpgl{|J~Hn66mv z_=7#aN0P zsK9X-cPvGB=M1};GF2Db|8L?<(jP z+#xdb+Yj>Fk~+btPXEt(zIQy@c$6HNlh5YsF)q+0xe@D}!ycYAlYbO6$C$a3ZuK#- zPQ21&Yqy;})_@K90Oc7tuJDW_Xr9CnKlzW^mpD(4o@AxTWTiQ7{uO6PV{zZy5l^6$ za7BLYEMQ$kI;*`}um+Q|QKu6BtQSzTTqhxuZabrMFGFvq*gc9yY1pomEMHcql-ik? z&C=FC-`-Dm-v)OOh$m0+)*i0v*SkBYEM zFJk0h>Gh7#akvsWmNFT@ri+#xrv$?(MIw@85XnomBSHfncwLVrLNk9{AykQG(|o%z zFq_gA@;ehbT*FXTp^TazSVa2g|LLcz@`j$yQb{(rmu&cr<>=@I5y&q{G&&6qHR(v_ zryr*(m?tBi@Kd}wzC4A!R$}-!neE?X3OCs!5xiH@8{87$joL+604bG7xg(twIF{m$ z`LQ0lria8Pr?8uslVeo*eLjP3U^xPO+}AOzv5>4%B9Y%gpt)t-Mc?X*FJR47&hu85W%IjODk*ea@D>{i57VXUk`9%_bvRzR{f1JR46wvHg)9Uy>ZfABVsj8R<>TD)A>g=M@ z_J0tSu|ICFgJIUw0VnmhC0d#zsNz?cU0+8`O~M~k$_V%7YLvU5 z4xj49!U_M+0`}FQ>8#0j{b2Tfq-Ej+h|1l`1!uCDn=1QX3XNSb;aL4Eo0JX9^{4~l67x3mJ(Scr4nlX#3VF5F)#(mFMa`a3+p zHs;SDSydodwNx-{x7@i#a|=QWIR9n%)A1ZqY7gOy0L<`!j22>mQ1Box+Bwy#vGRXc*>A2k_kW0i5;t8>Pr7DI_=#!+;mxRez*&1#Rn zA2!ra=VMhd4v7+CHXd9Q0n<&v?J8H*(Rh*7LS7fpk!Er6a-#-s((%`qQc|OLiL~X} zt8mSm(mJRpaCYdqpRdcNQ;Pr#vRS^4s^ZUyq3>X7C`t8O#rv&-wa1L*zN%u&gnyBB zS^Y}RjtA!3k9~8$F>vbICU1YZZ8yR?;<8udjxjIaH!qjk9FbVtruD$&d4k=i)|;D1 zUR9xy3wS>P_Hx!!mPU;WA=*BqQQunlmj+D!FW3FcY>`YDPjh-Sw&7Zy)}6a}uKn@p z7t8#ERM*!wIF>@Ty#UV1!iQ_&hH%K`kUu`8KR)V;*O8toab_1{MOk4u*4uKJ7zD;J z0c<09)E%xPbyQMQF5p=NqGVXpRp__t8^AYj%P!tD{V(d&eN7DA{jI%0FwY${ZA^{z z;2H@beqN+$?^?l+z~oL-?sNf9x)6JZ)fUM*0Qbr2iliz2J*Cj2#j(_j0U00qh}T|E z6%oLTOspM4yEXFtmla)X3|Z_LPc6*ZQktB~sjyz03O!hZ`a^bo!2{~;%1C~d)Y=Ph z8UchjE6krYk^>W?it)+;-%+mjw7dfF0!{hH3-FN(cdJ-$Yh%`x$vsDmW~lR+CDrRfA0Y7&NJ#wK4?!&z z^z*?_1P)5~ng}5>G8j2HW{F#wOZh@<3hQJ9>wt)ldbA3XpTf(#D%D37y0lTZfEe@> z|5usop9_dHtk{H;#Yyc09Jv`VeyIqHNpS*aZ$*G4FmJsAv>1(Sz;U;YiZv33IWZH1 zU1N;5dY>}*A?mox0zG(04jn#vpLj@W*Vd^Idhk-L+%^@lb1nq&j5O~he(rke<^_1; zg|-gX+k6g(x%D7B-BW1RJqVdgIa@!pmEo zd<|*y${@a5ihk}f9Qq3D7@Nj5=VKrIjT*%g&C4b-KC*xx- zXENuV5K7<=_?h$H3&ntNKNhE9y5dmLvh#PQfT^B%}4*|14Cy zKU|N|yh-9B<(c&foKba)GhK`m>)QeZ<2AGOMwec%Zu3f^tFx=Ib2)87wJC6!l)LZr z(*-kK2ULUu{|8(*zYS&jY2sQLIX1V!5-bmv;3pLQ+~gcyJt<-XN7@hs7%$C%d&b~{ z)6i48DLLHp#-F`48&psYDmeGgAf@LKfT#Kk;ebzyxznhibX0^RQ}80-{D!gE>H55s z_*Lv%-fyq~qmGJ(mW`Y^3jlf@=J%oe@yYpg0I(NJXMoMsZ!rN}wc;z$ z`#y?COZx`ErNXe2imxr8)te2c!(I$X z`{rOBu!WtA5R44u@GJ)GRq-cavqoi<&uu~mS#E&FWCxAbf?pgnfTkvC|#q=72V6LdmK;fuL# zmqp_Vc}Pcl8Ju_97GL}Z=4hDXfa5bw#p|df72!{x;hHH3Dg&V9ITr|nXQp#1nSO@L zpa>EB4}Hewj;)L*1Tq0aF1Lcp%n6@I8~RWf;@MU+BbG$3+db+y>Bv7&M>53A0dq#U zCd7slv%y>rK4kTmYO8t?t#(HZ^+1LD(`Tj~{RK-v+<_i=5M;uO-;5kHKu9$BwOfFo zx85OvRm14-!tcI27Fa;qDR(H0b)KXsA4z_d^c1wNJn}MMl!N~814Sf1U+kR-IXH+p zZvp5hg%*V5o<@@d&lj4wk_wJtW7EC4(Ij7S&C~66 zcEwib0^nvh~q7}ieLm@xHd1aaC=YSjsK*&NBs-_sPaZcp=bc*EK~%Q1~=zXM!qRhq+r zw?J%dguz1^m4OY$6}!a0MSIrn>Y?ZH(JTw68vKi>S{+HUN)PvXH_F_y{C?stIH~7f z05^x-6_BfZh^mMJYY4+eTtzng^jPTDAvIUBS<-y!+pu#}SKx=6u{hj?u2|gE1)-|} z@q}(*^j1ut@*W8JC6D~xmb+{4V>*Yb(v@U&HI)}Eb`hEdxCh@OKw5wUNQ;vIs*?(n zm~$Hn@z4h=DDKSTTF1gE{uBJZI5U5XarQGP4Y37ECPd4B85;x)N0`7rn79Ve5!1hP zE2(^VyPHqslL6v$kkzU)MH-=oa|plVdqoZ|8eY80Wd{}+&{QNU=&VNbdAK`EmH}9~ z!52g;Z+By{a=^TCHxS_I)?5lzT=9j~{>qcFQJi%!eKJ$|mz!!+IyU$rO$d^OI-s;x(6K{8Peo(O)q_F>H6 zoN5>Cr9WGpb1y%8lYev?}zN+X|R7e7}V_Kfwr=M0;ju=!5FR!`MCyVW~;@7|`7R#J8P=v&#A>xtb`;8k~3zf+04Q~6M#ckW&r zt-}n+wd)SJe((zJ8&vZD3cJKl28Xv`Coly_efR;okJfG$lI!VH^89;fgQ8L@C&9a2 z)t(r~>{Sa&T77%$58sr|E>K2f$WB@b5;*5_YE)But>Gh9?4M+9on#j-Bo-(ny4nEB zOOFnU>_7a_E!5x8&Wmj(A2h!)nQ!LgDs8X8-DB)X{~0JtYoA#B3Btf(y|hWQ00SFJ zdu!1BMACsi_`m=d>`YhsX;Ex&ia^0)8*4J>6&CP}Wa_w+fjO@X^2|V@O?!NOY)=QNg;)-d0L9P)c;o{TaXO{qD;J zHQOV5j-ay=f5C^0E#WlQ?CpSA<4d?EBV=3j0S@Qo!a{ZW^;zL(tPpatlh0(+c@tgz zD^q8nl){?DE#LWHaTRHs>gV`F%fd0-z1PgCai$ zdp##A!O?DNU3F}MeE0kUMH*sB=x6vCk<(^$N?bOr% zrHTUuU&M^R0Z%Yv*Q--(IlyU)Y*c9T<%O#)-^H8_gy6T3ga zdjSJ~(KW^Q{-UEjZ!?CwP^P`d=CC4vuR!wrNzFEQ%rX7Q80t!SsK{-kKg^^6q&O+e z$YQKPw0(?<*pZozX`5AGiv|Y>JNP*RysqADU*IMMFt6t0WN@`Zvz8sye#7os&o+yj zq)}krYcL}v$!e~h*7dZl0(;))FZmQv4WHT;o>(4xbNp9OU~RN{^_MfYR#Y)@k#iV* zS_ws+eD~;*b`aPupsO!|b#^72lXvlu_*MJ-1o}S()N0#07R%RmD`TlRX$d^T*A4ay zIC}PMIuAN)`+pw0qj?DrwJklT?Drw^t?Q(fl?U^?5uYm%Jpq?xN35Jf@|u9 zBcLO;uCH{4$|!)O-6lp?`}=j&hd;sH^;(`m<@h>M3QZ=}khurai0a!$zA1WH*1$oG z@kLk$P}S9b-Qjsf)bJ?DWZ|Y|8{=SySNOq<~ zT(v9d-*#B?ll`*xKKLVdvz~)F)G(Ii@||ND>P|ufaJ2$VlNmW2_>m2c#rri?w1MjE z+$e=txxeW#_=C!`1H-mTG|g9Knd*?zOaH}dAaCkFtqS5LC`Ls|Wd z9tB4Q$sV2m!4~z@Xr_wW*?BDa3vk_HS;xLX>;=NsG671o?2hpJI%`SG4>&}|Z9ov3 zzXSj{c~s;SwH;U;ymEf$m(4ot#XNVxP*}r()3y%R{B4)C07#XDgO92cpu>4*UFrju~%73tC% zfNru!WdE)`oO=Ao!)?pc{CwXcthNEy`-;BOdct4n0CzKBv9s-lTyTgwk=-Z`HC_`N zg`5{G(_-%s?vwFFsLV2e33`7UzkqLLHV*gCp(b^;nN&H>W+>Ks#Nu)F6^Pk`%5ox}fT?dKey zxPm77&l8Qb#QRP-DWT5v8$kqUF|P1S_RzA1YtOA-gE!f4m5g!$OA-%of&;ZOp|Tk) zGlHTY0{4mfg}JMxSiYADYZVki{8m=oukz}}3g|e+*O3h1C(TQ!hl12EUk2J`W5Aih zq=Ab`FNp}%&Bj1yOoUm!TgyGFWQYmZyJui|i$Ft#!<%0I0ARSm?=UW>Pvug&Pf>lZ8T#l0aM8z~AO$D!uomVUOI~;5W zTxFpYt^{^;Y3=hBHqayzXm)_Kdkpm<-sx8p>Dx(;8cnRDzG$;Eo}U~{){tB-8C)TEgtd0O5? zcbl;3^pIEj|7wk87v)n3X{1qOAw?OmljN$S#*+$nYaOdhuH6!5ls83on9j=(4 zHkyFYA=MKOYr~qouug*5yW(=%(V=O}v3kBjn*#bf-vm*E{NTj`dr^s?IQ8fUNK;Gg z$sWipV1@0+w58=y2)Wtj$`JL4{bs&LXj&P`e7BG*;MllabN&I+?ZtB&*7zck193YU zRWM-hQ(tib+3o|3TyCyy+rK{3APJnQsAr~`M^|qgc4Xq&is$Qwgn|~-!PBOeTrSdW zvb>i>m`~?4(f`1-^<(g9b=KWT6Z0}lU?-vZ!`Xb=(fVncacU3G z&7u{sL;G;Ms3Yx^Q>b4tX>eBo#y@Hx(()Wo@8|{geVI3%1Ojv8x2EReaNmMo5n%tR z`5VAk>NifCEN=H5%hhEpki!pBH>KfbGI@mgoxrD0OuA;k;n=aaf9HkS2omt;6f@8! zj790K30M#CL&_$eOsUqTKNueMgD%ndO+EEw(@x4Z3d@Jc032HI3HNIc+l(O7P5|*~ z(psn6jSrCJRk#w8L30y1gZYb0^H})ltI+THTk^bp_PK^2NI35^|CsHwbU5|PDT~lVdPCy6sqWfm`BJfz{WNm23Ob;)U z2g4KQIM}uwcvHDTGLZ`*!=A-68Nowq%CuS@th22uCNnG z+yx+ULv=WPi~r|vUocCsy{%@tbsHJIuFU)x4RYuxYEKySbW2TH02X}z6v8YbdZXl2 z)Zp}3k4PPk`ZF}5!g{GKqfJ4LEf;e=wWPQn4uBZkG9H=OloK3ysSMD>;>n5{8&7&| z6WIbyy9cOo3!Q=iuu8!9hl$V&Vwc>p^r15+(%GSA;LCtmGWSx`l2%7f#~%p%qgJG} zT?Q~8xkYN0?zJ(!bKL2D9Db^h!c|<4&l)g`L24a%M`PIm{I@jc{+m}A=DHI)^9=rs zLo}*D5PWiDHI(h0fpG3tlu1CxYU@G3B_slQr`59tcBv=K1g2*iDViH2D)r50AT!pa zx0*?{(RA|GiT%zm7u2CyYk_Jvk1x*4@pKNCETkk9Nxo|$5Dk75hjYJdTgq()r>GM3 zkt&EghCT|HE}^&=726utKy!uj~x-FhW~iD&ZiBqbdd^;7NN|&UE2auE7~8pMU|e2=4lpCAWIXAe}GW1n}6V z)y^xs@Ww()W1(h;Dazg)n7VVu?ZQ<`C~Jk9H_TA}<|fGp{bXWdy^D=Pc8A03fAb||t-Aog9I}^e|TtFgRdoEryuQ0$KH2mJR zTDC|;Fsr)1Igm{FODcxX{MatHqj2U;2IcDzI=s;Yx6DI4G_@7~zh2#$5r(17 zZNS9>um02=wPP;al8bl9Ym+ynmCRi_*D6K)aNATgsO`u~Hn*c&+T!%+ZQ#2akW=Pt z@+4pL`vX)YfG)z0CO}Cf3si~)E+G%zm^YocSd$J`>gV-Z`u;05JbH zRz>aA2C#7bD)9|c7xxYrHXyN`!B-;Zj;_M&1&07}Euil_VO8@VIx{}`JRvL+(#{AZ zU^|;rSfX0yXY|3zRu1XBkscwi3T4@NWTan~t^WaHWzpRY$YS|jj3d!w!S01N!-c&w zCIH{kal1e$ZdEopE&UhRsfzfp>eOBYK^CU#-8vkfSwzO>y$3QLycb;Okg7MRNE7s2 z_&2%0`dJ}qv`ivp#8|ca1ZDe#i58J%%QXP9TpfM*wPBurkWST7$u>i2P7iX0RR1uH z^c+on?}5KIu{Hpfcq)JeGfu`6unEoKl>JdM!h?|bm`7S2iGw1QZi&lbE5jg4!j&aN0FYCN*Q}4&TQGh;EnE+RwGYRu%KK=`Q@r~+BB@nIHOUGy}KZw&lq8!r>Df zZFdve3eqQ0viIn&*b~d#!bZ!;qh;BHZ&=O_&vOogmz=0`y^D@tUkO`_FNMeQZPZdu zmuK6gu(%G*yA9FtTPeZHm9h+y*(~|{GdsaIuAj}&?YI!jmhTbC7OACfM%tws)MH5M zu~fJRJoGSm8TeUhbY!$RhN+a0PnXwC5}&|Bfl~TYp+De?hWq9mW>`v&09Hvh@G%mi z-u>G@XoWrc|C3|W;8vqdBcokR=t7MKVvx3~KHEKtY z{5gaV@lz=qMl?!A?(lOSIWE8gV88-SAdd`^zIkdTpAFL+Y5f=a7x?1W&~W{AFBEg% z<6fK``@+h#Xe(XcmB(u7=LdW3H$d>Jx}&!Ip{{j0d;ib&@h|zwlVbAqdz^cu@Jy%2Ni~?SX z7g^20x|-=3RBdJa0^8lV@fCKQ9}MRgiKvP}sA_+h*vk+IY+C!>_dQ7R^ZI+RPUrh! z6Z~$=RTbP;T{#{>T^=A3WUXqL)!H3cYs~<+o*qN-j+q4iX5D}0H`(NO+px;uVU=FnfXD(s~{KWmLae|i^zrtpPDZ_rSmom>MAi4op36%zFM`~GwL@v z>gRCZ_5pxrh3W2l`5tEG1-Xue0+M}emSZ&*rz6F#V{^{%PSKyI{R$sg&8cw11Xb(@ zRcQ5$qvFTxqI;%FM!##jnW64hQP&8_4^3H)eed7IF>o8S!q3s2`T^o3*7|Oi{PqyP zq#E~LfSrR)-B&nL0AF@!To+OP!C8G?1*xGLH#|oixua-oIY4DX*vMZE3GoKo)jjRk$F>FsUY3W*J*#d21!AdM9^G4Q&Xe*lhj+h$@E*Lo!W~-E@ z94~;M6ky^Y?vNLEyC?@8hBy4OzNFEV2MfTD1!9j`vBzM`b1`T8RA^7A)_$MAneYHW-Ap2EQC!s=e+E+v10i+;*akL6ou|T2I(#HLDXuI{_Yf#s82u)kf z6mgQOa%Ll4?$0Ic66=B`#=sY27)qnmDgYl4hzf+v4Y-3f1Ux{!Ull61_yT-MfSsOo za-CKDGH6b~z!76Ju+v%9wcuLj5vTms{Zzn-<8!wR?-&2cQP$zJ&q;%R>Sn+^uF5qd zz@)~yV2@e1$9NUdoE@Ix9Hvq&V8zw~rX+q}-⪚6=XB!9Kn5F3VG{IlJ!&HQ$?<- z2z?WPrmHaNkVzrruu3W&xD?2#TR~imF904nUifT%?*0Z~!XG;%RWi`Dg0Cn~4N%d} zZxpQ{*8HI|r1!fhNNH7}UO{*Qa0^%yld11c%*Io~Z{U|Kc~=5dq3+dza4vR$HPQ^z z?MmO63krm^j*k}TX=0shVx6<6zgXBHR`?uP$yj&(S*2n6JykV~JGT&``HW=lr;Y*j zsK(V^K$NoD_OK2F>=>O+X1nkLoKqjwJWPXH^IiqCCXQ}GX`3L@Aqa}hQos~gvn?B0 z+*-#PJjA?wNArGc%FPU}$iPs>rGunLe*}~W@GT)@C*U+WzfrlAn$<(d3Cp=|o56ZX zfRs-2Sd>`!0y5C89j$FmBpNVuWfxO&=S|n*JEzSXeyD z@4bm*W`wl8q>3t_av-J@8q}Hv%7B}hH1se^EJG~sh?pXRM5}N!rL?jAFX|EsX1MHv z`rd}2OWN5}8tKZ*&LS9#`$(Q3REQ3`KnQg>)rV5*BYE6PAkHu8XB}7YLyR z?o-`~^+!3$aGI3DP{MW-!C1f^Z0FV~jXLKp;aLXaB~n%5MN$y?`XB-}{dT77!F4;% zkwq!P;+sBV2hU&TqX5uj+n4aSak!}X1=!hwix>dc%+kp8G#Ben0t(>N{0$D|*?hmB zV8D@`NuI$U1bk-prE_%8;A^B z`BP+fK?Ea+8_mBVEb#@Nkit};AL*SLN$FT947Q(tMsILer`yiF?u0|5pD3MK_?5Be8N zMu7s*ul*@`ewsz9C{tCt?lCCw>B z8exPum*3q`#uu#-Kq{Zlh>vvarRyC|P8#AOd`utcN~^&_p~WG>O;i4y#kPmerwF{m zz%d|JZd5xQk2k_hduRZD|z3cV_3|p)3P43aLgQ2VH*|nB_vW6#>j+w+HM_>y8$HuIxQh zfSl3QMR&f$NPclqq&3+*6CD7>eP|($50SvRkJ~UM&-CGEa!MPona$Bb`xvm^lQ+ z(dzPnINC^9Lvspl+)n-A9Jmtis`vkl1tB-Ua}+XlzAaRZSU;#ne2>4)m2L&i zhi73ChXaQrs^l*bF{*&g;Q`o$>Lh_WsTdtdDhkFlgCQ58kmLUa%ud&Wdb3QiR8@f> zh!lWYJcxX6h`@o+yvh z4*hXTOBV{oN60~Ul(bo3_H^Oz@RerP%I$#K%|_HY{wRW(`q7yvC93nX&hJZ{ENb2!aW> z>m_ac+?K?wYDJq_4D*rx;nu*6;Tz+`rOnE?Kr1Fa*+|7i17Tl>Op)=cg>vTYgm~t* zP7qy7TRF3JX>RxNkw5&|J2)}uhQ`YZq<5t;rZ@cp&}od=K(4n&N+mL-GWC}=zRL=D zsQ@HsIB}7;KlT4%I^7d5SMEtr(911Pva^>)b~zGO`OvIoZoh@LdK!rJ(i(tC;Y7of z13D6cr>`B{NJn0*nL4U85xBx@9McYj&S{>@ZT1*20G1qO;{?#Ub?GM1#GL`F*mjx8 zTe3~W1Wik3kxsyA(|^nW_atyK$<%3wtPu<9k(J2E%2Zw(e5F<4`8j}t4H=$DsQtLP z4dN_ z$n4cMm)uU5=&Pc@G%CgD=fdb z)UFEQtN0)=M}~$;0C&lc9iECI$6pN*01BoE z$PVwE#0lF**@6OK{;~rl%A^ScQ-Fn7H!>bBO_w!+M%UpCfZSX%x5OXY{$@qlZ zT@-{(SH@kQFx~a$$Vda6cEzC*1O}Q%St(j!<=`h{ueow{3+z09k=}aO*(3mr3*290 z&JMSGkyX6!-v?pg=_;?ER2`Hus9go`3~iM=BzF`HHBN3b>}yT|uGsXaxjq7qFWOcQ z>hbIr$DH!Fj5?30o5{S<=#~y(UwtqR9I=1VaHTyn-(8zFABfCblkP?WyTuL0{ zv~S-QaFR4j>M;Q%mTa^J=7sdlZqrmUvN`D_VA6=A7p z7qvRj>y)wN_wyz{7+ta;<{h{v zGpqxB8C}I7UBrOzow*V~z)=nv#klN1r>!<9a6l2XW2 zzsD%bgZb1-`kvDpCdi|_lYn13_~ym7 zu&8Ym@B~uLV7p>;xaF_;{S&-EcL(g?#vW&Q%2xCR$=1hh34>S-(7~4SC>wI0ESZYR z?lEOv-o&zNHIy81>0o8gcfOqa*bv0X8?Z1~LII{h9;(83pwQQqz$AQ^E(7;(@WaqQ z5!2};b|UaR>knbk0x67SJIXJ4JF~j&OAeBZ$x*qYvpI{zwi)DfZ|WXEOFJ+AWD7ag z+wvKl1T6H2{FDQ|!2UCx?Fy$?GYD?2w+UUm*M=6CLEWjm*$c=@^$rbnTjzE_x(yRv z>WC5ZMGnQ3)Fzd&#L^bMVW7PIanYy+EhG9nGnO&?A!X@`NqaMTLJC|WosWle|BYv? zx|3lbY!uLhj#5Oyk`TTbU=aX|q?wH9i7pbPF0iP$^I7MhEc~-l8a! z^V8QXg@jc(9h(V1eY&@O{H#4_mnnS9iEHoR`2GZnds6TkwIIt{L~ViQ-@i}J97vvK zT@zeaW2!9Z({g5R+Ixb3!*wja{^cy{I_V6}^xw;u{+ORV8$7>QkTw-}QN{W0aO5Ub zbS%9l^U)?^!fdmIu{f-Z^WYcNV|s-!?6r`UhY7^MFqyN#`Da=6w?e)k`Gt-^Ev#M2 zlRQs9B@y<2QGK4L5MbwnZ=BsT3Ec81CFQa!D=T-_haZlLDPK~aX_hfIa~U4)+KfT{ zEa(#(+>J39e8k)Wgv|UlV)vri)~LQt!>`cv{Yh;#Glu~*Ev!^*uzdP&Xws`STb%|8 z4ZmMkFSW4N2?cYrWS*9&)1BI(8W~Lgcqo*Gc z=K6d5Kvnwm?3tMuP_*`9ut=oZmxz5y_(dTn^J@*={OW0urY~zu88c765_!B>VA+sS z8af+r_potVQ(ctNm(sj;Xeuau`eJ-YLQMj7=EWp!wG4L|GSt47^HiF_9>Sl`ev1i- z2zK8?#eXs7H$QsDxt2?c4beUOMlqP1I`ecAn!ZAB4(c4C`)Jg`qg9|HYL76o+bxiy zs@>22_B!?mpl-cQE%oM>>v{9)Y!@eDhsBo z<_Q`&$MRDO?ez32yLEqs*e>3c>96DY`!Jd-KKy4d^@SC;+=~)8{Clofxy)`7K=F6D z0&_x=Zsy;LIOiq}bp)5B0rTY&9iO~|8PRdGfy6G&DKDy}azvkH$WIxr|9DcLFuP5X z0%%&#AG%L>QeW4?c~bH0mFd+g^$-)oJ@{B)t7XcB3p)Qy+|E;Sr569`kWcnI}{{75|5*^NwpO`Tl+i5CI7+ zQd9)ON=p!A6#)q)psXYcgwR~NE=UbUAvD26KonbqU<0IuF1<<(DhgP@NRd#bN(m?e zQuUd*-{0%`!+4q8nLFj)nKS48IXBlSnOC0fG-FzB9DAI?;y&q28Z{A}`n-iqOb|sT z5@6#d&>-mJAHky?l#kz$`hl6cwGdIKmzH_Ig6=OCtu(`xoS5SpBthxE(AA^6&8lB8 z)|Kf`lWu632Hk_z5>p(gsu~QoG%DeyO@18bGi)L7USloM$_XU*bV<3zhfm=IrDtiv z9!30NV}BY1W-ix4Hnunnl&7M$2FXC$n=GtU!vE=z7yoef22)!z!RRE_Mnjxr^iW)}mobyL zIR(DE7h6FbaHQHqlL>S~cDd9Ig0L@ZYu^Dy$>s+vMd`kmtKgPWmC%=VORQCIEM=!c z-`5c#|4_v>df?JyG~whH{`OImRbS|4b*Tg|;qFG$`eB51;?bXMsjEqc z-!0czf(P22w!QNv4$PEf7oz~kKx@P#Xj{bzpARPAf}w=EvRBppGN5D$ZzcG&bW~t-88}2>e9)Gemu6`Icv>3BWO*#xvVE-K!+E|XcZ4dAJu?DItp4GuE zjk;=mmEkrV|Hepi@2JV`0RC4$talwqO}+duK(cO_VCt*nuM-kBzPhf`()lXa)@Ow9 zPZ0m(AFX52a;bI&q%8K6c94-!@Gt+XT0-U9Jig`71~8FqzJ!T7pg*7@K>{~mCPUH{shm% z>wlBmpOI=EX@drmSvR8#^yx=02hxv94B2Ib*LqHFFi=*i!%tc3cAbBL%h+ync6f8v z^DD%B7Tn(ZeAiUD301a4BHwO|Rtp|kcECYUr5mF1XYdsu{F=2c*LT93%)eYqaBx)8 zD`ueV-7c$17EA6LMkL3ieol^ApiBL@+<#U9H*A+6r$(%`J>QQ>X|ua=LX9l$L~ARq zvhwF|u3=BtN}6#9vVQ!?8bX94+O`6KCyi>`_~N4su$DFTWYh)ZdH}$R8w}yTA{AI#prQjX=i-nB$KKj>^;V;*NIc zlWLNslGpnQN}l}V)ud7fntgFqr9ZzwH9^b)y{j0PYd5E<)}5Q|@KT7+JEy%8X1wVZ z82D;Kgx@puNSn~MXO8S?HTo0Vh(63YbyuaY>9*QQ#Z?7f{68z%_cJ6Pz9+PL@#lUw zo*KLL=6zQ35w;N1Gv`(n?BhS^m?BoNf83D$to(6Ygk7f@C?=WE#ryv6YTox{Pg%i+ z`KhTF^ua1EfwXfwtfq8TGOUwe;KBc-qBFYOw&v4Qc4D;L<+F0S6YG<{Q_SFwUsTbO=i|D>1w7K$ITpC;)?aQvAU)$TAV(asoK=a_w ztt8!cpp870Ft;1iDhhs_ymr5s&$17T`68-sl-0Gbyrfm=7d!7%+9xfpv_=8TK<1$~0WA~w zcxKCgY0oNG#H{P@98WmA65szx@#oG08m#%fqw2BD{kP9#=%i@TZ$Ex7aK;{6)tMG@|a%jL8)f-q}a0p^rGKa%5btzs^Ff?Q>ur;2&%^$GUiYRex5UixOMo63|G-*)I0 z@bk^CsfG@6m}GK=k$?8pTIe^9D%}s)sNFfUU#wJAKt;uML~u@ACa~-_XF}kBU$#v( z6fvlX@T*erg6pjvRXT7W_3}Vvr4@aU`Y4J_2wZ-!y`6ca4*IR0+a8r{xXx-_UWFhU zioq)T%O>M@ZZF~Ypd|3_*+$CQT^;+LmDh_k52K<~-GJ!cF#o{h?khxG7W0h6?z6Nz zy0k0n``rh zf(phS%jJFPm_QlxZ3xbuX%G;GhO?GLbvM|p6ts5(Gc7G~1o?KMKy3BKWd|X1`3(Pt zg}*oj`n*f~T)=8prmM#SyYpUE<>`MpXbKm{rX=WM=~ZbauaLnDF|Ee$zZxKpzfeP< zjkl61ZjKFnnaW0#B+pA~vo{Eo#(hV8yl#H{MDs*L`uZ8K=m8~>; zZbg#k19NgKwI>Kc+(}(o)eUMu7QLa(;dcQ@c zH=?H6dUSwxo?E4J0pU_@{q7U(47chpAHf4aJeI8t_vmP3xX>%C_ z3d*cup`N3Zak;E~Z1Oa2!28rkaK>vJaWF_JYm^LgY;`hx7hB_=XP#FG#Gd25)o=VX z-|tsKz)#fGm16V`V{Zj|fik*OG}kT4NxuY%0qdF(_8MP9@F}LKD62cMc1Jex&67~R`v}r)Z6R{0RFM!46ALgZ^?M*`ya$(IxY33Nn7 z*Fpw86r!ZBYATBp6fKNJ5T6g82ysnLrzJ&~!{owe^6f?NK>PIjHpnj>_N=C1|mOeohxx9ywn2V({hwZ{$ldp(;H^EVe zAy{g?Y>%*LhJU=Dsb2o*0o*XM&;|^aCX%#OYuOl^R594YdW-biOM4_M zeo%DaWC+m}3&zY`F#Wk;50^f-R&_9tyXWkXG5H&xRH#n@KK+y6p~bb}QTtWOM0HXs zEj}9NibWqyec3NpL)>wkW0Ehb(5tMUPk~APkyg%JD(Qte`i=@$7E9|+>yff_3sQ+= zf&$6OJWl|vd*@2fVcK+>jf&+MMWwoEPu(zj-xmgDwH33&d@Lbmi3-j;c{iyhGz~Xw z!AT8)9etyQxIiHt#nK+7RTM8ULN&C`!s50AEEGTg*zS^fvFg-j7b1u;ADP^IAwYSlV?cRx!b);Z{iVK`=o! zrBz+w^0};PDZM*8W~>KF`pq)~DX_LpP6Uo%R@5*Y3p^3m1;#^2MObjo;@2oiqZHsJ$V-#R0Tom+ zEdVvb7ccUShp?Yifn)Ie=x5l4!UpvU#L~dDT+~?F*=3#JrxI9}^yhoQ0}D(f1yo&$ zkY@ARBIDox6|gbOE8u?do=<)Ki+s8piRl(M{8U1+_vn5C1v2O+!GtD#UZr1KaE60n zvRLn;54@q|H725Y&m2Z0)*aDg#A>zRn1{lEsj}Q$C|dD$pNm}kz6Eg_GmSB8;dX(y zJ;V91(UA)lbG|BHtM_0}yIsherb-wHXjUfG+!g^NQJrCY;85w1<&6xvBh>REoc3eX z^SlMBu=H>`_gdU~xESN30P(5uALk&Y`>TvRA>{owo&w#u3T;yx_o#8}Dn{=1y&3+0 zQO}5=txwd9MiF3r9r5Y)cVSeIjH(kUahGHawvOb~hBr+QiBR&9e zS*<##l|(&1H4jZVrg~2#%CFGhQM_n21991CJ` zRFNuz_lkM^9+LZAGe_gDG^`?KoDKPTl=*8n!2-VCg-GFF#?{D2mC4b?6P>TQCm3(l z3lKB&OujM{J-xPJv-_$hEQPWAEbIW4&EyNr^*sO^&}{3kCE7x&@Z!A`-tb3KQ3ggSCr z6Syu1cCS_u_VeQ+u5D+o(@!4F7ZS-Z0k_P>=`zAb+Regl2xdiVYF3#A<^$rB{a~ws zz37@lL-5Vktfd!;n+lLiK!0E3%QQCj0t3L92ECci^KnM04(&#n#c(nU=;oS(44LG z*TS1eM)-HnWwl>|l7By5F2JjJnlPv&Q=zdrzb3r5$24RbCJ=&;f5sees!&_Za*mcJ zKD`O+aYCsvV0 z!Z~n!ni3eLsniY!K2}ktwlgDIBg0%eCtbLXtt8{6F;EnOule!p7_fxI%fvz?m%xM| zJl#xGZ<%c&T~dvW^DX;bc37$xk3e~Iv?&peO9&Isb< zU!#Xm2@fRNZZ41TFMQ1+pO!9raWi6!U;k@NXKTkyOia>YnRbl?FX`^aLC#Xqa!kzT zG{4poup8GIpEXcdHYo6ktq1maanoq^tlgo|i3YFIUjAE4S=>-*&F0hR`;>2lq%Ihm1|sO3rxkD`7C`JCkz^P*w_)dH1~wETk)ruX~MI&p}xuI+tl ziVqe696Z39Y&9{1bymy2iHTeHeni@x*Tcq}hry(y9+MuNs)X*HWBjdCkZIwTp9CA@ za{xbS2s!a?NmR23Pou!p(-JpxwR%K_6!1#$aiUz*W$IIl8_#NGD6ToKa@6M*32}SE z=9$s@w9IJY@ph!4ZacEDWzXI@rh^{szJ>Rl+6Ibi^6Lh6EZ>M;j<c}HKN-XD=m z-@=%ijb$YjR`K;6_bwXdi{7XPlMn9r1z1#SRk zk2Y=IX$MYXG`S}2ALVHPf~SpVkgt%r9EBZ{{3T9onFIp$#xb8R|hvlq_>p zaFPj|Z%(_QZ=*j;OUxBi@+Xd@{PDY|O+6tH!z_#JLu-5tr;+d-Vi4UpmabmEG z^O-Su>&=p8Pb-*L@Ung|#FkqntK$LLKPjsRoRfn)GZz6Y9L9=vIe>O+)o5daS3vw9 zDw>r`Pb;?J!G1n(5i%SX>#HYeZkzju-rtD=q>KV9)%kQ|SzQ$AuhQ9E-cl@X;jPk{ z)XH55yQs3jSeJq!YQMXUKHn<5KDsmk7cRFxe|Ym7CrYh;^fM1$anM0S{`cswQ>dY_ zleaYP{!J@2Z&86Fkr#8XUwNQA61o|@bv4*XFf{x~pCsSNgPqGiaD|eM2T{FlS2*(` zs9uSg?Ga6Ypbnc}l0P#m%#LbUD%!NlE|~WH81Ml=Q#^2Q8}j}UBU}O?H=e7hsHDG2 zIBf94cEsLe&NiGbS-Uf`|E!i7;{~JMYhN#&08X2Qi}-B3*2&*`*Hp?r`ORZ4lnaVd zy&diNgMYTUa|>fo+^n`!BFn30N7pekrBWU0%IBDv6`IMn2)LPGZ@>>nxm5Ag%ldVP z&02ipV`2b}xUg|`rJ+19FmUx-6)%%TNSvt zJoWmBt7v-+`WK71Yo$Tr>@MAnO_ya}MZST0O|}LJ_u4*QZyp&6odjMtTWG}_(D$Bh zYNN|{1N2$|3j}_E*p;;DT7X^681%dZOF?nd*>_+B2z1#1bKv+ae*>-zJfFY+SS1ht zm<2oQ9{bGEnTH~aMcoq-UQ(NwU?buW+l`G`4Z88hV%`D@OzyrSFp z#p$=m2=(ly)kN5i{e_Wmjt_RMcKZRpj(`9rJEb2Yd@Fl@fQU~kI_{-{h|Y4sp6Bn{c<-H z9=HV-ysVJYfVoCJs+ym<`_@8_7LleAw>c2sS3@j9tajId_DY4y`>DUrMt>nzqZ zBfaI{UsnP$T>!y1!U|1YV(awvnFFLUA?Uc$CLGl_MOU*Ts(f$erONB%B2O;Eg6Hr!>GnV>gH_!ynP zj%_014*mHZ*!@cRPU^S-sREswK06!3e*gmj>4Os1Of#)k0l+6dj(QT@%?nhnKDe=G`^GTnK(lhhz!VOZVBfA)h( zu@}^?ie&*towe^lO+~)))6v%m;J~NWvtdrN;RfTF!+e0m6~+Dj8#opS`FHY{ip3QZ z7%yg)-4sxsHr8)<_WcG^teT(0j_?D1_b3(l@5@KiuEo)xezcx*%nmr%d`=NMm0nQq zB@`u0tabbVZn_`B9!dQ9gRrd(mjKi=vz9T4>sH1^ddPqHneW+ULdL&FKm~!{Y@bk{ z^0ta1w$uvTM;y6vz8`j(oT*U`!M~{?j_@^?qpa2dA>wii`Bd!^g3RZ&DjfNt= zN5MQN)~^NRA^&^hb*wv;{R~u#$j1sZ|4SXmmMX;a5O~CAlN1Lj zw+q6nUHo4@UHwA^K z5i4f5+6}m^fi*ZBm88l;eRivnE0(!@v+yemKldMC-tC#n!#-V7is}I_B>#6&w$itM z2r4EkmL;#9FUAe?ydW5Sgi##8v7`={r^%dNp&oM1Tn#M5(L0r-kB^-bQ}NSbk=Z5NY%J`rkF zp)on$+)@dX3S@vzhu%is!|45AqY!dok$(eEr0>;*aEAib5}btn0Jn}Xym>sdOpJaX zOkG0vItafUX+q44ITspX1x~$79ZR*}ngKOoCyFA)zm^fAM!((T6I>4!h6;w&y;zCa zx9bb$55HuI$jI2GBCR{r%o5VX6QK{LA7g|hC^X3w67^_F)eAEJ`?^k-8e8qL;;NYde&r3`RG}zS!Vs}XC2x$e z6a!?o1~EX5f_34TWZW&%YD|7SDRkyyPBC3gvtw{iWa+7BFA~a$W>``&vlLSulbQ*u zg?T!mgNj-E>@la+%3dT>vWfvp<{YYlZ8+vcl=SETL|nwENUj(cnheO*6p799u zz(yT=`Xv|;L?|pZNbtJav2q?7-{RW2UEUbu(QkjXV{drhgROz(u>k(Zp^=IsBPNN6 z3h-M%YV?+5!Zau{x!AXM8BoYkC8~HyqK*Armm2YTa^Z{+BQSaRV$t6fHWE6hgsvYX z=Uz*=hNyeuP~P7IfpF5Zj*-$lNB9dSw55^zF@Se>MSp9>lM3|viu|gU$Orp2h}R?P z~(5Hpm7y!G)dn&jW>y>hNw5E zli||C%$xq~Se*g6+7D}WB75iljug~!%LiOxnY#9oj60@N_+tOpH@68>0?doq_bZ`E zLyA1dN8oZ!A6a6T4k}qjDO2Rj1R^Hs;~{wL8iUN*r_(7dQ}*Jv(5wI>Fq`igbYsiS z5zM>}-&!MB9Y$x+->IZ_fg%4S_bU7hM-}DITGt-XtFtN?piYykT7BVCwfH`c>M!zt zPoc!N9}GXJ$Q=SOsIx^^b={BE|0EA6%N{~*4l?uoB+ehp@RzA>69MGS$_IX7t?Hj6 zQD3ECvRi%5@bPM^ZyahExo1w>%`v5_*nD$F86A|3tO0aTwf{Fjw3HDmjlZ2-5*pdF z_{WzAU`Do#>t2EC)!^w{W6IPs5#Gr-HqQ^zd+LqnO zU_R6z$JXu)=3V#5u)tft?6FEvDDy9J&s%M`3$@k1>~;Z*qczbrOFHT+jmh&(4>~I75Oid|vVMDZS`z_o#IApa4${29S2l2bj*)d4Dhvh4}we#HwvJB z3z#7f#JI(0KOQz4|Te>Bi2LQ{I(dNTbjvu7?NS$z}Jwc{!&!P?8b{G<^b@I z=CNx4YAw*_;!-FBW3{I<*PjWNi6zP|m#RC2v@Ld9Z1lObAIsWIVX6H zQu5_JBS#s9lrc9fe>!NqhI2q(R5TWh>e>bu_nIPjwqZeJ5dD!y%I9+&Z`}Ivqxlwc0P_j{3&MtDOxRGK+bJs8YZ+F%<(8}%Wg$~k!rsg0A8M9~Rn6i7 z!OklPvHF;-kI+Ml8B(E;n^>m$$dgY%I%8)5N|oRj{XfvgH3r7&clgkv-3ZX9%KxX@ zqH34Rvbe~B;t(Q6pV}>J^96|tMsNl6sP$kX)13$lM0q2)aR8~wR%9>Kly?a$sH7X# zu=Q-%B<>IfJlWB&Ge{k zzmfOdKvXbrD3GouegLr4^Izb}P|EM&VYz{;YpoY(`gGl3qN6^bc8N%&P}F}^Qzf0i z0hgkipF;4b!`C?qk$p&?96<3(ixZi#w|W$e~Y)=N#jfm)d1hfZTO+W&{7~{DBQydKI z_Ke-K+@@YVsL- zDfBbJ#4A`(9~)JWKVB>41gz7zV+nF3gm_bzSIu)E89~0FM@7ks7e{x-0DB75bRpyC zCCIPiipOOo{E-BiL~RpzUiRfl1wkY?ITvV2hp#L~6aBGNRFtN! z?uJAk(#;g1{FrqG*(ss&HT}f-x7?Cp`*UFypqS*?J!V}WBPM^qfv8eRnY^M$6H2SF znqt@mlkmFWn2`!jQ`vd9DhT8!!O??fc@kXf%`SBK91|4;`*pnFS1RkulPBhz60q6h zX!$3&01M2da(7CS&?~`{(~MogguLS({k{0sFMJU^ref(ZfRI-r@aS{y=mb_R7t)Hcqdq-P8KZx@nFYIrR_f8gZQR7K9>;o^i$sPU?=Z9 zeg-%XFEYm`5JFJaD>##e%jE&)pn>U2r1;}BwX_QJMJ6KzX0L~KNMj{i%xS6w<|M6! zrQzrnH|+9)TaxAm1gmD5s9+db54|f5m%=-xJJ(uUHLC0%MNtbKSLZfSLo-1k6JDy% zEA+s83=eAHj?>Ph+02@|5%VVRCJ_b&ch50UKyIjropdE`m(Wh$OTEOtU%#i0&1=QI zrlTt4EIk@3twNN`Kwct|^=R5@D-WhXp-F#s3G&S{9|ysV^*oXW@v|#@CBdX0SQ_tM zH3|qzMqyQVrLi(B23l8JUtL|G`v(y&7KoRyr+^TPly7=m%h z!p$_#53PsxP6ge=>9_=w)KmJ9+LHj%Rg@m@0muwIW?cw`r_f*vwWOjk_u=okkS0sno+uI@<6w7U4Clk)F)V?+V}YodDUP0yc=|O&!eP@ehA1y z-VerVmJs7m3n|gcR}&c{oDgDXs2-uBL@;JNVkq^kl@U$w`?0(swHYo}5#wb>-cL#q z=*@*z&3Y4@pKP{NUj?kwWmP|?B~o(%{;3bBxHcqvY6QxP72aJio7ih}Q6R9)_#PS3 zw!dNk{I=zOT&@834EVg(lWW|24ggh<+&!HM-HmY-6=MdF6#{dNKVN`I?w9x%fJEcL zSONNz!Gl4r$z3V2`P*ndJ09*Lh#CauD1=-vE0amoM0k`!-REYneU^njQf&D4q`#zO zTm>;HU0n~An5SF@{z~QUmSJj`NCF9dz5jbek8R^H3c7(YhLP?aV6|TJyS3kDOQ5^l zSk@1M*c!8-p1jw-21Kt)inoz?#EFUtx z1~#Nu@*xoT-qnML4pzSLqepA279huHF%e@BIbCMI;llOUMq_NRK-ml9%n*p^0r44u z>TW0_kT|^$_w$-!yF!yU@#+DbAc8C-gA;72k)z||5phpWXT+X}_(-SgD4s`R0^z?Q z5RiYJD%mNstkb9CD?I$o9`CDC@`WTFkkCg2zEXht5FhWu$s>ASLsz~5-;J^r=KyQp zcLT(GT_#Ip&K#6s84mocvQ>M0AlL&vaKwLx?UFAm9IO=wm@^LC2Dd-b(l>;Gd03Z2#qR)Po;&+7nmkGLrE)$O=u;33TGd6XphSBr) zAe*|1-l7TpAc=lWC%+u&mKZ}CgD4-*r-_c;>PpEe0hmNN{Pf4sz7k<8`_GpesXilX zE6s&B@5{SLpbw)mVlIB;=Ud4-5DuMhRAsub^o)QC_mPt1*DRqhkffOJ%y_TimL~6) znQkbm{l=1E+Tf}2A4fA8;b(kJ)C}*?$o@@f<;+GRRby)uc!&;@AT8E*TBwVAZPhm-b z-?#JZ*i$i3Nt^1MdQJbIvE7{fA+GxQBZD^`dci+|FA@(>tdI?WQzojV3uQhNO#PO4 zEf_yuulmJ_rFdA-Mw-7+_@TR@E`W;SZ%iXa4v*2gteeZraX&Q#{VhY!UK7m82aM13 z_7d#XkFw4ecg9j6q}y4q05_~T*kWE_hc*f-K)A5rSJniP7Kwz?Q%l#+1iQ$Y9rKQt zCdW2V#Yg<#1y~mrt(@SyKCaX>n{_Q1YSowzcLmgsBN`0dXmDQ|=CKu25(ueD@-iCc zk6oPYNPL}Q6o85vsrLmc0_jO`xvVh?^j(Ad(NElFBUc~+@-BO@GV{MK8MYy&Xa)Da0l+v(0x)7t^Ci4>dj%6~OWh^c5ci(*u6 zz|u1TEAyzFWT?j{)f})uU9mntVXZLNtztVQ$Ot4|O~nc3Rn?%6`;llVI0+SUW-9n> zdkP+Rl4vRmp2ujxZ-l@$QpD4gP4ff+TLuDJqS<2>S6Qh{@Q^<#{4uK^n1ZPn(B4V= zKk_AN=P=DVpLA%C%sUq)(oGeFF zf52+ZwMoRc`NF%?oYR2|EX+xPteJm0DD-m<4@ZA zkd=|^o;65XEYdQg*_&e|fN}PF4-80KqG4DUz~X2klqx=6@uB`?E zf>~!ahT}kNL!48VJ&pG-cT#k9a8RFw;dGz;yP3(<7v9Cbk=yDHIB#^H?$z{4e zr`nry(sWbx;OzIPL!ZYeSqmWKrb4Xf*E#@(6kXkpecwbSx3Vd&lJYK= zod@wb>1Um*H10;>n>*nJ0z2GQ0c>wGFCLF%JR05vWs0t(0qT{NZ`ZVSV)b$|%2PsX zM}r?Qn!N7#0sE(s3P9G_7}d5p0whkT)TR;KGBsLhMRNY9pCJGae6f`vHv!iX-b7=* zJZ&k}4!^Drs6$ez=0Y@(iyslTJvFcdZ%L z(!U`10~Ff#nZ|*a{Nhq;C}?r|8Do=b*bVpOvB?t=0NbVp^%h(@41(TT=GOJruAC_-VP~wq zTc{P&u3K{Z%}NRF0mj5AK++ee&i20vTg_?*7z~Mu9VrlydLyf6rq&BoP2$s+Re+Nv zObIPmkj{&k4HsM4UUyjy`#!t#t!d6>WI}zVY3|28YD^M?-jy=P+-zFnIhc+_OYf|J z0dg4uQ@^1i*2Mvo)+|StB{VJq4`y3Dh`2pjuqyA`7!7XLn3GoIqb)j63qf&@jw|+4 zMW93M1sh60AKb_q`T{yF3kSd41a*JyI1e3wZUCqZNUHh#PY{gk@m_JqeI;a}R$nXZ zTgXE6=r51th*M+U>M#3qxASNx6uv4;oDV8ErH&hp7NW&$&05^QjagNRGu zN_H0zZ~bqLfXH1f``YM_C_%Nyiqh>n7v{vg>)btVYYTST>` zn0K|9ah;>E$$)zj)x-n`Dgu~1?fWoSz}M-v6|J;x^+ZYOLIGj1`nczB0H)(uRvZr9R1nG1c8*u%yO(Yfp{WqI+#O;_i%h!(#n2 zHERIFQ@o`vu?eauybu!EM01bdZpRLtYocu4*bO)%Uk$|7(JhH5eZc0I0?a6d84?1p zZ+tFmbKCHl5z14wU7gkXr0-zMJ8QZl^^rQMSh`nc4X*&?j@P011`tDIYvfZWmZ-Yy z`=J~(+f2R}`lHDNM=H2ezV&XW*b5{bYg&6D@&XGJrr3)8?zp_e; z5sICstw9u{;=u6QEO1g=Tk)b+e=-mV;0FRZD0OC7C)KBiSjhCHyY&(EOF$%NsF3de zse3H~-maKH5Dt75m$d*p`OUlX>ja!V^YtbB1Z*XU78P9zV$<`R>p*Rsl9itkwVkMV zjj~AIU20eszX<+2dOG?NAW;y{ZJ^Z@k54I;mw!~w2$9aXdvgwRxlwTa2LGcKK;iJF z`+}jQXT%pEELFp%R?02$=F4@{&1I7yki1cOFc7S85e65ziD!(?V$CqU)KJ&4sN~%J zW$*LyjDOxcd@M5amoW~iu^H%F77N&$*0f6W9uOg3bBvSbA72~}ySi5gj=q;G0~AF+T0IC}&PW0Ef?PuG!rU1-ls z#HRy<8(oW<|F$PwS1TK^tq-=7+abYTu6d%tR_$q`rG00fn%LkV=L&C8W-k|`jjyp? zW+bn3F~i?^F(%75a)yi4G)I$t28G^+Cc8Z&Sv%1-{u}ofz(a2=8_IvDfl%dGaIFLv zYR@6p!CvoxVM3S-sN0rHep$o}>e?q1f)Z@!76}C*;AE1GGi{hRJ!tA515ffw=RtlgFt^ z!e3GR;@eu_sh2i6a^s0#Mnlod>f|FFp|{|j+%UZ9ZGV342KL%Z$*_4$>jH3zGEfD; z%J)=sFRik?$bYTA)9%$}f?K|tX}09vx&A)*GETdj7vG17w;f0031jMf=)b%P5NT%* z#Agills$U1h%uggeo@GMwLt6{~+)=lGBtgLQpk)F;mQESuJpA5SRoxt`pRW5{85QSY4OndZ({Ccofbr-bfg7QsNY| zU)d+DsFh9H)^r&1)TRX#hlYAg`hlOfsC@bhN!zbZ4BFafd;s2I0IlV~RJ0?#>pSLN zQ1Y3YPP^gs6Rb}7-%X@Pjx?)M36{NEPtnPe(1X~3S7IvN@a-pE?Tqh$}7O9FX;GK%9IV53k@po^UR*E zgT5Zl|AWkO)VX0R>N_)NZt>G~*q<&=+O2~>D>HRpq7HT!5x+P{PyOQ!1l##zD8(4qa*;3 zqbzUFMFE>j*+bRP-XT?ee*k}dVq}Q#ZWm62xAMmrAa4BW?4MLoYvn&c4fzQI-%n#i1Jsw($h)xn#GG>EjCMk_OyDc9RYMzp2!Lm;m;KYj(iyvz;@7n8CXCPO zmO#9(v+^9G9`&y{7?PA?J-{&Zq*RAl+3o(Awq%P1owH^L1 z%qhpnHUc^*mz0wQx3zWs0qNz8)q&_$udP7=cc1@)WSK4Go>1*ETbZ^pk@g}JBo*n5wJ=| z;8+tk24w z#{|;`l#(y=A~*)9KPoK)2}V|OyDchC_$#CX0aS2K+V}{P&-;N_wRIJTrp9GVg9E0p~6oR0(a%8P$M6(| zl+#!aM{IFkfn6n~!rGiedlXd`2OjD81y(Bsa~y=ErcwHMA*SdsUWBFKTmX+3*KoO{ zT<{RMBigb7S>}ndS0?1bdNn!%@}#QZZ5*YV%bLJ#(j13Ua#!J46#Ij)P%R~c5m3-? zgqjx7%L@mUt2ph&Dd^+^Y(0?i!$}UPEOv|h<>rX3E|&e&XK{{)a8EycX5jO~_OU9D zZDT=&@>ai8PuN~PnfdMp4@--`<&|XjpcDa^^zDCnIhF@KX1aM71$-FLSo<9b7!NLc z%z=G7;R|{r23B$6{3nZVULbDs%^Cw3j_&b(%t58M3q3U;Cbu?fv!AC2yg?6BLb~nhe%#z6WB$M zNd3AcI?z~cophY~sMi`f;7A$Fo0-}`|HUN9N^By}2W>=bFNBc|q6xbTw*=@_F|a-! zN^}V`6WDZ1Mp?O^`e?22HQN*7idCGIWw1a5Vl8+((esu70T3k!0)tHVe>A>53u&fw z3*-RyXnd>>1S1mtj#I;AtE%S!M>MNE&Kx+T!50r(UF4m_=QDXCh>qx7Z2x6-G$e&6=r8L-Z>(=b4$S+Y;b>e8Ou&XN`fQn z(@Q~Az1E#{;L`x}V`&yH5tmRw zj@ib)%pQzt0V-x_&8p4yZNn33%a9rnx@i2qJvTdD=2b2TbpuB+e-45eT%I$`?3-SG z+5uJ#FCOnTL$p~U>qPyC@hq1Y=;>ebRDV+)Va8GTXFg-t2>}!|H8Nm}R2d`m0s3|! zgBR?JRecL`H-~(ug#m5i_5R1T+X2k<)P zd_VLuH)A;%g2yUSWD}2yc0K~!dIoJ9zEZRse2?h`?4B305*-OM33b~m+@mgc85V+d zKiy}HA6Jz6QH;h@Sn=Vo%m(t0D9Km70ROW~YWD0J#>;eBjQQrR?`p$p*?nd~6&8bhTXj)`wQb=j~K#?Kw4(OXtoLk_V zqmcNI)9TY0EM9Snoz@hcGzkq5o|?Dt|Cl=Sc&OSp{xg;dkI^GbC0mbehX=u@OTb;~Sb{RtI3-5#$R} zDLQ7#L|D$U%r4cc1WXrZmh1^$7>A!HDg>S%0jDh`#Df8`7E zZ8vWa=H2=L_Yp-SKD7<-%AxMEW2JMB_i1aXEX{G|2}_79$CJCzj?zQmXysL4Ad)3F z8mTG36e@&N(;-$oYml#Za`acr4IZ%|@-Ko*b1SKbZVD#fJ#Q@8b)>*qaC4wes16+(4;I-!A%tv-Cn|ny{C|goEU0j36Jy*4$VH7r)hxS(o2e|xu}D?O!QI*lcLyUn znB2XbzLAct+~~h)WQJEP5!~opk-t*m_Ja({x!Yw+&-iW{(ofO6JpNP%pWFnK=#L@2DTh>Fe9tS>?la&+Cde-hEyAxAPxxpW9RwEBtLty7 zNJw^<#Q%O5H8=)MG7f~STa|T8NP6{+rvCPXsEKR=_UgXrH*Iwl(qFH`^AC za?Z<>%2^+4Z;NfqL{D)z2``*+T5&ozLcM^EPKo5c_=c zLcv2PAHC8;P{IkyxEpq#3h$sXb#w+RH?9nD1zza%!4nNVzNZuS(s~5D1~r-WIDRXx z&HZr{YR_oZ#;rH&xTJla0R%|?ug=eLpZ2(Uc5{&b%i=J9COhK_+GZV>9t4QD?ycdx z;cG0h#p)MtT&?Wt60c}Fr?#K@6^Xhf-h{WDH>TFRn8%vqI)e#vi=H!7$m}rCq_qfk z@6dq1lCl?)bUS_G zNFp1tyK1uLTa-9vHJvrv||HkdBAhbD>Z64L--y6Gf{%IQ=snxt+%Lsc#3$ZW(bi6Y-wbl}z9>zryEjscdoWXZyF!qZ zNAFvAF_Ko|2%+bXo(z$xmCHZQs+!6;62|FT?JV>~zUsAFH(xMkeCYYF^EVsfiK5e( z+~t7h)5{!N$ag0&xgn&fD(0}Zj^ON-57b(LiV-9I2@K{u>G_53+d=KP<8yS(`Nn&1 zV)#cuEsm@wsWr`SYriSL`NVkjx0+0X_})f=|AveRhj%*B6P^1GH+?tycLqa2tt$QN zP`9&oue|xY7?1h5-C)abP|F=eq;|se#GWcN-3G^shzI1_Cmiu_u~>x=i`SK~lOjLW z25!KO4L+0SNDqED4E9sf%u~5vYrTiT?ev9iq~@_A1~PIP&cVtO89m`Hz$!`$;Xs6* zpo#Bg3Iq>$PoOtBB%H1;sYUM*pRQXA;hIH!H=x5gR~)WvG18d^z{Urk3W0_{@2!0t zd#3159TSwwLuH4^Wq1VPdM3a3|^p)yPib z)1?A$4i0#VyA%lg*CjtQNjJGwz8TngzITXyQcbN<4N|X!nz%;)>3OF{N|V<9MV^>tO%e{@C5HrI z#ZklNt-ER}$rqP$6*UEUm7heF5*k=3eM{L4hH+x3V1ywp!Z?QlS^)SVFFj%&v3>h(@#Gf&rfEwEBIC6Z~s_# zns3q7GUoFLg`OP)46(0|DBnef*lp?&U;lT#hHeanCt70_Zo zsc1c~y_vE`r#S{#U|q$0K|8 z6&L=jX<~mnADOBdZ0mQyg~tA= zX1J*oW5P~XUU>}0*U8_|eM(Bi3iF`vWeB)D1|h?FItb-Zx-yD;(^%hDx!H&Q9{#BT z+0(59tKFw%SK3>=raw+N%<0I#+wa&XWgAkt7qrnBetLM2(EnoWY6d(=>g@(W&MxbG z-=vYABf)s@$D0cmJRwR`o8II7dkH{Bc0c+iUOVEw9V~u$cCA# ze+g-b!g3ApA%kex{cA>N8o4_6z1vNc$pL}bb(_bh?}7t2RETS;aG<6?>@6>;5RDkpa9vTr!&?Yz)|@S z)YPrhHMT&7Tlw&%=kw2zUe82FHbec>;vBpsDwp2}BMIlqgTh;j5)1aoqG}baQ={|? zjLTRO&(CorIv1S;jXh3%<2NLTVrD>hjuVc4J>^;Jcv$aYsC;!=?nPA?0#Ps;(r_+j ziGhn?Zw-OmGnun+88U)*0vt?lB9yR(6nBQ^PwKb*JpT!Ir|NiA^HTc0! zybpS{8uq(jBZ$ViMUFbml+G<`fUz-rG(HxFsd;q{&)@=4@ZZ9Y%l{QWX#Z{MW?lVHrgHAN$r?bZ zZkFKLFk*1uhqHaT1hjx^&{?A~bH5*GAH9}l#Y3g}@KlUsRPs&%;>!BYuzj_?N z!nqQYK@o88sOR2Cw=`gx8ZQbMW$~=Pt40l@d^iotvwdFn&kiu;;zz#i@vDm3-+^Rp zr3#L6d&HO>5&Jl|)Cg(zn^%}E7ZW*rf>a=dz*4B9&mhDdm}Ec^9eVzXg^aOTR~{po zcy8Dd6JyUjp(FmmCnDMJA?ouQ%HfQ#Vo&!0!3;y5h(?LGec_1tg0 zZl^pkCfS2W6`Z1-Z;-gUMOzCbdmNZUzK{4v4nQ*Qpl zme!)mxB-H8xgxxCYX7!CwpAU-r1=6Uj)>G)_$?o}ZBTBkX0Mcp&I8#=ps2z~`D3## zIN=pkmkT(`y1n7pkjy|@xyD7Zm-AF@vlEkX*Bh<}<#)PCU#jlrQ@CfPoQQm0p0{g? z*FV-ZX2rS)Oy@>bzT_`)zdu)u@jm9J+0K95J(If#V|y%fe?Eg{BV(+Ra9MN%o1Ejo zqg+A}Jr==VP{QZI!!Bk!ybv9Er;L~H-{G`BZ%=B%_UFJ-O?WhO?kb=ZhQ7yU3h@I) zm1+{^Js~6Srr5@R#5GeVLZu}cOhB(AoUt{VAgenmpXhAU#arH_kdwe};h#H`;O(c9 z`3SZA*fDdQ1+>>pivp2VYZ)DtgnOdKh*(6qWD5cZriTB>Hx$Ha;No{eSl5h3z`8Ct z_t}1|-EG5v5H{39{e3)h_y5{p;BBA{@5go#bNQ6>HqqiLyHc%pv&ms6dDuVJQ_pUo zuUK8~nY=8_??x<^T}&q1WzOYWG0@fnlSH-Nk&VvqY%eC~9nEP#J3eZvGI8@*L_>ZF z!GmXkMY&)X@igBm)+T+2^!Prl<+iIZReor#hCIbxl$h}BJ^#2%W^^IO#m*hu#IHTP zu~op-~0f#G)h|jbP=s zNkhYVR(GtMs>x4Wc@}21Gxw(iA0kQ_Z+J2>3X(fFoDceIw7K9%7_;TXa&XRHj!Rfr zKiy3_D&}{3y3@?SmcF1-K(w>zPAJ9fv&%Hhvl6m#lFQpe7b@GxejG+zPoGr z_Y94iw#;(~+GR%Pv2|=l$8zTw3BvFBZ#ZYV6=ME*q9gd5Wj3cS8Qg@m-vEB8I{x0% znG@Sp{BHG#eX- zUgDfhw;l_VWrxQUpqpd9n381|(VEXrMR9=AFOc|@L?fO@`D;mxdkL&ge&7PrsxhOD zlUudt1hZR|dprQ<8fJZl?p1Gxf94GV=%&`@4QiK%61#6JRFQ4Qd?hUM2imJ`?xn?; zZ0|XE+xs8fonvE&kt%86XrGxD6T7t)xe>D;ajIA8=q_3ZUePluHb9<6LER*(bv(o_gLK$$&{RsP5u z>iwXmjMH%yDgSL9pxmLBkyR6V#VFs8L>bJqzQjm>Rl*4tQ%`S^e>7#>lgHaY%BfAj zq97$92dy<;+?8GFP3+U?;w?d1V5N841C4Z_WUKPnm2R{ZsZvhIp6o*Jx($o(#*`=I9y-Gj4h(D0|f94ApJ(}{FcaLxUPhV*-*@m56 zn@cV9dT49jZ96n&E}GdJPeGwllT+>R#_s%lFw={RT47<>O~d+>*t>AO3PR*nNRxfH z+I1AD8hoS2lf7`=+19?qUm9c!kV8ZL2B;F=*4?z8pS{vh&fyCqQ9~v`LNs1*L*Ky( z4>0F8-YhW@esfULA9j2lth<(eQ3nFn1+&YLLvJb4OKb6_+|!6QgsT?IYKPMkAH7rx zr}^mY>P_ePSXLwNj!E!QNU3o%g#xPtfeQ%_;oID07DwA@mFNs*N-x%R)a(T;K8%HN zWfqURz{1Pep&{cSQCc9_*{)#Z|3DilszrTV4y7O7GX;Y`DyW`%aG(r$TYYc7*>5n_ zO~?Vo@1XuE?4`N-fnQsugpUHFnJ}FeyWluM^rdzemT+ZtF^_+=@5E=0*9B1dgsT|$ zQdw_sM_jWeR0+FM|LAusUG=tnFl#r9tF_Brr3=1Jlr*c_6PLQui(7L|tPTByuNo(w zr#2bGI;oiT^%*R#r(NzH&A61Wk@fXk5>FgK_@Yc9b-$$4?Jc+iXA&zHN}!VyCz%kg zjmheA-`RpoIg{na;=28$?@d}BeG)`V=H-B-)cx<)+W0mnco$WGS0qA?dmME zob8NYjk97#A=w6A;a0KK^c__J=Ti6A;l_sn2!SkdjP%}OuG?KXmnMkL)NX+in9gL4 z3oivOTP~zts=yuiiZ0+g6Pex1%Fr17U)}%ca?xw&u23lxL{nv&8^>x-}_RXGrCirnIz23=es8f#p{03DCW z#Vl)fI=pq>NE=PDxT*QC6Y_c zt&CZV2j&%AD&6?|6U3-reb&Ir&MX*bHM=LKIudvuNxHSF>5t^N9p6AAuE=6aMo*r` z7k;lxpyG|I+8(BAC;?%*XVP_tzz}Cyy*#d?4!9Nsb5}~nDl|^x%8Gz8%o?0 z!|bcZ=eu$gCjplIdfbu!e!o8Le->fFe7U4jyPCZhHCGO_uO&E{t@}P!>NCP zKvq-`ncEB;%(${Z=n(R6asjrdvv{j)&vRTZ3F}vcl(%i;f4T`C`e^Y#!k}0H$IJc9 zCP`sIq3Cp^7y5UDz?ZHR2w6K2ed4f;9UGpHdVfs59qty z+XF$#V}6$`$sFO>f5&@=1Ho8&`Nxc*hPzXp*<6?VzK2G?~l(AY>@X-<;Z2Y`a%)H|3r zTqJqP*|=*|bG3EfZx7H?SL!)>C(}*9yi{cmNz+@wgtQJD$ti%S+ZTe|uij`Fok1Co zT^BVXu%Cbd9i7F!JRhV912E>z!if#W$`I_3?s`u(UfQ2sCt0^e$io<0^xUv=v{iXD z3+MOBFt=NubBH4&*m$g>FR8x?OyJCn{{n&D%M_Lp2>{R1I&>E+#f}hy2f%b)WbS*= zB+?x&aC{*!XNJFXCIy-EY0+LvQu=VDD6Dr50j7m{gaA7X{$n`h;6JXRf`ra&ThE{1 zlfyP)lX1u{mVEj^#fp^Z~+0Gh>uaREPfJRxh7joN; zX)UQ%BS^6mDToL8as8?_Y+08^eG34Ih@Ti^R0mu@BW?aavDmv%phw&Y)YQw5Ez2IH zGTxX%AZ&3q0h~~h?T;4u(zxRsf%NMXs<^iXB2aii4Hy)JD)PL5cpAQbf-!K%cSl@p zyvHXHSJ!`wTduqP`IdA6?TKP$_PQ|KjiyWQ!8EGIF?w2{7jb>G;V}-3%~cA;bxw7V?7nl?P}yolU`D~e8;>OX<^L6^bo>6{ z{LV}Y0JRW5m;yxGoYRWlTlYuYOcgnUkh&8zAnm4#*dugt)h5uAQ^Nc%qSTW8@>!`2 z2FzAWNCB^ItMahqL&?*MkWCY-gF0mU3};5TqXQ|8$V5vShL@XS)D3WJkgkt|iGw_; zjmM`FADiYJbyT_R%sz}j4|a#|DENt25B#%f=@@m>keD4^j+iP3fMTBYj(+`FISdKr(RIR~9A{VsQ!I5sr7ns6#yz$W z&@rbxpTz}FL6NTPKv2TvpQkcJ&15bLH8SH{3C_p5r7L^hKr#&F(xo1bBu!?x zVE1(m+KeFIPJj<^ywYTjt%(R`$%Ra_88Skjk^t*klDGawkK%OuWQG8FO6);iqk4Ew zz)4Hl*L!$=SX*hoV0wrlbzG2a!R6*~PnY-urS306)U__zjnOSv=Nkcq8B<;dB_uD;^62>BIHAMZBK z>BGsSn;8|)&aqB@kP*iR38rTnR`#Se86bKj;4pm9k)w9O5t+01WLd;upkM*m@ zd3UwR-uE$=*j8tBl~JVs)EAa&Bk>l!4=tuy;XLTbLHb@RTOBuW197;c57f%epEVEL zMwA8_+Zk&e!I?7SF5u$BroQDo;%}_8rDV~EBL{`FBq_mH=4$k>pXI1UAJt2q`++4F zZpK}W`glJM*KI6$5DiG=xNm}pg7>;K59LxGAl+4>eB_;I0Qcp(<)KT9YLQZf{0|jr zN{7z_Dfc^4vsf_8L8Mr1AVNIwKFD4jla~R`JJwt~6 ztFxf6itnuv0BlnN;4%LTBsEqm-2(^a&M{ZepwN5vd^_M}8RMwQmrn$OooZCU&Y3$d z1`a@8tZOw}2q^X9-ZNFSmJ`A}I~xy+XFe0y&?j#(o#7M2Sze`-c!D^h*3CiXjHz-q z>;YSuV%n)Do>1V>*Ec4HolSI(k9jr>q8r^g;Dg2sfup_hC&x3q{9$pW^T*+RR-q>& zv=xFkLd?6UtOYyrueal#x40W_KJOk?j<~5~HVRoEB;sqeoNIa)_#u15P%n-ae1a~k z*4-V#iLG+Z>obZS#q3`wBA?g*VR>c#8{%;#hcnuY5{581szqTX&2~5es$X>PIDZjJ zXCNu2w%K_8iIVAYV)g&mAJG}ga6StSy1BOVy!f86^#W&4CDXy7#BK^x7HDy|l6C}% zQg`o5heA6?P|~X|;1z{k8r+h1TgY8=}9x!SFJJLUFjKu;E`g*olU=Ae>R|HW)O2XJ(D=?7aZgOvRf`7#<;*ym|8>*wH$0KC|s7*T_H z_i8Zb{VKONpLuquHE)4e4kROpxSvgwD~ieO;c1(ozjHE+8o0nm88qK;PZ(G)RsBlb zaCug@?97Qz^h#Roaz83%EX{8PP~Nps-d8~u#A=Y&i&Vj`kcec=Tq}@851+4;|9fKn zf?fbBFA!-TizGA z<>-B<#rHl2**1ztDXun#HHcie20^g%%$F~}lbp_qPjn{N4Jt%E2J2>%T6K)ZFB7M; z@yD9sd0z?zy7XLDd!a&r;>DiZtGO$#_q_3o)=Oau5i=+iK$3L(45l3F)ES^*dTz~D zxxgxTMZ1!Z4)D4vLWUD5!UJrttl#cUyp5zrAB<26eHPpt@n; zZQ*8@baueWk!<^$!wR6K09P&g4F!E~yGswdEJ)8>awf`06&)j6KoCinJ zFIy&cV&Uy_|C$CUd7}o9Vukp-El4gM8-j1N)0MP9hs1x7Is&x|$3KtQze*wB4ZXi^w`jTuv@&B|p}SzS zA$%*5LNZCRidSfPOzMJ;XtGEqg5RF-#mpqJioZwB$EDntg{T-5rUU0~811almuHJ?Iwf~i4Es$+#Kl}q(RJBmMdvBt)UM5*RRxr=U zivnv1LSwu4f}NG*EZuuJPPjzS2Xi;c>Y+khPS2NfjtM!hZTVPV0Luch<{W+abyJ%dDY!( zp98yB4cNV;`4fa~y{2hX-RsU%D3HJs>il)9@boQ9w)F}QAVT-(x`Q=0L45=FVI8*I z>=zO}{boZzkU*KVI|rrd3#I+GFU7BbAQ&Pej|0#>z+BHPRAqVjfoZas3uj6(2=9H4 ztLR|J$vY%L_AKVf1r$~gd>&L}hTP{zg-pPUIEilFPTGFZB#f2a6hRnBu?X9BE05{; zBUBv*h|m~vE2dZs&R^IBGN-G^Q)HNw+xG){Hx`V6KTuiFW>K3Dl!n4R*DHOdM8sZ1 zZAB!_f!KjFUR%+tiTvp!i_$g*v-(l`8I`#1oIMclNLv!S#4wKz+__Ri7Gn9@*BU(s z?Q|MkeOH;Vy4Lc=#a}c=-Qw%=g8m6$!ZHTnHD(??zd8WTkcr#DvNsg5banXWb?9NF z&wGD&n1jG5_8JBDV4S7|-oFOi26gm7%j?dkqt%caKP|R07zi4na@tWhS|L>P8c?0{ z{*IJUV-fk_G$3v9?nbs+g2<+@-H?$`4r4dY(sdIif5l|bQcbj(Xv0lI+1X^h@rj<_ zGos()p`WPqva-Jj$m*T25AgZ@Ds2pknB3z&d19Yahe0(>*dK4;)t?WorstNAXT&N+RdlghPWkT{ls5`hZ z6G*G0hP52agY!r&W?mjFG1Cwj;`G{i9z0!61(t>Pz^C0*cR>|DdC7b zrj)*;E?sQw5&y1is3?Icakr2RScLobv#T{HFQi6CgTs3%#GF~HDso0_z&ggG?}^?& zi=Lx1yk+y|*M{n&W(T1D=z4~G;b zYD`IG8kR>4BWxtxWhom_72(|%{mUDC$#Mi|ABwX*Ef}%Sgkz|_L4VehrZr$PkbA3&0`Th>b-ojA>T9#wAK z^IVDvnydSrwo>ywcC^+VA`xOTy9G+4d9J-R`0T{Fz%qYnOJnU|zY=TIfgr!u7s@U% zk5&GSccY@;Vh*67a^uy$gYct^Z&ty&YL5o#JIM)5MA${#-oe72xh+>}?tU~PWrx)z z(4|ydZisGfRIUoLY1*t37oV{E75|N)vIU^V9eqSJwNX}tnP31l`xWUuV-}w2&jL*g zZ;?kd^wIoXldDUEFq>)3%Jr!!q?}4sL%ItWywbVIhg6DgBs_b@-!|wf0Fw5QWt??{ zSw8)MO{0CD+~tJXM))R2d%6DXj;(jF?5hTi{Gq23j7!))iK5vr$sbSgcs!<*9*sDb z&*B{OMB*2{ivRNI%%{pK8*f@ad#2oXISSw=Cirw&9IqGz#pay)KKn=~W z+il~q1?|B~IscB+nf`^C(xW-g^6M0B8sAGH2M}qy$^^?U!c4n>{z`QEx;3>ZpZ&|4 zUmn&8O@OswYWjKtbqH1gGRIKF_~22O*RRQ>x z*SEW$%Dh>O5qzRUs}+6rkb5huX)-Qhte$_5bLLhS%=cbwwpK1tZi%z@Xu#SVv#%=f z``xmxd`%8?<(Yg;xn~=3Az!$`ri)z6zIP8qLPW&?=)7z8$pWIG4SACatU30c|DwZc z66C1|2Ew+zCl=2S9TM8fEyw>c4pu>)v^g{7bXi27U8;wo5fWbOp)#=H3%3~~8PaQ; zoqT(~h^CElF3d!7~LDyvij_fRv?;-;G~MEwPWw}rG@$~OS+#%& zf?RaTwH}iS$SG7K#?_QjGtG5sO%SKGjyT{~j z>xg1b7ybQ`Jmtp~UD}vt-S5*051jcAG;bZVoJY@|chDleSr1M>cq#$>Rk+1}e1}>v zq>pY`=t+%_n$}%R@FBj|=&EKl)?^^P5df~dKxakeKG=uEGjvC!#y61CS`n4J4Kfiv zNLTrS1PGQtaCE%>mY@n)%_tu(gK`VtwibGes3C4^TcQd5lLE;%{@GKDralk~h3Qgv zw%gy;=&~$r{8Se^ILfR?U#Bivf@vwr4|AU{_FdxMko?#)@@b@{cj0%f}9xz#2ebh+5 zEb%fQxUdQz&&BUxHKtYgmNdz0<%zk&!x3|KD_1@o!Kkg2P?r@4W;CA75_6;0lpic!XTL#&<$C>G)#cc0 zNnd!K10Vdpug`U*@`FODpxdazmK8wmL)CRaF4Mg)Ho@pjwJ)2`x6a7-+idxKcHZ2% z&6~%5FnqTOLsaPXYz;ZhC%vdV>obhx?;4l(GP8Y4vb?x%N&u+UIN4CssiwKyVrmZ* zy5IhDr_k1xK9i;eg}|T(PlF^{`m*rD_a8@nH8U~115 zG*D3$(3=`PfqOyiIJH_tJ$^0C;{;W0vc$+2dup{5|MSS0$RHJ#^6Kr$nVcjB1>p?| zANwRnCQbRyVoxRO4HCVA_%fyQugXR1Htb>dL{a?4rg@d_)XTG2^w`Yi%LNf z$X&Ti&#Z?PTt7@Yel-bl<-EdTmwBWQKQ+tOc51BJ!#<%A`^jfHEI}$T{R6T)J1>3k zX_l<`VOsT1kWBsWwBD_8&#W%NWYyecDwQ%>cU3RgoQScx8^~Y=rN640`+Q>XtLfQu zSdZ$%y}kI;lXdhUWjBKP7f1}gZcy8a>H7)HeJsT*s4$nX(0B~$~tn2`{gsq z&10r_&!I0LE;~UrSr?U2(;j@#Kmmd0p=9uPwV$4e6AVIBzhvjQ+NxC=;_#;2ZYsCj z|0&`fDow6Lxk4SQAo%sB&Mx4#1!Wmmb4B&Z|A(qP-F?o0a@1g?dy$p_H%pk3?-cQ5 zTDxKS#^CSeWg8n%?5|5!|6HPZWvfOv+CYz~?_uD*x^Y3|QCWXwtq)43W_+#Svg?x% zpA=?Y^by>_?JO*{tzk^9aRtf{{RP{~c{WKr8ANI?Po6%P(A^KWL85lKy3Cf$=DYpleb*PVc3^xJI*!_ z8uKBvuv4iilSE<={$-U{;@W`2rSbHkVgQZHt4=YhsOgzimkXe3G3AoSD6S+Rv50lp zun+GxNjx0XZB)sn+9$6((e{`+kUE? zlqT6ngGdq3JrOoK2DNba2SE@s$)Cfb7jG+7hZEutL84f0w_37AP&f5FhlMs%Ny=&; zZhQ2w^3`$9pH36uD=F=`+T(x8L?dBHH!`=Ib9_3T91KDC?DJ4HQ)tW;iDSo_Ikl(b z(*2ARbd|a!0amDynI>!~{6@dv8^`P-kfBhg$e0hm@#^?S?d%hXv5UWZ)%j)CtlI$R zGJ)B+twd;+BPqxjL&)~p1|3%e>u!y6VPD#4zQb-0*s@y<;1s% zgrG*&3*hSa^x|ZUQG?kn`q#g5CKhMu6OE2ApUl4LDU)cJ^Lb;?RYE!MM0TGwpXPwqF(IK4a&PBF%E`IDD6uW%AN(u>G1lURVex$Wk zn|5agVG7Tm-#T)hX1g9Owt5Im-mDizmKy4*bS#JwatT)X@dm9>E0oz1fO)w;hX-kN zxknYv^Pw&)9`N>f*{5Sns99RLKXWRD(O{Z>6yyl!tK*FQIj7LF-DT)I*dA0LjXtCZ zcv|ZGJplFsQV)&AmaY5|26%7srUt7TRRG@pVeYa=0dX8P!f`vqBw>a-dfuvJMe`y4 z!*mE9_$W$ku~3`S?E7s(Mvxi#9rU8;T>-z?)?jEe=VEI)_BT%RKg(vS$Qv#q1pA|nPfaY4G8|@nN1gsEc%L~{9KJzPsn@YhD{;yG2T3Z;> zK0VQvy1ed~A!p{NvltRVo(iuF()GlL+<5)Qc~D}>nfr74Q(!aEc(Aruo@&BN46Y{= zfd`ep?@vJUzi_$(yOdNiYy;#A!oPSyxp6S&JZFp8^W6 zjDyhds6oJo62~d1|5aj^?pAX_rj~j0=eS-9eMlVA8XYNr^x;|pw9*y}&zv5~n!;zO zRB6_M9DR4!jgp5?oZ#lZuEKappA*WlPkw_!-1SpJaV7fl-W()}woANmB|VY;j@G~5{s1xn z!FjRu+}yu( zcZ2Dhv?CdU&hTK4OZ5UQL&3(t1YYjxQo!XpOEo>Xj=St*en0{&no&&1Oac41b=WPz zZbfxkkB$l6G6^#XBCE4mce;){6kkrSgH#bgQq=$RY34X<_N7DrcXL0Kxs~I$&gLAN zT3A{G#<6m3(%!AXbvUF5i+XTaY->BnyYb~W)izB|G02S>`+`WZ_JSlTM1ASHJ9Ttr z;&GlGSaSF|@LbW95NB1n`B>3OhNz@<@c36 zl<*!!z<6t!XH26H31vnbZj{L=@dux`)~Vt=LCXP85d( z-%oJ`o{{SZ>L%UAfvRD{vo}Tp6bocII>`mj(VoBFFEONj=%a9 zP59)kJt40Sg4q=YA&P1KT^t6BQ@Xx&6THJLw2blAy1^?4-pl4pM_L1~C1Y=P3m94> z*O!Cck)JLDPq9@W5FTVFJdA%yv_0b8SP5D@?n;lroi$cui@NTr}kqvsoVs>d>PET8~r%fJR(x0X;ik_jA;4`Ut$kc^(VJ?Mansu=^`oGO*sbH|D2)%b*g(n`6+dc(8! zEu$iUvvnCfSWlm1w;r!^SBw5j+%GA{{~6DLuNgnB#W&uKNh;+TAI@O=ak@NVhC9$N zsC6F?;=KLDt*VVjdzjvP&SJKLmUY~!M|A+7xF;$`BkBavR83h?JTCt5SiRAQPnd)L zANpM#iH0aB!|B~qL30T$QU$|=e>s4`6As-eGd@wLqn2Zh1{cqoxcun}S&IzaeMCDo z4}R3j)<*BeNdqXNub`+g+)stGPBZ9W12yA%Q% z&t%7F2${&}i0{oMF|#xxUza{NAm%nYRA#L{^2Hp90N8vZ?h#6q`Ajk%AY1<8rLui8 z5E=FC-L?b;zf8Que+nNT!VJpLU1FT>=3X=9U)7xYNvxl4l>7hHB|HrHkA(Ncc&~Ib z!ZVogq3;xYK=pAy9TNib!hh-!G7v;wCnd-K?bgbiQwL6MS3Pt;5r}<7l;5qjzp#utscwsHFvlh6J=0Gk!rO#j9m;hxsIw5JA}D2<$T&bh=Fb}G zM*)`4?XVXw1uI)pSD@%}wFjl)zq-7KUPX6BJfM?;Pd@YTaxp1+vqDh;3T`!-*+pN0 zVwlXNe1}IE40E||F=Mg~q-6v+JUOex1ALM$OG%G$}+1<_*+Y@oB&!^KDm3>?} z61E8jA~SH70nTJ?0=odkX`r4=F244`5y)%1spEBD&AGwMLfH)Z0g#KmM(>lh%yHw=AZP-I^(Qq^Hr0jfdbiUK6L=Ua{hNc7y!EV92TnkC--E2S;m-!+ zAY%$*6-WQ6IX*tzXKObLN)jnk;P2&m=EggYKxwo(pAf7=rG$ZERjxh?>Qe9fyFX{1 z6h=2E{>1g$x>J_N7OKp^yBW3)&dnfBhdiw}Wju|$P~2&o?YWsiShzY?ZZN>0lC`(= znqEhxPPZPZVFKtjPI6-rc%Hgu*ylsltMtG-ad(NoDqMWSn}4nw=wU-i7mmx{6CS!T zTZ$ykq=z+?eQCGX{eipr=wNRISD!W#Dx+_0G0s)i`+c&b2WIBTYyoA6K34R2DxY0m zvA!z1rln81E-lYQT4^QlO;D8?FP4M36drWhWb{oxQg%T*wC^il1px;)2Y$&zFz_UZJYRQIBC0I@{+=nA2_*%b zTsvTIfN3TpBok8&W=0Nn_sp%r5X7ymZ?u*4uSMau_gW(9$cc8f1OzaxcVn7g7bj}U z7%2tmgF(B7gfc#t&_#%a@39DdSEVNi^mRyjSV{^) zN-I}$N3~hIA^ThAJnhJ(pQy^=kxQvT@Gr$;*8;F{U1cKR{ICp9cKn1Gzx(?ov7n2g zzYw;yVN2(SptUddy>L39$D4b2>en7^(7;68&O$-O@wl@*$!&1Gu46tT6Q@%24c)sC zvX?6Y@hgLvgG{uSpFJ`IP)0g!DCkfpqo%NLYS`EFD$scczRN=596-B?>d3|#;a`Ld zd@}NP*0w(SZ*p-IDoT#W%?Q|iM-3O1POtyliGZV$O>ZX`f7Xx<-)a^^30FWG)6T#t zXt??1OitdM!wQ{xF&kEp)z0DauuG60eCem>p_z{pGq~r?HwIU`r&KN_Yrx z#S!m(;nxF62C{vSsVv~daX}Eriez`AbAGK1Os7_613w*f9pxKt#=RztbhrSaDX(px zq22^-O_d=kE_1OQ=*gM=1R7S&>KAxo^`eTvhmUB-O@0Uiyc?3E=m+jQVrVe)vlyS1 zz+NU#@PNVNvz)U*J(H`-u_{iXF)v=N!wERga=uzDk=l9$D8jI$O9jv7{_S{=`wC?o zP;wA*6d^AgbhIjP-5T5t0JE&q5y+OZFbPV_#{x*C!syu>gOgq`-#EtJExsGG!{@$O zIVNV6eO|e!V(FI^0G+w>)2yH2e=@S$z@B(I??qMGYpm(0>!HkR#Tcx;dt@g+lpGx^ zMkPlF3WPV?l6|4TsWrQY%y))ou$0U=hSw{otGB^BEPvs8@%`lKoR$2#G8;a1X|EmN zBeww>$HJik_9dGpGgvR7X@cMDJIeGnmR7b@iOWf7YU6kI$kZsrfZX+EU8ZMod1n49 z!@N8ue?GtMtF@E8N@;;8DnJvdu6FXwpX#SBr@P6wy?JnD6#9vX;B`aQGOw3srjCV5 zQ9;7i*Zd-$3Bhw<-jr%-PZe!wBip~UNjJ%3(&4Oz5MR3R@RpKa+2?@AG1-Psa^0J= z0n=SVvA2uRD6onHcWYirLPAnKfBpz`uB93_WE7lIF~6VSUkct*=%7jkEW2Ly61C6t zT+{Xd;Ifj4iOs+svpj|@wNnuQi2=yUyX9(zdk8VgW=u~7l4jrWj65PEG;wp$%R- z&+DdrPVIU{SydG%E(mWndHYzKCS~}LaH9>nGRUm9{!|#g9+&=3f-*@MM;oo^; zhPn2!h$97bkc2hL))zy%C7T1gj?&98b~~2IQ@}{Gk#SHNE`f_oCVaF>Kbkkb*wn!# z;+ZL_3+-jiH*EYOA>e;-LA$`J8Wzp-x_I10v&Aq(~f=MqkxExH7Zatl#gC@`y=F;o5eZbCWvP1s( zBav4cPG^7n%Z5|-D&LgYSZP9C@?yD6MjEU!J*<9c09`PG16VC4t=X|N)Qujd}53ZUr z3&$SNQyE({kQei9&#&53lWO129r-}FP%8y$IV``^e4I33uG>O?y2b*J}C>Y=xCLO{?@#Ou&sqRHFOKoFXz$w z_@ydxWeWx(JjcbLKOd()7NHV6u$9N{+zqzdir+pi$u^sj}ch2bkBG2Rc*)=w%1D08m#}UhO^Imapr> z7r`5X&Sr;~bw9dsIbN8Naug}}cY|1Y?pXeSCtU8)O?+OlvF>>q-33l(Jxls+qed3> zHuU9k)Lv?N+Bw-dH(yUR43AyPGGVZ+hkbdLFIXFgN?4t-HGekM_q<* zZh@1E+o!zw5wS}%1r{+7_;aS`&cO+LRg-Vcd6wskz4Z^9mTKGYA5;Vk%9RrfWCA?7 zKkTjS%PlFp)Kd`crc!aDaNFg{k7tHshYjQigN5_|r==^8hjRP>_K7ZImoP}m?%oPz zUn6B5OEnp;7VAjGScjNoO%k^x+hi9KW-!(+l5SZtj2UBBwy}?~rQeypzdw9l<2+}7 z&hwnl=kuJ;`+X##g0G+N6?2Q@@UPn%(4#S1iKp=8kgCa;Xl=z?j^}EeB?Gu;_G^_D z%XTbcwj5NzT^K&%7{j9*ZJ*73pK>!P!(Pm$$3-At!(rtqPM-%?xo z)dG^OKtR15RHHb>br^6P3Jv(cXQ=Hvc%|Ffy%RheOfR@8uJdb?jj}K27wQmQ8=MLF zx)=M?eiutRgu8tLx>tm`>&$bND%UUJkjNIEt@JB8oX8(io#bnqMDecqv zQe5>&YMimPk|r2Vwstbg<6gFQ8<2>MSLz?g#ool2epGpYR4KKB(MkMX@yNVveQ6yh z_!9{l^Mp)`XZLHHT6DPkGMr{)-?_yCVc#JN@*$pFq7 zs;HpOpRMZFqY${MW7l@04G2kwjyavtNo#APn5MOQGhJ_ z;+KCDQMYWf>jS7;MMt&YRodvqv!s|G!2R`{=qv88i$S5Rt)-NPi*tOXLP>cj@v(Js zCBtcpS@swN8AGsUFmF{dPZFc9cNK1^)q{1n;Z+tQdBHoV?Rb2tA>!oA-_b*n7lkWf|QYI5qKG7lv2hZH7(5N4Lo6?@IO)BQETflb6E8=od&l2(EsahY| zZ#+l_Ksm90Yt!P(Sxv!>`uCcHz7*$#NF5sz|H~i#g$znQj>)$HUZlk7Ofy{PVVMmA zuN_$Qgd|^TKmJzWu-4+&?s&j!#{k1zbI7kz+!~59P>1EC54hx_XAxF={G-mD=zB%J zVR{XNRo2y5IXWe%4l70hVAeqggyfL9a zOUxZFS%tT*ruj<1zvJo!?ccg3`a`NI3NSk0{RMGd@&^t_Yw~*X2pxdzlEb{CY$KsDw(l>k?lsAM**%+DJJvVJ-6*vsm!v&V;lskSU1|9U_c=; z4W}~Fgr6C@`@cnhT%JTn_^VMfhta^7JmIBS)@AN4WOsj3EIuQ_ zEu0wsO#rsz3Xg@XEN1J4PP(@U=RYD^j|#vV{MtqYx(SvpV{gJ&YRv9E<*QfiUGaz~ zYSZXIrqcwhcYJToFezOFH)J@(`Lje#_ACbWqLb(IpK2oO$-+#}l9D?*FK4SJ8?l#G z2CgzozeX&7*w5F$)P8XNyIGILQV7S9`DB?yQDTL{$|R0BxFMj?q`I;!mmgt1VlcP? zcF#Yacs5jUtay}0%=VN>tcA&^J#;X37sI*Vn#5I?9CQJ8`jr9uklR$5KN#32afOZ# z#!N0V$LBo`a^56t;U>RLn!TZZRUP zrKQhYGTCG^GjLiF=pQV3vAFN_K;#cb|Kkswe=vOLeFVY#7uPr0t{K$*SOs#32b4Ga zdyY-QV5nHY{)<`50^4)_I)@cDFMTIh0dU6QuO&8U1LIOd(rQc=p!z??i%wlF)vC*}&-#;2cr(@epZHgE?A;;ewULw+quzf_<-9I7>pJj4 z8CjeeYYCllgAMvcKb$d&F-etEj^QFr09KzpuMGA<$-yiHN13g{!Orr zWfj_n#fIisTc0KmOX~gQ-j=<~=-7}ebE>hme|z@Bs3cXwj$UtI(rnB9O{8-vMJc!& z`Jn{YX2*Ec@t-ZJMkHuCMcugs&y&jng3-7j(su@rYc>2^4VrEpH^t?ycT-_Za(~Mf zeEwEjNoffw*_hxp4Jq%>0Rh+GyEO~z*ciP7{*-=!B(NDOPeJ%XZjk6)!FtX#TYJJ; z6_RA-R*GrJ#dv+O0=qz>OI^3-v5B&Wp|Rg{YGN2EIl(0Wgn1*RyR{Quw9K^|v0m=8 zL;(pGlXMkKa;?)&D@~OZhQ~s39S&`a>P3Ju(;?p$RR`;DhKtQ|5%lWeYg`3-^<_(- z$u~{F8n;R$?}lF7(-+&beb)dlSOw{sTfe(9EqQMqYbvMclnbt$-C!xDcQ1fnrh}3W zYeV8itT8I>lne6f2NHix$;2Ea)uAsUb)64w0Y8)r@1@|H-j}pRrPJQyWlo{7{W;J0 z+$%R0$7=L@nvMi``SXQe-)5FYO@XDXqInorWE~nSoGTP3YSUDVTmBb@6{@V}hSVSj~cBn_YEz(m%U9Hbg^sL)JpxwTaau;{0XWS|np$yZ_a}bLe^WLTEdu9iv@Df6WQ1-@$3ul?Ns(B`M;f zzrF%7x{d!TZ1#$OyZyLB0`OzE?j-8*5snuz!;~fKX-mEhf2g^FI%rwHsuMcYCmkzm2DMZ zirlt%9_gIBa>Qy5JiR#c7~+XkB;O;6ow*A7*SNLRvA#kvsm~g>@kh7T9X~c1%U1XJ zzj!sveJaf2W0R-*bkWZnAa7ArSd2TX*!)b0y!QF|83^_=Zu0IlH*UvdE^t%fj$8R7 z38g8q%(W!(aOG7ukN9f7L{}I2RSp)dQV%En1JRhbdOpUr?%&IqYaEJ^lxM5(7Tx?u zu8%%l=3W7zZ?($u7!BL=cL}+F&d-R2O*`^8wVyO1U$v6WY&m*mV_`9}B;{|};3Y>| zld+a2>I#rXrPB8=x~*_vnnj~E1iM_TJ4sVNMj)R-Op{l0yJQ~UZq@0>FHeke?}aL( zkN_Mq7 zF;#RbEap;_T_V=ZT4~QsF3DB2;xcNH!>c)isS(&+VwzhGd9N_|z36Lb%vq$h4ye%` zC9gEaQliaM8|yBuam)~LJ4hiZO%SG=QZ1f-h=?M|VQ_hF4!ybCzYxfSVFza-;3K88 zwE#Ky@~Hlrqc6dDGkgw&XO`D+|NY`5xs@lk?K#%m`u->b=5*)n8B6u|cnW*{t zLVK&7mbwYACWs`~e+L!V2(frf%$U+hYr8DD!Z8Eh@}DFPd3#d5JzZ~gUB0%?u}iEo zSOF5``Lp$Ro(SE~tMDkr$?xu05)ln1ha2JA$0jOE?_t;726hZzZbZTSQKyL}n*kPe zh(`fKpAdR~+`UJ90WU7uxg3TC(V{y)GsufNIt?_LPxGmmcmjT(Hi;(SHOD8>AwfNe zQ6^6T(YY+Zo`5h|r@P`1| zdl}@ZObcQqD6tZJ&#(%S=nGxH3`v>-?;2KRIy&T`xI$VImyQ+qT4)94^HC;XkWk&^L|?iOF(}d zpY#jyztNT2EUHC29Vz6xt9ERta>o}dM{`Ka z9X|YdcV^^fT_yrG$Abz7eiS?Lc?+|0AHpy{1;AjXIjJIROKk|g-}os(A9-pJ2)4U_ zmLjqxfMl6d!IY4ZS-hi%5W*!b-Ji`8FY38G5fMkT_#> zC#))4@igcxSOOkPL+j9ELlgePe!W!Xdm5{HMJ+qkf1gzR;I{83pROb?ZxlC~L3r@} z(&up*G{J%G>V)*KX&I< z0xQjM+7*U=FY{~cMVTE>JTO{O__KZyZ9A|Rmr>{V$LQuej5;|ccO2LltPTU9hd z<2-`m*Q}&ip!g?NyO)03U(jNop`qT?O2xgnU6+HMS2+X z@H$MKqwF#5y1VQ{r_EmZGC>1Yu}uGQFZy}lUwgXnJbW-}JWS2}{;A@i#pONa<40qz zY|tNHv2NXt^q43)fSH|=N3&+K?g#zwvkF6XvK1&naZD0DjQ9(a^yL<)dCTO|{vKN) zv}s@jBIorus$*QIHV+Owhfv`b%zfcBVcyZ)WMCt;om^caL$DJe?^t(I>*dN4xi91V z`C0bk-$o$7D#;6Ig#in#vKnd(le-&<0bh)BHkLTkAY|eegS}zb`!r~b`Z^z+ubn8_ ztB;)M$PED&iTn5cX~x0c!EMWPv7pKa1AV}c7ISJ1%nYxrwBrda#h=Z-V6^eomhZ6> zYCQr&(VzwNNrQ-S;B38Qr=_#{d8p5D3cQ^@iMX#=A&JEcn67ZcZX@(becGPXTx+Po z>ca0A%yY;1;mzErJl~gNI<+t0i?Y|jG|y4OGShqw&les~?%mhjh9BXN8XKwkAu+dq z4jDh2XY?a=&ZJziIl_?Hrp6upuPkfsl%tnnw#vI**onSEg|Ml<)X5Cyw;%1@b=6Qn z$*wR+g}}%Avdk9f?7G`tOMoH6auKqBfh$}1zvY6H>uhHu3J+iZkO7MQEVp|^X|+N7 z2&{~-`l|*F7K_EDRrbYg`{0O&O$H|%44s5zJ?=dn`n>r`MczT9cu0_w0D%5K!eglh zCn^nw;$ZnPyS4#3QlfmAT^%=hZNktK} z!(;l@d?v!&|6uY-+*V^K<{Tg3#~6r%4Wz;Notc1qN7HUYwYbg>ID2{y*z_Vx z4-AYCVb9!Ug`#2QkD&G+EQh9Cn6*idy zydlouI*KU^-Xdv+t#N5*$!4sMNRq07HD)%j0I+Pg#G~@My_3m1_8FLm2L|sjOJKnW zs~AK3o8$Rt;DDh}j|eI$=pqpn$q2 zmI^Gr2m`Q+Q;rXEo?9(=#bo;eRDp&Wp)tdk!U3%u(;$^7C@mfEz*pj6G$31eY^A`I z$yN}dMAJ8(hYdLAArFkS#g9JAmc8lNK?iehpA-4;yMfatxHC|00>pdVEC+ydG3~!Z zfaD=zm|PH)Q3|;_rch2bbN&JDwWsxjX~Rs}!je~BpmoEH1bn0W!xv`9)c0S$25Arn zY1x5B7`cZ5rY`l!C8$Lm&K z6I<#O`+7hZJNmNwus+^%gd-hn{UDy&TryH=P6KES+H*f&D+|T{GjxV|kQ$li`G+{m zr|=!un6`h(*>h$Tmwxz?~ZINK|5XU1_b_ zq~GPja`V2>o~I|4*X$7ON*FELb~dmz z&>L}kf(3C-Jgv^6GKl>Wq7D(jE`tCu+k(}KNh2X);3a5Tmv7PK$G(33gthvj$I%J}s{JhIn%{|ysYNMHeA|GoqM?*UA9@Aacr6rB1s(1#Ft zu)p6^Oy&;qPyDmC)JG%#X7Y3=$8^2<`t{!#9y!COkAz2Q+^`)|~cD zbq_E+|1sUD#nm-lfdAUfzS&N*Ug0nT4DvBp1>GxFk9YHA?kn&stI92 z+so!o$Cnp^X8rsN0b@eLuJv8jdGc{BpC{_qDvp2SyR+>Ew3aY{avPgksiMNV7V+GL zyHV^v|0g*i702ly2k;nYwTzRu&LP85SqPKC;e?QCzTGc+9O6vh-U>_;Vm$iS$gcy< N(TbJ%YsOM+{|9+wF%JL$ literal 0 HcmV?d00001 diff --git a/domain/consensus/testdata/reachability/noattack-dag-blocks--2^12-delay-factor--1-k--18.json.gz b/domain/consensus/testdata/reachability/noattack-dag-blocks--2^12-delay-factor--1-k--18.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..47362ca268565b79b48e9b7c21b378922035f78c GIT binary patch literal 31591 zcmXV0bzGC*+g3pll@Jt=7^uKR1XQ|Jkd*Nily0P9jM1Z8L_k2Afl5htj7bYfD>-4r z=MNc~0Etj_bbev4&l}s#3CRc!30NZ|vk`Y-+>v&e(#-#Ma)_#*v5T zslk({JnzhGjoo?7jZK~Gkvu$4cx=Fr2(PuHJ^VuLSa%`2Vw~B$JIN_!IO9IsjA3BW z3&b;DX2c6>b_>!8^zfsxr&_2gxx(46!XACTaj~iQzdao7s;v__lRg_h-gQ& zJYU~EKb!VBHUvKh_UD^zJ}3L<6BXyvK4;SB!{?{xXZ3YwWarc8JCU8|>pu0z6OUZa zlYI=l&Q;G2BBl9GI+KUes;!PglU>~U&)=MQWqM=PUJ)){cXjM1w-@VD8CG?wA*c*j z>1))crQtpyJx1yT?bno4r+j$NnO6Jz57Wd^h9eV&UG|z0*1@Suzq_8VCYoC^dOF*| zm3xos&B6ulckKTH_dpq9f0ML z{JDA@@1$-#x_~)5j$L?dzozxuaclqs-_fgDpYVlWM1#TJTCSe&oByae{8_}TE&X)y zG|{g*`01_s_3ZSF%V)YeK>NyAtviTpZHD1aJFA9Di>3YX>FY- zk~KB;?tPzg$-3`j!qO`k>S%sH?Xvo8S4OsvcW>h2nd(ge>MRc*E4HrndabOZkz|4U zXJ;CJo+S|0z3VN0zLDmkqX^77J1ALLjIYX+_wtfnQfAo=imcJSAi1=BtXuKs`y%Jig{X z$r+xX`ilurM|czqQ1|R>9<3LJn#-b2N?6rXINM)iTrHzh)-AS3&$dq=v$p41erA>r zKl>7es5=k;>98|P#Z2pCs(KEO6flDQ$M5sqRQ;@>bSbhS;_SfN)=)g3vEj;c7H;2$ zlJeAVY>;)r$GUz*v*mFu>Knt5rs}Qc3(I~c45+#hHQ~7-e#=~G<_Owx{@SC9rKexd z6y8*Cp4>;2zT5kt%(^C)dF58A`glV2%aPJ`X{it8$;|eg>+xD&*wJ{WIK*#LlC6#D z48@^-_s%9O3kSt!j_m%hAnxu1&n@M2#)cdnA+v-zNybhZv^x;n+=8;6AwBQ{3OC=DCU;F!5Atr0lbY%JG#vquVDW1#`0tH_4;X9>So zg*E&mMNZul)hqjP#_~Fs*m+>lbgvY{Xj3nns(G2FT-s|ra3Vu!G1KvAg~dI)6Lvr2 zGE<+tMr+%Dfvk660(7>rVI%>Uk9#$*FSVXHbw+F|QZjB<7`(lawg&w`pk4pZtkJuS z)L$zl^icvrs?_Y@Cs~(PO5vjfkGM&0Ly80w9Foq0>bhJa$EV*@-whhyl!*ju7I!^T zduN=SWB*ar_1T9OhbDhN^C({G=}zJ*2kfH}n>mtjDO%2Gj^B;La=9i416M?H!U$YX zd_2#ur)cKoGNkU^dSm2#rPPE(n}sJIC!_&wdngnZX-fsUyes=eg5u#p72|&f6qI>l z={hBL`HkswS!&zxy4ymZ;`e;?V@&5Q`}81_(oFxgxb;aCKTQ$1xL&*W@^-T#Z5XDC zj_DU8TY|wISVn_fo=n1RCWTrv5w9tUW@;Z~)4j@Y!DqFMbG#!3E#oD@+Hr3qx_@3N z?I4f9JsX;Qofm+5`zq^3QJwxB*eBopTxLwWyoOZC(-by8HmOpbl!qmLh=W;nRVi}* z_f1Q(#c+XkNDE(*V>F!9hPVa%tb(6HsRNode!*~!NlfK_ez44Dey zAN$)5+drJXqtGf7`>IuvlW&YOc5Z&g?Gh*WdtkWkyNSqi|JniWW^$SpGm2)pyympq z9$l<97oZ9ZdfF_X@^DBE`J;!GDV3%xLN=d}gRh4_@K`uI@^iZ+4~Dnr5N&wcM*eh`{G+? zLI~Q7f}uFrDsj-b;RD*txu?{`A`vJyw`Q<<14UUrPIZZC+o$oqXIk$@h>b9++(bH& z>1sWac`_fTtugL?4~VyTTwjCRyPrZ*@{DFo)b%L-si=$ zCsjg0{m_Kor7nw>xw4w5FSn0-7+Zx#-WpA4qvP^%u0vnma9rG$*@;t&~jyz0O$v@CTL!v)cN?AXbT7XeJaKS@g9_E#O zy*>In4Hbd=1TH-Fp>(-Us(^6?tV?4>)yC+X;Emz@o*a#pH+<_SMJ8(!CfP>{Pg10e zPfVRx%1wGv?o;P_1rLM!p&#?R@|@3g?p78HYT>Y1Z%9rily6L=H+E@Qm@^5N!A-22 zr7Ah17|fG}<^`C9%5wbX1Q5*;l|gqiYZ%T#=$qL(=K>MUl|u9}=P<4_`a2}5b`jY^ zw&uDQYFx~4O_gkNhIwyW5V_S>2^3gO;0)+4S_qL@GYJ*)xV6t!n>4rXMwy7*x%Ax* z-eK0LsfDkI-fk;CriCd2of5 zUqp2;#C6~750>?^NeJCY`ChO`;3hewU zh1#^3T+07xM7b3Z{^gIODT#KtuK&ruJG|5u*H*bv)GHj~0PX|jfzSzbPvE(+Xd6)} zv|{Nm-^75s;u+3XneK-;6a!h-b z-4}lc+ZC)aWIy{-(Csi2%(8mF_fi@hsto2o0-if0F+E;$CXK=q=%AFb{OF|-J3nQzZYT6DifdBUIMiJ`vn)dwpwvE8=Wgr#QL$`FOA$ zk9~ur?uwo6MrHS@$0~)#sQd@Q8~1Mvu-GqmblHl#L#Kl&*7Qko8DME3T*6L2u>D_Iu)}Kz^R~4L?9DV54-GHV zq)TIe{zRayT@y-8V@3iL2lKu_>%@IVN~BjCZ@3CaR+;*Y1mv$$YPqbaIzFii$7SqY zc;t~_GBWlU7qM#nC@!g#V)7lLSx&q%&;9m9z0Xbu!k^S+gyi-b<$#N=9-n=qp}^!f zO6)L1)}E?N2CJUIa*V^So?*p(yKSk=E5$F2lq9Y`=h}OwyL}(=H{5PjwKfnpx_9A5 zci3SSD=X|ph`hK9=CIaRoZ7XQMbj4LLESYbx)Oo5e?*5fqhhEKAH?)FEh*i(5|iRX=$40>fSz{(mduuP{T zpz+R3B+9>F^||EUBoZ6Y$ijrzdn9;Uts|U#4Y#zVuPDCcaxHnhGvExk%QMFpm8SE_ zVVHI670+|@`emUe$*X@Mfwr!oUl<>7bItez!d0%?^gfMo(drVWCF-`Q&zQyhtqL{LGh$rMLf6xMK8&$UQIo~xDMKHFY^{!$h6 zRp&68gFJSm+V;dc{$dfIS*u30QDVdkMoVNWSxg=AB$BIe8hG1WwRrzX3EvRVkf+Uu z4jJX9jwir>-thb2BD`A(8V|F8Ss~f#$3jOVSdgwCYE6~#=ufM-tNTXEX>J=hl6~LL z&cIt)RS=*_{S_=sgae@~87IUjo5Gf(g}?Y00IB3bZ~G3f3R6c*013eb3`SHBw7vJl2dGTO+k^n`02Z%~lS-237l1H>NldL9ua8I&Oj^P5HHqd1WWmNQv>DP6o*V*0$6f0@+lcmjx z3w|m)h$J^7TFIt2Ci)*ae-Xo5yKrij5-(>Ol?o&F+DeA}m(Kf$ZNjhR1{V~miUjij z1P7ZR^p+lIF4^&0-MRX4vqCeMLG@GdQ{g{uM&gqGl*|!aR4W;~;ST;HYGTDUkc&!` zWR_$?UH7S{2&8ij2JRwwv0@bnd|{=b&P_y6yqIZ7*H5)H`JGttHVZ71as??*{k@qY zlm$0SY4Mb-vZ9#+!GdcWVKQYEPYGhdHH}ENt~rxV=T?!W{r+++cOkjiuiJ0T#=y?9 zK}z0pilm7N&bZt_=R)dsZ2jzZGuOt?4#ZPZjHtgEb3_E?iuS+29YIr>cb}nU_$>f<=U*IhjkQYo1YL!|6@~=WgFwk;&a5{PzjJ)ul*5Us^69>bjAXaTZ)*>)^OR zCS!vY-OAEcCnr)9F?_~fKgneTr?XLvSjq-7E@LUe;a-qKh0ASR4yCXM=tjA}IIo@) zS!{qgi#!)8Rv#2@Mfd2cH-j-Ysp^rmJxCP7e7WQw7v8_xO9-5AXceRjQ)zE&qUEY5$>9QT3)zI_ zKP5M}cl(7eUv=3nB=$+l%aaM^#M61}#~AyocZd%9p>yk=z%nj83Q_kZNq$4rH;3D6 zZ(BH>1OJrQFu;PLA2x5f88K~!QkAKNFv*A)OB3CZpD(+7aZB@`KYr+?s|s7YM!;jR zfdrEr*)&1NykEw8+)v1uZ3rgjJ1;lBHFr0%;KC>^WXLMNf+Xx;rlorD=WArQI+B=2OAgwX2tfXI~G(Vdrt@E7S6 zEtyTZ7y-*>gI1>WH~tJAo4XMsnVmc*UNSq7*FaA5ec6Tzoa7<$HqK6J^HK3^it)kB z4SqR`gjDM)I`Q9kvUqx*S!8d2qxJZMdv-v!p3P(_R>ED&y?2^)JlA&S6dan{pEwYz zvUG#fSu94ZL=oMi46{`O_R|+=mEHg3XDE8O!aH%aXDY4?29<#B<*WWM!LCW~es*|jT3Fs3|f$hL- zH65Sq3z_ta1q`75&^?n(*-Vb&B_7=^O@zqstjq0k4#>=`6c046w#U~YnbM)v1gqHY`U*`3zVjsGYA3Us@+sHKAtVQ&0k(a97Jbt&qnpd)_&xWl1F zJD(OiyvP{`TQSIPPNZeh9D4%0GWrB|F|LA`m_K*~v8B&+=-?iPPC6Ml7Hb4I726yxHz(8nx66>u>ry7`nPNyLe^* z48~Z>Zd`6(1}u7qdj7^cXE9dsl1Ow<6R)lD_QO8w!4A5;66x}a>&bs_%f+G8SC~nkm^x`G+rgy<`cc~9@r*lRA(NYP)|;sX7Pk-TlZ z^m~<^nA#w_RV1gQu`br%(IBFM*VbnBAs7IsUTBJNxh#+MPt=EfPzoqK|8uGugUK;G+J3aj&|L9lkAV;%UYF1N8ICYtUB~b8irCzuLZ5>Li+3U7W7} zoV~C?KR&(S`sfI&jc@h<6#x+(gz=!-)oVD%%PW{Bg<;^>vk=IZtUfLU6-*igw=}+b zVN`N|HRyEhnzw6ENlB-Qoj&N5^e-pzIX-RVVl@9-xA*3D^Wws*^`MUxLMw8 zJs?>Z?&411u%S|~#P$6;c(Wm(&$Xqlz79yRQ=c-D*A}69A-ISv9k3~^56TSgNNu{@ z1}uvGv9&S?Thx}z$YMuhdk@W(^+G!Fk=qQ*$VwNYVA&0N-VsHp{^5GEHt@eU_JD)D zB%|lY&6}-2zgNy(k$b=v3e^fpi&a;ACKpJCf{5SM2n(zwC zIUD!ZfP12};9b!M_+Oo)%fw6Y%LhV+Ljscc%0eIhZKVn3eE9*k>Cw>a7w{}7JgE_e zUb^{f7C4x_y%KK-3E;P07mhu5CQP4t8Lp_fyL>gZ|23YN3 z#5dj*1K`@8lGfUU8Bf>vJLq5h%iE?-?^1-(8o9Xd73{Tw%y%%pj=eOc2L{_3Yd%Zq z>~_${)zX7Pe+FKKCcH^fL#^=2^c=p%t zrubexf-75Nlc<``U>Y4{*;sM;&&3p5gT~`=8Eanzs`zu5k_Y5J{2~3@lLWU_acw9Z zRe3XpOOtwiB8S4%FO&ZaRnEaYS0TO&wS@@h?q^w`A)0K@NG zavAH%fZM9M8vPh;9|=b!#p0dwwh0BbbS6Xd=5a6 z7|vITwdLo_Nyq9p_Rt`hdiis8aVv{Y`m>DwW*vp6s@;ug{?fO4r3XmCk%UkcX^Ljj z?O)~0gs;2=m!%ZskT?2#AiQ>gl3%VWSqEEkcdX|V+*Y9~AcBcW4S2lZ20=qR0HiLb zNaAsRQl-~Cqe+}RD{?;&`d5SB!&jcU7Gp=B6T=87fsMBsf`mL;N?( zuUX0txcD7R35nM?2B9?ZljL>G#rO@J-`ZnZXR;;?ntluyw)Vxqk%ZT#gnsN|He6mr zc<o)07E26@0+m-zf3>OvlSqLNW$> z4qp*>-9XncNNrL^z->ic6Ry^b?evE8%u_18r6&UUnbtT*GDJ0t2p;EJH}X`tHBNnk zA8I;hk44Y4p<+8w`u3$vyuR>c^BI)qbf}Et)6N2X@cB#sENRH7=yn%^HoWlW$J|& zk^SKS&&X@Y^-l#hX0~m1fJMj^b_R1Ff*w)>cR-i~@XXV;6wgW+$1OPg*fQ#L_rEOx ze>&e7w=H7eUOejg?l#cLS&0Zuh^=TO(?`%X0MO=tP1+8!TSn>bDf{9$gH+$^k;%&L z#kHO$oyBcGRvM)XMcdtq|48&4v#dOcJf5$ls*DHp1Ung}J98EI076DeT#Z^k>M=f1f&B+c6@!Q}qP!m_tcdiv1*v)#k}zYt=c0 zWV-FNS54pzEvzn4P^0c?xepLqHr0)YHutuG+G&t^h2E0WfQ0N*?nPj5B)Vb!(3Af8 zwr)4DfmGkeyF*j5s7X;1Zg*xY37itx(y-wE{oBXwv~tZ5D3WR~#=)%T4aD}LYJyTu z8lZZ=+*D<-M>Xm7&~D6=ryNvAC6O_8Pk)?il-m{|aVu_<=rM(?JXsAdX)D+Dlbj=; z=2hKDXggIVka=|JJz{bCU)GrgXg(3ElywQ5tHIvna0RtZCD1{DkF9RH&5|eWifpWT;{iNtiNZ5<$8buS@v#j|+lSsGYiN-eGRr zX#3D~G+dpdQ0SzxSlqWC`l?O>zGrbrGX2{kmym+WV5H2Il|z@F=E}t^)lk%TcuD_Q z&z?q28sF~pl9np@J7M`T80Sop7Pds~rP=dJiKvHM!9irr)H_QW&P&4H>8l9QDxX$ntt}MS$6kG;>@;bF#Y)syn8H3KC~>| zFl|2PCSnyUs2Q2v%5Q&BHT?0Lom%Nah$_W?(a(74$2wlF1b8>eiwPZO5A5BOKyk67 zU3c#Un`@D5N)yo>gr!dvU*^ZwJHp-2YR0;S{O>|mNB~9w2)i#yO&S(UPigqR{y*M(mWHq-1Motz{8RFXr|{XFXE2}_~2UKtRown?jrtYY|_G>3O=s&+RuZBZ?2B1O?{g^dOYB@zYOm# zW244R;8asD^Pg^A_1ro=(Wkw~rgmZ6c`j-4HO>1qkDG;%-gt|p&EMooJ7Yz8Z7~ap zC*q+^jFTmCE?Mrta8z*X@}I4%|=b<)fh! z92x(SK}B9$WNleCkS!GN60X1OECVz_yRm$CED0+pP4Mfko4BM2BrEK(v%Gy07~+FJ z6|Rg(+jv~Id$e}`H_^u5;yDB6$RIGU4d_4;XapS@q=Cl0ljHT_0&o@c7fnZ5?fmD% zjzbo}wQsj{tDYYHcprUBAH^kM=)d44Ojz3VBq!1FF_m`zO!@{jme%|7&Xm@WfnkBq zAFu#4>R5gTd?_P8USq_5Z14qJarHf7;6q@-pMXl-&Jc?;_!VX}QB1(|l zkn{|81zr5XP*Lyn11|DPx*U${Aq6j+dYdS0qE4z1g{Z|T$0wv~Hr#J$nJeSoDcOrV zs!V!fa_Gg&R3?9ODW=5*vW6umA30N{%J#jbE7adsYm%lvXIh?CWY@PP@K&t=-U z;9KSjxSzhkgz>bu9PMtpUE9{5=#?3q*4i`os)SIXAFJ)vT577!blyL1PiGJ9rI8yo zpx?wih=>AF7*BNeJrL7_j63HrpK*ja0mPB-c-|RVZ9(#X~sL{gZQJ$jr4j{{w#Ye8^fX9s7h1`#Dd_Ih~^O_3Rq&_@CseuaqlXE%0{N-2E4se=fiHL z5gS?Upkd+n6CGr#?PKHJ6r;`){hn^kMETygmty!PeOpD+%4)wHpr38t9qZndx~w|a zqzU9}bmXq!Mme7M)6Av)o1H8$upp>;DB8#-s<;AyJNi%ZCdZYVgi^FR z4_sl9=sXlI=@R?6B$S#E{jT+ekjQA+1XdJKK8Z5RR6gUvLZ8s;3ZCdex*lug(j<<* zQx{Mb?z5^G}mApdw64+e^-_+5G5>5Fc|4D z&im^=O4<_-b{a+)HjYgwM_$tH_w9QaYCp?c2^PhKd6{#iGz^idXGbyX>8xR#B7x!~ffdP`8rj4a19|CWauwii;A}W*3y5iATzPB|W_CWq6g2=(|RXXJ;c8~E6yF!JQ!Im!Bk3X!L32y6T! zj*MVKR#Wy0gzCgplbNLcs`~h%!5dweXO^agkbcNZFHQ_nyc=&OqEMLtvPUI-?H}h(s1=L zO`A0kUZKV#8ISFlC#Bv*lF2gWjm)g{w_dhWZm4d5jSV;b8?qOZEytL5^qX_rGitBG z!Df`E8QvEx1h>-#gJ~MC_;np0o14^DF&rnh%$4Im zWKX_!@NvP6bng`(Dk|guR)^UsvI{SoFu9fhdrKVbkBOTqb9gjL(_@F+v76Sa{NKdn zol<3KdcUR0(D8<}S06_2%pGxp1DB|9rjPJ*~j^VWuQpd7^WA z0PTEO+w>KoJcr?s#Aj&0^{9jujhI53gq1_X;+Cf~suc@Isv+>uJRwoKDhD-ubf6v0 zHDSsiz5*}a4uRQ|{jVsA)V`Gw&b9#{?&OTd@Z+(#)?6VjdnWl>6%?WMbn$QWbz44y7X2d zQdg~whwE?WJt=y#&xrbCoj|N0)m1MW2(|d>N~|Z)1E7)+j^2Uk*U={yG0kwM_&T1$ zUe31`(si?lfqEm-mgoJaByEwGvY)Hfj)z_iVIM$>ER!LD)!^k%EdtGNa z8*WPcUiNfofA!M6o|jv8wZ9WTUWdnfT#D7dw%+sHQT2W#_Dv6(dp;TE0DyU_Ecy36 zSqtpWZ?wk(?`_2Vm%kH9Z85->zXdva&=lzV&w-EPWqify+a*J1csCv952}^-M=|_o z?eZ<@?7~r7FFy={ji`RB$aeUpAK|f`bx)KA!M$+(H{P3RcH*S>?cCJ!g}EQAMyq|sql8e`Xd0tKaCAur&sSGUW~$; z;>wD9gH6vxK2OYD*$FJuLXih&ELta=zVz@PTXr;wIddv8NHgqbzJC9 zvsmc9pinZ3QK*xM>uquRz!A2F=XDjmUhNp=SyuOX7 z{rBHBdeCI)N7Sq_zn@3v&h=#Lwu}G%WpwA$j$y~&1Z#FDG^mx8bvBtyZqL;45d5-A1|#QdAt?H`5)C{44M4= z{kw~I%?>7Myx8xYSpyex@owz){BsE zOgc|BugI9JH9pyw*>$7KuQ$TNmWu-mfW?WjbvTo7)OeV?Z9wrNwr^W~>XWSW*6 z3A;Aj_=3X{AM@pd5>@pyc{Q}m)?8!wt_rP7jJq|6Xub-T?h4X1E<07cz$M^JfbPlA|54@(Ql=nd$%@Buzv?J8Bz=Md&r2@xrX zRnz*X7jB3s2^vQhwP#ek(cl74XP^>_67^EvD>1lQs~6@}Rh{>>r|!NcOuD$U4|!v0 z3&|lI?YvYus$}4eLr;|6%CZAUm}oeXMA)Su%&gLHfcpaH?-*!Q+*Ig-D=dkM+=3`- zQz~kc&DYD6b~V0U|3v4E@C9)^=dR$wq`wP0$>Q?nBL(XI;c0EeOv&WPt~nQ%2Rnv^ zxiTUH5+eIGz;Q5S35=j|`IXob)87Xg0}9V}E7}Vo5z&bagwMW?$d_XG8Dg!Sk&i(# zl)@Jel5wZ6{GtrIRjsd|(vqOnBw;ZSedcNSD?afu-B@1zpC8@*sYZwf#=MAa%~?bVrM)?&RnYNY+<(ksV!eQ;+G z_vlC%uewE&wnQc-B_$6)CV7LWnd-1MG`?7>ObV`*J(CgxjvUuCy}0(;t3E+s;qxaK zBu=cqYn1Ej#>|MbQmLq@Ey(Kb8TPrR1Y%=owd$QElxY5@w1>kKJ)y28{5K~OTlpr+ zxnm-)kANrD#qUu1a(?4Jt|yB#{w^Jj?J=f*xyBY|NL{iL>-Y(HuC`Ga$Q2AmlJ~d$ z;@`KaUrHAqr4{a5yF>MK5bzT62C9)Vd`a25-+u8^$fx$ns79bHlCYkm;9a)vRJA%1 z-+s9M%G^bXUtIJY9qkC~@v)flRkv;j-JiEjpz^hKHmQ8>@iT@}hyiihC3N%)SOh9N zrCdUE2_4$DR50D=n)Rne{o5?~fIsp>`ZyOEjVjD}dr0L@I`d>t##y%PWDE(ulh=ng zEA1goEez&tk@QYHQ!Ev~ZjgGOrc#ZPP=e&NWv;&hGkyJ`zBNHyTFw=DCf@&>F!~Y; zz=^^G3DH}rida~VK6JR5zgu;$H!=j~pQdg-+rGPDwk%D*dN_T!)pg`nhs#9JO2j-* zRm+0G{Vl)=8E1$m+;Zu7-5#?&!S!c(=KKEF%#8ts@2;HV5}AQ$y(5??84@`Fa5RZY zXAuX?*?Bl+sfS%XTedRhSik-jFsfTz@iqhnWaB`hYF2P^qP04$#ej!g3@QcrfQ``FWks~XNHSn zi-uE+?=tj{60>XOT?_y{DwA$H?Gh6L1aCeb${_os>c5a-(w_XzEHB>RE}gzp-nEaK z$a-SLMo8!%o$5JlmWxP%KuF)tZM?=&usU_`@arz2OQ(I0S2V%JA?pVXlY!N{wdiNg z4!?h}s~e~li<7I!r8P}}EvuiC0`)1A|b*G5{N zmw9^=L-@KWKKm7hZ3AMvXf;EMlW~^pTdUQ{VTqQct!y{{dfb zWIZ;T-k^P*cTtyqAIt4N!U1LFTXT)iXbe*yi={q@_I3s7*5BFQmx+A%^+I;z_|H{g z>Ej_oZQC4)KV!`kc&#Mp=j)Y`_?FC~I>GolVeGAabvVm>J+}j%gJOB=#Fay;hF#bo z<-G8nQ#|towwm0)N^M;!ASgZ%8zw^-KC9LZ^Hfy+bKJhou{ptk*_=ArFYWaC8+Z~u z#p%WofsHoSr+L9g8RSz691=GRlspDVO8G@si^_(KGC}ck>lrV35Pe7!$b=NxL&kXF z{_)InSiqtI`Zh{#XGtIIL2(gVy`!&q#LJaPA7974iHmjHj_&s%?tE*a<*=w8e7s(1IcH;#fI(S`anaeS~3n*Qa=J%995Zt;mi-5ehLU_aMSIp|PHjj0h55v~SI3ZU8*_d8l?Ds1TJO%+ zi*HV#XIA5AgM{bnbvp)#yC^*{_X05C6GvGpYrViwa`I#{`jf@S1cc-NWdw>3M3Ay=VwmRw7?T;)-Ww2k z&$f|lfTzeI+Cu0~r{TSQu;1=)_F|4I8=i`#Zp!UHM9*u>_b?B(gSID#X9l9jEXFs< zK-;HyG8aHIyRlriV+wp0x8(ws>>2_F2Ck;h2M#XcMUw8fapJo(N5^^(tTW-;tCtZd zzEf}Bjt2y9V1Hxp07|Td=ZFda_RIgmQ%FQc zO|tqJ`oVG>zrApF4bb$%dpDQBVC4-grUNMY#gZ9&ib5ox$37EnuCw;Hs=sgQ@VcjCcE-;a=^% z?Dm;mw|aJAl(_suSI1cF?7-jVi-oI42pepS{&-&<1a9YAS}9LiF4;7a`l$e_J$j#P z1kz(2$=rh?jXQ1JB@Bp=$3VDrsM<=Y2Agv>|C40qfRZo7kgh7;*iq2%5Xq}ud?a*p zv;s|F6aP0K(GFO+EUDjsi1!p{rA{~JlUruQwF8VEmLI`Wg+cuR8^J2$5yJh zRllWqe8-QZ{(Kfm+8v@h8q<0sjnq35{L7sL9}~E!_+s-{P8oQjM} z%Xx;b0O%eKNnGCn;5&Y69g&FY%P=sEw0N%S6VIlyNC@6#S4U-VNdma_Cep%hCn2Qs zjgO5()3h#i6|9aCpPVXCw_i!D-h~JL$Jcwlt$5hx#;fi~Yn8ODC?{OSEq{r%P+#@l z=c3sfltfu-P8&bB)%g92Wx~jA#qG5rz!%{q+uuSI;Z)G#s@I~cdGb0dCFNy{QB9<5rFREEl|qnjTc}$PU3XMd5ntE(PUpASFy^*BaPA0;MKC04MVm5Q7srrgT0Gu8Lz#}RkUtEF?=U7`f=gT(Rb;z&mp8`BmZV6 zEw1=C`}Rvfsw&1B&f-Q4_SYQ$q>_PBiGb}X$@P(tIDhR`=Xf7|rvy+Nkx&AvL~_sQ z?{fN?ry4}-k>vzP#J3+Inuss2``grwiX8?}g7vjnRVko4#KQ7DqsjfDJe1aN;yFKa z1(mEg$Df0;_H+*6O0l<>0qM{Cx@~38_<}5+8wCynez~7jm$~8eNFtJk>>+W2rYFOI zR`>l4+#unL32{?4^l4#RL9O|Fpe$M;vKRRXe9Itp%mhj>84S+N7WGS;zE@kfYXFP4 zh@I$;29r@;wP5=<*>ht3*B9YQ+%Vfpuu&pPALO8(%a32w79RBibx36dBF=fzA8++3 zoOmT04=^@hx38mz>642=()~o;>2lBExZ*HrZ#-UBNr%h|%p0=+|3mn8QuaV7e;o?S z`esWNVc>4wshd9qJ)HOgck==#B(o-{wf@Ra8&yr!Zgi^?1_krP+c%cSdOBtNjhEHK z<~C>KCctHez!;WLcB_tmI7z6`da9f}!3D$er+h9=f{ii1?))m!4P#eor_Mry8nViU zTTLFlkhb|#&f;MeAmDai@)fKga4=$Eh2eQnnRd^DsNS;xDRb|(S+*y6@b2mNx3suo zgDSv^)EzNY8tl&#&kYgl9iTnjQUJmAd0O3m8#ppj&1sf%W@6mlk40+@Wd` zqAMq$mZtiA#ej8w-sI?h^5qiTNFBW~T)(*DG+cMvtwWcdHTRgHUEC4dyADX6n%MUS zwD)+`n&|vc&7bhg%iEX*Z?)S!KL1!8CvLSPI$p0Z*`lEI@q4$e2;Q2m-8qG8NhJ8_ ze7mU0DufMiL{XQ8ck2v4e<(-9>NaikO?+>Q^inH*`S2(36M5jcpg77fv66iZilY@g zip~afpsrh%l7~-5J#`WptS#8zr|*7kPj2c~l)Sh6ZKnXl{m!h@upT{HiC=4UETG`L z!RDB5353MY{fftHJu;*UQt`Xqv5hUP5j(9W_Ne1A-swfbUCrt zhnrtEjR7`2in$6wy8_ZGP<1Dhjqc)j<>zG|1Ts(J-zdsdHU=!YGS@2G1RK-YZ%)tz z57lXcKM)+=Lt7Iva1$WzFzJB$WGbWDFdbzODD4T-;CZ6e=_!Mh6Y9YqFo3Px3{I^} z%LSGEZ=EXy&Vw!9GYo(o5_@`7@$ZIqzln13wztFuI)<_L2Z>Kd7u!Y^|3G-^H4XfA zr6vADK^7jyUKK>-c%ROQNb$nsh*i^nB@6Phci@j9pysbAdz?k?G2m7g_@rX}<#&`G z`@}%Z^7K6n`&~V}79Lp514Z6S1qc0V1zz%bx<$nGwzii^eNE_+dSW%kJS?y&NXD30 zpfs*o^56yvMIAW+7HK3mEJftFVl+pyRPl z-gA&gQ5$D1V97Nj$pSNKg4D;NKiftrRU%?N%A89fnwXcDrke`v6ep_`Ms-CRc-m=> zQ9xD)JnbWK8AxS@onwPSoA?me+9M7UdreTg2RD9Sb3zs9aw5k~Yr^-c>c(>5B{wtd zyJH?4j@`?#AiVik&!92mQFEq)IV*qr_3~)BDF+_)s0?TtyEqT?WZX|ZBDn%eNH!kZ z);LbLXY40#L|Q>!(c}w(_yV^k=wWFa2CQ`o>e>L7(Tzr{hC1;~D?Vra?uP3@xKz?)hU8?=4Gn#O#Zn5h! zeD=SCQmeEuAqhk!F^6b=qLUd`kaBBSU}1kSDKEsam=md+X;X;5qe-muwFoYbJhV8{ zC=9W=SNzs`xMR0?LJUG}^~qW##*tVYjhRZGht?ZZLkiowG>C=02YQ+3`FK*0WBMw5 zu253d1$$`k*9d*jy^j@CSt^J|X~3KTs(JS7E+#e)pL7A(nI?cJmrCB|PIp{{tFTon zQR|8}c$s_s3)+UfIuN@;q)k$ZF2`U&$`X+^3YD#lJswN4w2Ga!&Toaz^@MpobG3lA96=3PbA6VG}?W* z=j#O%|2|Yf%yJ%l-Q8qI0nhgBojEAf3N8{JR@ls<4!)u%H$T&(DQgS_z@Ij3>|G49 zxLjKWqoy7zI?QHNE3N8aAl`tNO6{XBVCK-nKnfM9h6R+Wm74TKx#|k&c{`>%Hyu<= zsya4nW5Z^W(UDiPajqYUC>=Y)v=Hmg2^75qfkPT<=FWPe{uU;#McMdOR`!b*O+Kt9GO9hxvUsPWXHX-9irRJ)C&Jd3EZxR% zP4+c`|MxDXtnuV&?*#Rmf3{bztm;B#UJhB%XM%>4yiQ6F`=Hn-ghzQ&J_0_t{k#4aX{HhdM;8#T zIjVAn7YHN!3)+ozsfL(aed$43`hGA*Tv=439B23}^5p+VV2>RTm;E`{ESWe@DdT>g zRlwW+>=twrOL7+2HdcMLBHx0P;`xhcm~3tO5aVZ^3y;=?i`BaR)+Mu(`rzpzo1!~x z2779C{ax;bJvEx7)Dog1^sr@2pO{cCxVKtH`nNRjXKfU~x3n*>;?Kx-hV{adT$1PT z@-nTKfWN>Hjyi?2w6PP(>x>vWhf3LbO)(qBcv7xrt5@_qA9VeSk6~y~(l@hXoW?b4 z2!i1yPy&@hXexC)?WoD*Q@#laZ~j#5)C0f?WbPsRQWqf(%w3oM8?OGaIm*PP^Yu4+ z;WQXJ-&nX^lK1?mq%T)4WTj^oXGkvy&vDiJ2W45UT`iD|O^`f4`5w&GzlmD^Q z(|QE|UkDA%1s)fO7H;nuW}%2&;q~{;`b)q*jiTiDd$DyH!u#pRf5sG!Y06v`JmkLE zLx^+MiKBnGlfJn*<^ll*lhd3iz0r40#IGP{XP7@s{~(A_7}50e6)3TAzw-4<2^=Fm z!V7pzZ2=*mni@b#C}sNC@;T;Su5nr8I+}}!7b^CL`V0V$QYNmGr%xvk*ZB&FB{&(b zK4q5CSLf1|rW#z<4$t=+T#91(@FXlhtol^oH+r>Qx6;8(wwypUiJrkN^7KOq>|loQ zWxB8;MqQkI#|GMCDuFausu1)=EsAhp;pUO4&sKLzQSLm>beHDaKmm-Yh2PAtw)@vA z?6=V)5Lf&453_Ke`D^>y7`5WI79#;>gxFujvgUG`=w~*PvhTn&o_|4F<~5& zGs?L}9(@;F)#}_k2;27$2_CZ07JSsXQQkGv!Yu0LIrAbf#lJB1iMmF(eUF)-ReQzUn23D*G zHNJ8aUXRKIRh;ZIP{=!%_NyX4OUtnR+t1m?fJ-7xj(Thc`{(X#(r13c*)jR`a9%9s z(|l&_D6Vss_Jozl$nYG-&>hH<{wP7&aZz2P$~ZDspGjI=Znh6VTv}f(ukgJ7Y6{nE z(qw!JOMzZ_{1$zZn{Z^rBiBFW)>A|224jzAOsh}-BPKKo_VOsP$gBV8LhJ4SOaPf{ zzBv@P1(j@S%WvhOdQSi+bMKQ@3W~T|3(EZUt zJ9`o)4Q~hpnS1lPKyzif@MN~m@i4BP3|O*IDHHxM$PL|&-e;!oQ2ssYTg0-=dw}`( z8R))_oXaE1I$a0ABf8D{N%W7!fD+X99zJA6XmO9Z&Cw8+@fnQjgPeVW&D zqd#+-Z%P{3dq;@F9{(*(tPL64sXhgY+_LY^?WvY(o#yykBfq(~iISG_zg1#6-b34S z1`tpvXIvb4AX+xwL}Rro)j>`xS~{gg9p_rX)>j6#Ry1v?@X|u*f{6xQh3XKek!nHt zY?iiM8RJJdY#X71w~cc<6{&p7Sf8Ro)Sv9O4APJ?q0J%N;Wpun^*=Vog77E<8|2s; zaO4utSejqEGA=G6Swhk_P%i%kWH*);dA#w~E+CU(!!!8{GVP4M{sV_P;-|+Sd?0%p zBbRh3z5Dcobw+Zyd(!9{^#%hK;vq$ib+u z0W`$90TXqxxYXL;K;J=yG9lZTXpxq0#M#`p-CYj2sYF9JZI^OvRL>iX&s`@cb6?uA z(d=GZ`hN)>g0nL{yEi61-_9V>TU@Ha4HwF!bIXAqYd)7vgsw}jy2(2(e}DISq#O3 zSn(2^l9_992jk2Mkwx9Gf4pzsgN-C_cOwlQxVSher$}muk^bf|M7Tk&2500?^Qlxn z^m+S?xSKYgnvy)!1Nb3f$JVy^ZCww>N#4dr!dKkNnehhe>5m}hVrACHZr-LQDvWL7^{DV{>yFQMpw?)pO&w_5t+|Jf+_={hq~#okA5 zG~2>{u=*K3mZqAg$E2!wtedtp3AEHO#!^&dmSf$5Ba6xsf(N#y4*9qe5_a_$4`}rp z*%4CQ<=OlH?$k=16dnz<`eJ}}fbn5rUyexzZ)=k|f$rOoU?@oS9eM70BF<2tr8^)D z`qp*E?a;69wYEz41p?A1ON&VnJb)f-bwZfyl0o^i3UQ) z79-U5-}%&hK~O+$_S=;FpZLUMRk#Ve1C>)KW}jC6h;V+s6+Gy1^5DZlv3qQ>RsqEL z;gl+eC%I2FqsD~Lb3xS2rpN8fqm0t2n_XQVnj+%EZcDR3x?4elK#*F?wZ#>o71{f3 z8XIgZ!%djZnZ%V*p<19O*D&W%234!#3<;3V_K6APyWnx(v|7SI9b`2!mDj^EMWMi} zL9Vb|*YvUdqAe!WUCF@^brB(y=I-v3Sq`!RnaVS^d6sBI74O~4MWzEc29LfEuzG8N zeP4!5?N14gldaYoG3zrtY{xyXBU+E?{J(+a8uvm96+kB#%8RnO=&?UwOCM^^2x6sE2_Wry7uLfm1L&{sCx z1b&8%w)YTt7;p*o2NrcM6EA1yfq{J&+mzQg>4f;#N3jyjdbECYBc1fbFy}RN1eg*m zaF4_H``|0s0G>X!YF!)@F1Lf2@PTsr{jss5@0!~MtKzponF=4`v!%~Y@AF0zhkc1R z3|o$NX*G0$RS>}^Gr5JT!T;b{jc!KnX<|c#Wh!ywDByQ12LmkZH(!$B zoiU+&RHJoFs;N?_PuF+_R38{lVAN4N9084frRUUdJJ>7buQ@U}H1Rp8xAm0ryMoI` z2?ZHZGz`vO5&ddcJXb4Y0(Qw+D6(#(JL6d<$K@g$DN_DEtB1T|rY@pZvnUSEoEpsN z`4o*;(a7ow>*0Fic)b|BK{S=MzXoYV{>$dH|?jrlFW`P$GECo_`(VWS@MYHW-)dxDlC!@8Bu!xtePBVznUe!Z)w73I_4 zdusNb%c-KHXE2vRcz-%csq*zX$&x3P88Knu_vDTfH|f-fjl$$3k|&Ep{f;^`-1`eT zXVVAk@UEIwqgLHyToS9e-q~J+DIhv39a=sEK@EX8K3@<<&Jow9{8)hCOgVnhq=;=4 zMKN)PTb4o!1`rCZ$VGIkC=D$a;E*z8gqKzcftPyT9BkuBAzSn+cWt$+fS`$S=*{oa zjW**}_S2J9uv{&yvKdF%u|lc5mkW_N+N-Hwu_p-Zmz2`b%U?iDS??@=8-oE`pZ1!R zsV>m(p9(o-RB8!r+8MuC5aAMv=;bpQz+KKEnB1woqO7ApB4;2gGlkkd4*NIvgpt`E z1<^pC{ET!tXFE{G272L=wz91k`87XAtp@yXC(85@dTAFU^hilJwGDcu_C6C%sN?QlUf<4%e0X_=LpX~uQvyJx1{Ef6q z1Kk-Xx1?!qloMpXYfnL>Bd6Yau%l*X+^WPMmtR_};({ZT&w><`o$&7f1@8y=oTlf@ zlX^+BOrbU)+#1)3kbn>^4s~NFrD}~DA)_ce8YXZm zzr%!6rPb6_Wg|K?T61rS(2XPM)wxS(yh8eOe4)bVgqN+KPodg;k>~eyKs~+Q>Tx&J1s70TzjqWGNdNZhpSlIV`;wy3Ai`i6qRsM+CjQ7D| zogMz@GeKB`3XG;3D~H$#OxQf%EB%J&gMY{*1uEH5iQix|Zo4kfda4xMstDQKACcaz z&7A1d3_vTC=E!tPl%CH!ds6D2>z;@+>&bXDo}5M|?N|nyYJi(^$*k*7m`wQ{UE?In z;=_6wxJlx`48X28U)lx7)B=Z*BRyd$^z-D`d&%A=hqFsm^eUZVYxvZkqaR|(y~R#M z9-KtORCK>x*ju7P2x9d=EIk$yUbW%_hUx!KKvn@p z8-mtrXn6tFG_?82=b*hXq2zrpoYKBGER5NzJ2G@C0ZYS_Wp@Bgr77GkoE)C-)c6+8 z!3*#`Nug9Sn+98ybsCqYpu?9RB@{%G(>z%y8Xsn21t5e>e1e%rqv>k}>gF-?hYXFD z^n~6F%L&_2vUPhYbALI6l&s_FhJyGMscVG8Z+aR=CK33(^$=AHd8l_D?b=1r@@h<+ zGPAkSu_w*K#s0nFF=0lonwL0RZ?4&i)88PTYFO;GrSX!=Lr5BBITf8evoUjb#xy%U zcmQwrGOn&=|4e`pYHg{)>MmmGNS|fUC-(dFUH#gXV}1S$*@!oG)r5AWvX^Wcd39|$ z{H&y&GKxN=-|EZI>?dG70!gfp@Au%Dl=E?fSb#pX*yoQOqZiaUsGk;R9Gpsi6i8|= zRk&R4ad>5&pgs_-REi4iq?!ylkwhVdo42mUW5;y1kgaRVu%Vso76L9`kKV*|c|24O zK!7tw7|r%dR%Ul8qFrJF6Qn$JDLq5)Dw;HF7qsg^2QMTP(HuTKkrqb*tSr)bw6a0lNsh6(N-ZSQxYVP}Xl}82-l(IQys-xLI@{h>Z z)oJ3I2&8Nv~`U8;FW za_A12HWh+&jsBuOQ(S8zGnz?@jMFKJWL>-N8E@_pitAJnbL85;1)7o+_NimPnBXpC z(VoO9$A%QwN|Z-0bir#oPPN70SalDwAisor60BcpB6C>Pua zkDES4eiDNN?}>(uo(aWE6;7Bk_VNe|F#)QW$OowwypD@#kE|Yoeb%TQ8dJ|6?~#aq zx|A=*M9c)du?ollu#kuf}x`kv1PhVDWwBNCLY`5^eQcgyy}H9oU-E{fH(;O@WUDpiC>=cUI~`3 zGxjJSkMCRXRtTYd0e5Ja7I8-iSVC3e=yT7SqM z$JH)s7>5KBfhtBCp=;3bU)9;uJv4nN4TEmLP2kky?3B(0)3_$o&4`Zp5f=E3!nyT| zY&5eTnk9bsqIWJ_R3^b*Llr}@OS=`qv+SOguB+3V`MOvRYyI_&^AHZT5Qvc+r_E!s z;%J+WYuFRdG^O^kCH!%B(a@C6wu0v?{QM`U$B!GQtwo5j#}+(!fi$r+x3skIT=Ug* znP+eC6})Rz(~%kL{^$FZQ0*DZeqVeV5i;YGa1+qglMmU=$SWB^W|tGpzC(N-O(M`X zd@zL3H#o85i*--lrsJc)U-3nr@X$jdzAsH?S!B5rgE(~nZxk!8d6r|+N6 zmCXEnyuVc{xmc6Puq(g0*pU2=5}U$*42ySM}fKs(u@DVXXXrR`~*Kkq;PSVekVqKU5`2)50kdKT;qmV(f1NGaO|w?`b+x*ybqVCx$LTHEd{AFhP+$rr5J z6f*g?%aja^)j|D0JlW+R#XD8)DZS*OiDveUoBTQZkWekjHB2N9<)~hZ-FzLWyTilI zWy0as>c;tUm*R)vEiwZy8v`D!9S#YlR$vUq5vWIy?FOVPefkedaAEoO3hlj@%V(EZ z(S51E|1ye@F87oFzL#9a>2oXpZAebRDQtoX6PN=b1Tqlk{5NW5OUWnvwps8=9$XL#&+kG zLWDi&>ih%k4RW1EPQ}gfuvlCh`ivCFV4qF-0H1eI){A3oDG=(7L z%srLzu3ZcmNUUXV^$j5=BaNy@3;eVa-FKfVd|+V+o)%qYt(C>nU+?;!^#huB^SJ~w z=c=_;n|6R(rTgg^f?7kc;>(7{2u4QTJZjnsB)vPVD|+wDdjDGF&PVc`f@bFKancu* z*(Mq|MZDw_KB)eiMZV*mhVp&JBK}0k$Xdt%{>0*_N_j(-@SVzSriAK z>mJ97oiQ>H5xuyB-iK0W>!13`hO4DYW_@e{CXhCB!$I^ zDGka82B=o2k)MMrcup-)3CV^6`CPr9|G>{kCM;QaKRW#uZ#}x^2&K0Q=Mx`P?2QPA z4rWNEvbPpB@l7r8Y7ao&g8#zG$q|R66JNn|nBsONUjCi;ic^(&5AtBJi?JB=5j*jy z-QZTZVQG4TRTrhCkrhfohg0` z>jSyFQr^);oZD-7y?wJ`d{_+g+dx{~O!9Q1pfK$6EgohY81GX0C-xxDzUIJ7Um)Or zRV2CLFWkBQ1dxH7nYI1%mnn#IV#l5{n%a&`y`gBEk4H$)oG27+ike~pFDgUp!)@^{faNg9cW6~ zyKk;6;hBnbv1##TTfgh$6Qr+BRo=oOh_AKCDY9cW=vC@v7;_>l8CmemJ=g>dnDTvZ@WT)=}+4sbCOi7l0l37pWV9$-GxcHOUbOv$7N#SRxZV$30s_|r= z8$jI?v3dE*-HY(td+?4y^aK-l;XyzjOFG0EP6q^tYoBxE0mSav^EoSn3DbxVj|G|E zGrEtdm3fH57@BrY3hVRbzn_c^@*1pZysBX2E77@qpwDx>^6`sp8mY+bt5#U`vTx_6 zE67JGoKR;9cw;8V?LM?X=H3j1UwC+N(yqvkN^2;g)GVj{lj6Bt9bg}rKjX+o~#O$e?ARVh+tH{=~8IQR? zQs1?mheu=3|dUW zFoEEfSampKDFvJjj#~Zwqo*Gu)xa9)smXZIvKx06FG!^X{Y;_jYh5MA|BS za}vGptdE}-C4xOYa}RriBesS?lyg?7FW{Itj%LH$125YBy+&mwboUj@}PIxnuxCqg<>7}DP zyX%do8^St$!Pkx6YEAf6gSt3>}hrsl=h-(2oH!5k=m1cW%{e?O2R$*od-Na6JO$3^cgMdrCqN{_e{ zO9IjVnm}zKH)^A^UIw$2z{7O;ZqefqeLQ!vRN&^Xe;Y3}*&ybxPJ+#U;#_NKR* zH?JU&(wtXJMf?iB_RCf_-}EWSz?ETs0FuJmn@;_t1sVaDBip*%`fUrGRkSy(qm#z3 zB%EjXxbtZH3B0XHV9kKyc)<3aQ+PhYP~EK3BZ>fzgWU$I($tw*R0(Ts#&e<}0k9Ty z$Ra-&Ty}@eJcp+@;{Q~_ZK*)`z!looDs3NuCKLYj^|FURxc|2p_mHQ*nP5M4K=yX} z*SFyI*7Un3_!l}=+PpW(Mu}ewF=JvOJG(w6y<0OE=%*S@KLJ;yo|H zQwGW)IPjcFRwDf#1bd}FBhhjI!L-v%8|ar+1naX!xN)xj`%olaObfln>v-pec1knm z35R=-w|@b5$yO9zbO7r3`P|^rPz2cH!5Re1|%O&d3(*H@oIu3E3R>wKy5vsb@@-lBJC)?<`GXpc$?`j;AS_}(<+6H%*?Rk zM%y?6hzG~vmJ>Jq2zTx_HP*0~Y z2KFe9gemwDu6gM#+(c4Ek20;xXm&!~C*Mi@? zbM9zvJPj(B`IQe2yOFlR^r!nbUSVy{&)CqB8R2b53U+nsN$ZBNFu^*WgiSMyLO4GduIAPSZ5<&} zuJ!-IuwLq5zD3HnK>eVvh#~cF`-7IXT;|)dyp;0w{}{+o2K{aQf*+SS+w&Xq2q{HH zq$Fqs#H#4Lv%B#G!S0DaOZhFASuaT+G^s)dXnn^dNqX{a2PBE{B7bZ%5a%JJj*`;G zkV3zG+w`I9bjUb&q`Ou@`q~0FS>(LPN1AyjgOtQ=`Gwz(c!QPL>HcD};T%iOcqhCV z^N(_Y7smf<4!xWZIG~~P9hEkWU!0A&%Ay)@|BH{L=$v3!@8JPuz6y(h-~PgcBA4&} z$uVn*j}c$(KhCf|{*75bVju4>>&=oX&RE0Cd~prQJ$rH!lG>c=RuLHIA3*4B&GJ|4 zif)uPasflaVi@omulE1aPHwO(24d5LE1IRDB>i}LTmLIrs8<2b_jbk>G_Mo|b`;cV2TVJ5Lt-E7@Dokmmmvo)s(g zcVt99d}4b{fA<|I6cQN=&Vh{cavPfzA^tg+tA4C0-e}~3nKS&~jKit)$b;z6XV66U zqN9Tl&w8eJfh9CiT-kBjtzDe>0nvkLqW2jC3gs{2i^1+9U)uMA5*2!m*|WyV-^G^q zd@YjXR+c85Bn&pH*YqO4q$nk80X3-6D&*EV(ymj;?Py zDo>9*Pz(nHlgZov*rNbwcSZb`KO|y7556 z&wI6@{5chNPwa<-k#2PO?)V7tgK&SCUk7%ryopLTCS^=C<7WLVJq;z(|2X-L+2-EICF)UIQQ=90JRCcgb`r@DJMhzkUKbXx<8HOn z!?{b-OZ2RJ47bavSd^*b`r_Rt9?1K9iw%VVTnPD&*hA@nGIq|G9bsQwX-3%VfsB6a z{83|-K#vC#5B?4C-eDxKs4DX^RwssR`Ij-!d#v!NV}%X&CJDEhdJ! zX(a$H-aKciem8PDK0#d^pF3ge@c^CDvR}!KormuKy8nNR8N{?9VQr9=tudCKDf8V{ zoPf6A05~|d5A{BSXVxSYMxSm6gq&I{wq;*IJ2vjW*`;-JLii|9^MH}at($!anQ2_n zcx4QrLGlL7niAdZPuLYu-R)Z))Oy+CDZ5c4yT_~}k%;euUY^&#a$k@6I+JZ=IyKL% zmG~4<@+K|#-qgNXBok_-Y|0!D%m2(jBYd=6-&+-IWns+ZX0oq=CAW~q&E#Ec627DR zauZl1sme2nu|Y(}kE6z;@7$GA4MiV$?7!y{N6AD67zX3YzIG*eUPZ)5wvip~G&-^! z5>TffgiIbS_p47W2ZL2=>A0lIkdnQ~b~O9Ccc?PX4q{3~IpYM>EK_|ek^gBOtj4~{A5G(_j6Y(?Dgpl)@%V2 zn-*QouHZG?D3G5$whm3^z6|3-OaL`tj4I7kcCphs0yhCDYoEla!s*1I>qM+^LTT#~ zTQn`oTe*nfYC253nLC;c;T~yN%AgF|5?;`$&kUK=Oq{6v3_K_#17g(iM&$e+J};;n zc~kM$@_)e)K4Sl9)JZ36<}RO!7`jjYM?U}Yer#GGk!2)G>}99Eaq3zVcMBcAxe8h% zHDdhe(Lk^@BBrLR+G*yvej!=v1O*b;hvju z3B{T6f<3Wuj#YKmy@NFq6IRuJDauRmzKi@C*q-v?eYBwf#UJZ!48ZlW^tIZYNyeoV z6&HIs3HB?szS0TUPg2@ICgoQ@pA{A*2yed#R5L{?3DT{o2|@31GVTUT|2>T5)zrOW z1c?=Ppez*k#9mBMUR^3F|J8po?R(9+A*3|Jr1eA3c9iZw?<+stw-R{Qd5V;NG|zRt z>1W;LZLY+#V*ruCb{b7;P0#s=hZnfZCB^5QJ%(R)8H5d^mhphXb+Q9dPm6^`9X0<& zz%thchHCwTy6UX_4#UPO_CMRTm5*u=_1-zL=k}+sNq5=`+^kY`GNb=&OAivu{ayn1 zR9>c#8eQF%G(SMO>*G@$M_x1v>Zqae*xT!({-b5^TIvOXTay z_>iq`dJ*5Nmihq|GuqqX$KK9_!*XX}xgN!76KM{IO$J!~>w}wT>R)xnS!1xaWS{C1 zO1~3FYLBc_N<=>LrR!QSc^efY^LMcuP}@g(@5~@hVrbc@AWYQ1iWW~9h*ay#@#Q&! z{v#=h7=qjHm12HBI=BTMcp>p7L?5pbN*tb(jv2K{Ii4Kd!f^y8+(?(!is#)~EPyQB zZj#T$!eA9YP4!aQ_GO-CB#U#m9Yv4BU`!m(ry_Ci`PZ&uPse+eHP;3ZY6eQqkrIkF zp7>#?w`dwUBl$m^Iae@^2a&-F9rMcBK1A~2XzP8=HCqR)e)DC=Goz!M;EbAaw*WuW zN{Z*FVJWSKeu){?pThjLkW7NOx3CozHP9PN!j%>4e~0%^pUwVLFJ%|BAaqe55#_Lm zr2FbjY;evTJb{2wJ>AvUN2KSyfar3=_P*pbr}XqvoMg}Psg49KExnXPC#(7fR8EDi z$?Qtoe8iHIpt`ihyDj54VKS9OA~9RcJ3eigO37gF?lvHyGnlAs9^Sn#i1L$Qdw`s_ zwDZi<$Z6)~{SnfsQcu!v zebKHQ=sW9c-O9xN!MFD#$o})gW$MOLF+b_7FKKTHs*I<6pOCj(Px^`B>obU9)_gnT zct-jzj&_o$@9c4ML*;<&)NuxN0{MK@dL+>5NQ2DjH*|LZG8?K@qUSh;*TZhf$N>i> z1;{prRb6Yxhm1ySBA=%_y=iH9u?a03P0*OUqV z-U%u;_s*Yf8Tb2>m&v5+l9s*SGPaE**OExzN>Keg-YWuD%a@c2m(*f|lqsT~DZy&< ziC4sZ_k8KcvQpe<09!X8{dPDhLpXPa1l-?2q{&U!G^thzLbx=6rO;YEA&WNw|O(w8^N-Lr93an#| zaEdHuG#n!PiB|(m$=7`N-;nJSlTfIn=$`^Xx2!UDqRVVQ>DZ-Jk@<*4_n?M7)i8R` zJ*q+}Hkt2%7u%jBp>s<`XImOhk0gKgBOO{AbJ3A5HvBGv6K>y1F9}3zv?9@KonAk5 z1uLhE&l~FtdcB`7)zqe==WD&f!v5rYU9Mo4{Xhj^8>VuTe$10SPZfstrozstN%j#5nK^~TlBep^_b-z!V+R}lgn@is!Ge<5&v+> z`|}ToonHCsd+)hX4L(4X{aCJ!2g_^H-#O*Zs_tD#6&EndY0t-p|L~p-*c`7k zaiVC(JdrjQ#x9q0??V4Qr7oW8*|IDVSuc#nE8LfJ6qtSooTGDa?&Hm}$R|_k$HsaF zct{9ya@fLtvRZ2)zG%r?cN8kn#NU|k96}a%#yPK~zD7Rx0aN^1c4n4aik-c{;@Mzz z>%5J-SWcNd0>zjT?`pb*5q-ntiKaNLYE+|~MZX1wTdl>c(6v*;J%qCg9ESZ5pz)km3nY@3LGwBW59Ml&$s zg{yj0$}zen7<*f!BK%mqhQCEvc>6+ijHyC+n>&xDvc(Sx|uL6&x%w;Tv9eqEl2 zE(DC7@Y_PX(h}0gE>OPU3;0LxQUbnmIRGOzG}(*c|fB%6>fAi7q) zL5I8Q(H5UWsOcQK6LBRB7}>}5eF}y$OCE`MU}rUB{bNW;(!NhDNP#P%#xU^C72Y-e z+|!UT`hVN~JU?H5=>!2r)!%`jo`6^!aALUAmREv%f0Q#dFDK$%MUrB?{njrOyJx&~ z0B+3l=LEhWCklha^MjfJMr-YskTSsgcLj7H5x_XQysKC0>2G7@PT;bf5I!9RL@Fpu56z9=QUkqS&R4!Y7)>ys9sog{fzu zG;D|JifY?9c7M~|Aa?t;*}7*{Hjsr!-w^@Bx?;m>QmE+(B&g0aU(ee+vB)nNx^EGc z?k9nN=h`Ng*m*$^ABD5pvg#akTh;3hz%RRh-7-^_4Sf0T-oF>hen)sx_fAP6=N(9# zHRc9R@?v*DF6@G-`11G7veC)0Ho>Z%Z6ocFS(B2U?_BQ~N59h&0T@kkMhNQ&mYys( zX|fCGrnV!`?+U%w=OksG?TX8Elk)&!hCN)PURtn7I;Oe)B>aH+|5?7#MrS|GJ#z*v zADrif+diklhah4ca0zt9(Kba)#}uTea!uFREEsOM^<@YtE^|G|=j+sSnN0>_MeFg0 zW9~wb#Ra9k(C7nFUW-sFTLBlL`iu}>=ipKl8fKKadVQ#=254^%2eZcz6G!IBpr-^S zq`bDgvAvx7SGpv~3!Z7;m8!kphRha2?8{F-e7>?|C^)nwy&18;%+%b%T>o)?cksv@ v>F*zyZ~OSK9!ak5*5`BIp-n%(alW7!Od9&R=(Cw^ zYv;=JgF-#RoTI2XsheqG)DM3uu8o?%6S$kC?e-z@9^Br{{#@73@Dc?L`}h^8p~%Vj zNyv%+$?W#Ykq3F{WSi_kZaP^x*^nofoy>Y1ZOfAfPpU1zoK5g|;Bn${Qf+X;L*6~< z_0T7ukn=Go9?|#{c@O>LBai(hkE4pUagjG3Cfz%%feyI8CmKh#nPi8|*t#=pq<7u) z?AP9PZ?h&Laeoh1A~jd%1(-63RaVuK)>@g?Qzv?4=3%V${84Vl{z@zPSolT$!!+yd z6IVDcAv-?Jd~I>~uJZWyNi(7JEeQ`xV@*QKz%z@-!nUC*SYcX134T{_&Tb*7Rqa-^k?Kn!B6o?{T480wshz_ZJ9Xoczb?nC+F$dXZS!f|@)Ml%IowV&XOgN0 z^P~U#+~Z@)kNzA82<43tg2!JE3cH(nsHKq)Vb^zkP8Ls&t$%q`L*4ohSLLk^R>uWL zWoP%QZyqVw#9ut#jVaHOpMnK3mMy1V>Gn8bxG&$71yu=0IX^yr!~sRPkN57m&Fje(O>Q zCVv;*{w{j-9naWB`K2Lz`A%Tf;?k}mQMpnOd^>UHJJ=E3^_cv9GT1zBShMZYad(%h zr_AG+tjl{@8#cao5_zR;e}r%Q@%!E{gldl!;q3vdtDLakeh0!o%`G!zkCSK72@-nl z8PN8GmDE#=F~=^r=4TRmrLB`H_5a}^F^!GnW69C#CIb0*$NF-+KR;qo;1aWNg*yuO z4SUqZD_vb}qIj$!4@D4Z-#<FCve zDnolcZqiVa#uM+MdelFsbNWFcM~1hVkGp?GL^4!JzsVOBE{ zp1L<~m2CpOLWLCWaAdpt9Q^XNIY;na=Ugp*U#nM4t)#=1a5vVUP4OnfKx&Nci5Y&v z`lnuObqh0*f$Y#GaIU(=t1jA8OF8sQgZZSl&3oh>*ZlMQ)k_U6Vvk~J$DEwrkgMii z(QNiiMgCW7ry=_1WH5_#x>ig>^h>XaA14pT;$dDkE$TaT>$TX0AiNU31XhpOR96gC zZ+O_|{m`7=p@jNShbu{#5Lcxu$zb~UJNsPA1oFN^2H%68DPHs1$YSWEju?MG!}O&B zhUqexXZ=*c``S0f)UB_%GVT&W<$j7E@zWK)Nqm2o@QIC%mSHDlm94MtXeIjEG(;NE zAR5)i7f~PVAs<|>xBm4wisrDrZIbNPUg;Byl0$o}aq@^wAL?n`J8Gme+(*`2s*f&$ zy1W)^z3b(}rnr4BE5700FYo`}h23Nrd0r{zj#t}5qveW>Qgt#Ie(!CJdcWbQZYecA z8sLVc(6hF%{GB+wu6gfhfEJn^I4O7!97P_~SnhWd$6@ssUj0{^KQq3yFD@_{d7Z?S zL%1u47G1mjO@Ks`OndoAm+^K!t-of{%Upugz{E>i^=v1|_&LsIZ>mr9DCpe;)xQcS2ZE(MJB7Uf#p~>&gQGvW5=$jX4E{*c^rG0Q_1Zu)NKl0f58J? zce6A|@GqN62Vw`{$(D*?UKW+22gynHx4aCawj@v-FUYA`|s1tEQIM6Fn=- zpygCoe=sp>S&CZ3*63W@`av*|D-^dB9jD77zZ8|e2QT3@PL7GBy<`X~Lz$Wh>D9@ih#_Jg3KHGfygA=-)EybNsy zr6G#7fprG4Ck)(^hw#0Y#iO?k?)M=V+-IN1T>t-*CI4{db{GJmMd`?9uzLC_Ueku1 zjj&tw<`+?uvxWPIZ}z%>0`Jkb&tr8Ct0tDxAJ_T0-OT>hL!q4{$uCyL_?oIB8DX8m z)gKSDwXhmOQYn&M)r+3y4NO~MCQx&t&u=iDar045!uFfOGnLD`s}_@VAw_AIN4oG7 z-&t)~z@FRTr)Bxr;zd;dP}gUxziOk3mP$NB!fH`G!@_Fu1-b(7gm$o!=X-t_SN&(N zT4I8AcA7g8nHy7F*5DEJ>lOIo@gq1%Ygxx)qN+cR^f}0a@luK3z3BdhQ9t2j{lfA5 zau1PAItE{IcMln{8q=};_uwr{QrSzlV} z`!KqKgIvaLdT)O^s@-df+B3is{C-n!#=H4Y^-?L$-rmcg-7%R0JiKiaS0{A4X6PKZ#4?=kFC)p<0f zNth+~uV6h_q9q}_^a1@iOuV5$yzrV+)!#eh6AbYp&AoavFOPu^T3T(C(u1EgtVJau9XKaQfTdf8R3^&%t=9F9zsOY|$GP(KHU% zK?mpF0p{Q99?W-{o*^A_jtsMr7Y^p;;wgiu;`aZkU>K|)p=z}1_#LJ-6x%;GoZTX#TXqmBY8z*X)&1Hn`mzAxpEay&X$ff%14TXD&cOHrZDH2$l z7&(c0e;Tgtlw$CjfVAbVE)AF-X~Ga;meAY42)^@oj!9--tyy5z_+U$2YHXdu-k5E| z-bg>y{Gnd1ltz2Vn--~h1_IDccrj8CVl|l}XYC~^MQ6t;RU{lcH0NsB1g0^JB>Jup z>UJg!5_;3F;Ri{)@0&;^_=_pmT(m01RJ=%k-#4k2z@85kB35cM7WKOzRWOg?LitL# z`pIydpx?1M^UqS4(NLj$djs*FNyPA(f@R~+=9qdTSZPk->kq9`o)NW-oGXO9IsGH@ zaXRpnycc@8zo9UxrKZ!)PUpyJr`hcZl{;cL%lwDZMg@C<-IhmfPVfSr?Uu~%N@1sl z3*%NE3hq46-4sR*1zD}A$@&mRc21pd|F~~GE|=)T6ymUqUUl$NO#S}}8!!1{@Wn=4+^8(A|}wStSc-!*aL=-%Z7PTGBGAch(Dj-0u_QoHZq z{~RV&DZ4jH`hjfHf{+GC=dn5yMWaFPD}+Tk^cQHDckaqV*_{bA{$uSmpq;ytmtVC8 z(US;^8|nywMb&c&W89}~m^;c~H%1CK0UBx+%dRI8oitK)vS)|5eJnALN=+fej~A=p z11BFeBt3iY)y$ImEGgVDA5nsWg}R|s746fc$fbyTGi{HPAh_FYflx@&{M zm6$3MlT20#EEqE%u%T?|vg`Dy+NotPmlr)df`BPH#K@TzlIoy?rO$LPu1>j9PtRDH zE3knz6tGi1w6dyFp6_58EUMNvKGE?!2t@+%Rb(3E?egSvQ zWmcKN1Kb6;0%KCG*pdmfyi}RjGT4PuQLvo`+0b#)j9t?lbetzI2BxpW`0@<3mqvmCV5@PG<}9Sw97tkT2Vc4u#ClPR1(CNd~JGgzH|=F z&c=z?9gO4IZk_j8sSOD6Om^WoM@*{VCJ13^(VOMj#fbjfDp414%P4+lBUaf&er|$7 zh*;EX_H=sm(CYZ$46B+tAA7{EKY!3DjYH3^uGx#YebkJ-5lq&bpPT6evn6)3qldnk z7Ii?~xF;v1`9+|4)kc!2FzvOnb(RGM&4L$13@}Vn+ho`o4Z^7|Ut{WGvW!){{=435 z!K-oug|jzGfD^lhyxi7N9~_JzKSHRgTae)kH60jeluSX}wTG!p5MBqP7+7Kp7h!-2 z@)%>pW5M1i=Ky7Z75J8zeHmRk+o;LI?Ed&8iSx826P*;DL%vg4+G!V_bxxiOW2oNO zbfpEiYDO?;zH_L02{`yg+-PpUcy}6QXJ^#uti8NzLDH;qu%}MnlatpxkL?7`@TRo6 zbb;hGFXt*|z036oQ{b3b?3Ph74o0Hi*&EF-X8j1Rk?}W8I>XsRIY}n%g6&?p3n<%n zbPk!fzRXDqq{i1}-|vaw@*W-P_geXYysnUxAPFzfKQ3gQ5WMW*(i{2V6jrAo=T=wu z#ZL>Uh<9{5KkDQ9yi^uZb+$$k-(igbmm2$r^^LGH#N~c4Jj--EDA|OdbNF6QU+0zd z-GBq@sn1b8>R^22=jVj2-|zK0UN}2tO}z^wq!y;9@2NB2&Ej0Cxh~p$WH|+b3t{ zY8vgS@y>%3j+4{V&m{Cw3_ilxTfJ4f{~sp;uTDkR3)Xn40Imd-h`ufwg@|j$61gIN z5t9KXa2jst)1yZJ{p|Xeb%03_Oq`?UmG-{H9URQGtfBZIygn%H8X-G)LSvlqn+f!x zx4Ii8gw(LY~rbNegpW)nzHOE^KdmSrWmjqh=%P@mE%SJ4W||@j>JK zE!$l>eEXHH?9nSy@iF3ihr_G#DenprdtbH&2xHABb}bg0ntxZ>%Ct!r&L*A?R>fWy zC{66G{T(nmcRoTEn=l6}obAJdnEBh1-5C+^%z>R?C1)dAFq>%X@b|poe#{gn_pR7x(N^V=vJ|u?_~;w+8Z{qztN(4d;-4r#`OiLES~4Lmx+)mL?m@6 zt6IJS{?5FvxOahL>bI)B-;G-F=RcEF<-fUTNJLHy1Fvbe_eImR{!CuOvd9s^W72sk~nL&VZHg zD;zLNvKw{E$jmdgcc?#LWf8=lDfeR}2t^&9X4nWXR?fjIU9)zV>`kT*nmbT$a4mUY z^D92{=i_Zy4w6tcTzaHxg~fYGygb~3*K8kNLR4@&_0Bm|pq3Rb9|)R6%|*rcDK zWJtc$J3o56e+S4eW%^dw7-`K@HmfEE zz$9_%e3cEYgUq#`NrcL|tU4a)+NQauqiR={O-&Oj zl7uu__)W5xNt7AyDpw&2?IB~-kv30CGKG12(`tR47{m#I%3SeVNOc$pRC^tP)f z5wbfTC}PvoSt)98$A1K>r$}v)yx*PYM_WjLS z+L`05fa35A!FWx>Mg~seW#T+~0%IJ5uY+q=ipReay3ls{2MI0aXqFsopv{=3BXPuE5rJJy)oJFnf2qjuu1X70;;@RFT3>Se#N15V)gu zPQZ8#FZ3lyANgUaPHUIMmcgoo#m3hOUVS%I)u};=X`ZjvWnrWpD+(6+88#!s|9z%2 z=5Bcho&YhEngkH6O>3>W*XZt)Rp{t@`TtC=SWEm4FpXHpkg*3nK)uKiK8^5YH9EUd}6y=Gn*h$~3D6rA@It4R;k!(kI3Pj{@&l2om5fz1qQLlBR zfCa?iJ8Z99(IJqP_iWt?ZmKca9@be=Xg1mbM}q8Mnmh4)ZRtW1aD8(&uqb??`e?8Z zg^wW`RlloMRx2H-`_vW{*E~lF@pDP#&9!-b+*fwK!oK0IonK(OgM=-X7v2~R9i@r9`d~E=3eL^N|Pu{BzVdFWB?V#zk5hcVA5rrH!BLy zjMgq7>3kujX(KJoLD&A`X^O<8QoyO;r)zUEUs~-fAEzQ`5(nK)oFhU9E=iZTw zXv%E8I1@TSy)j2n^L+KX4JeYu{73L2JrKdXaQGiFCevqS>JDHQo^ny}!5vazU4O3m z*&*kjKz6>CzkUyLIaWc>{*|-yjRtnGzqmri(T+>Vn4NEmAX5`70_GQa$t*MVlDcAK)|m5ULkkygGXl?m;lkjmXD)zvnct&;D|5& zob3XiyQ!s(fdyUPGD>%%IxDLR;a-;F8M>kp$VwZ--6X{9kRWiq8$1B^J%+7u}; zmnN!#^6aLM&ex{(){nyT^jd4UmP9(;j%ml)TI42mm@^lPECHQtBposxMH!|w1vCLp zG|wEhxx(Ot_uTWxOrk?}?hN84f1C{lBL>u}#OeBXlFm;695u z;|~uWxn?OEa>knu);1kGU7NLm^MD;1$vY7q1`Y#<3#lbu6l)g z`KGAHSKl+cN!Ptd{mZ zw`oD)YPuvNAmV)rUfXgF(!Xsaqi|FZMT^RU<5oaDj$JxyKYuaXP-DuU3>anaU zhTD=;jYG$YYYaw!&6zNB39F{8sip8hrq_+wov7;i6a!foybeF*&e&wE18UMl5P9%q z6V#H$uI@m?TnbXYz-+TNjMSa#G@iM2f{JR8W1V9!>l`}SQ(kT2cT-Rw1rsv~W~un5 zD>WZw=WMt)jY7=X8@YSAX?9`-zTn}trrf)tzC6qKYzw!(wt+f7aaoE|9zjgI&ev9L zqG?a=>>NtQq!BR54@9;>AV6*4RqeeI0hV584To{+RC@4p8%Hss}9(oX!0Wqc*2H`D6FGL^Z(vcj|a2 zr%2F^Fku|&VtxM(Su<+A{6uXczG)iy1lEmE83+8Q)jBM;`Dqsl_bPt|f3y z{H3qjgpNBEtiru|=l+$*y!YW9u7K96Lp0J0M3B#jR(qAkYNxPjv93DG~}hIDo4Kd0NQlmOH~Glby~ve(*{AnzCuL?f3!b z!B=(U+r5ZoD3f45TUqS5vf{M{A$E5U&hNMBsXJ1?JdplxklJIVULNm09%tcA_j@$U z)GUua`D({Xm0ahUn_mupmF`sDR=*fAgy-*J=Jq#gGmIT{Kd@KcbhWv^x$TrJdisJp zsXC|Wag%h-;Jnjc=pDdN2+OD>^CwT!6C)uw!&VQRA$jPW$4bKUOF!P^>${4!4pQA3 zP?If_@TmVd^-E4{JW%jyz0zQ3haMh&-4SoRHK&3PHmuf~ON&VOgmnR-Wb7B0FP8a` zDVKX=CRdy|#>e_2q`h)i)VCd(Xc4X}yDr^wv2d=BVr0ul{q-!n&L<}}z4uEChbxmi z$Js{}S_kK!l*+vd@i$#7{s&EkG>L-SO~}d?MTQCsZa!!8Ji*-KsDC96A`%@YTYgi`H>HWayWCHHQM(yLgvOD5)WE0T8vfX`PEn};)cANg) zRuR2+$b6glw&P!FzJrCq{%OS4b6IYg+MDhNn%iO($HjBebNf@|p##8C6(P?l(#J!Z z%v@TheoJXktvZjJ`7E8TVamKtYRp`|n^<~^KHmAL1hWIUB>Roz6;e1zXcUonM(C3k340ub0<7F>mjmwswpia(3G}DW*@RF`ij8W2KO;1pJGg+b)vV z4xv-nYnsbfT(7)6PWQ!Xb+Mttk`-=9lvg-8fOoP()9=-3l$XMO}Jp?${$Iu&Dku2 zH?`{I*-z*WrxCpRmXjhoJq^2G&r6d`HoF&`;Q`@+!ac`qBopP>)q`@L@7zs4A%{gk zN$?{1Fwx2C+{@-x3}vN!0i7&QM+_hUm55L3qbH7L@MLmt(z;#F0>(?>x9_2TwFL7| z1+zenpT6p&;TlMU0Zyq{585wme6WBO*ABtza#;S;`ohk0*<_@#DhUhh!Ay%I$_3cy zOY*fQ6_icA2~hCBddI!r_r=8HSeQJNE98Shh#PR7^P5vmw zT`bA(+;k0_Dne=L@`zKYmvyqb;Ww^8=zK{=q}29*#uw`4jWPV}2|O+TNQwAIo7FpRG*do{?WYNX7ea6macqD7qVDW@rp zZys3XLFRs&>swWn&zm}q9yN~D zfZ5{YUEGk}!M2@VsTPxNdkY?dMX$W+jqQ!+GK-2WMpNnbdiLB2u$~nueHQ+vJkaf( zP-4vhwMvdeXq3fZd~r^`z?9%G<^!@#{TndzmwC3n&|sdV`QRP8DnKyDCpW5It6D;h zvE`c3{P!vg?hA;|T7t$xG1-zWQ}KI$@#2HjYC#fDidzK>qHOyURNCf!ZTm+yT_;pG z`;@+KrbV#74BwDpv~N#pxq^?n)few*sdB&M+0g6q=fGg1=i)MB=HmW~nJX^lfAfaV z_eWy%fPz_0MsiedPy9EtC<7e&&A|)c)y%n(D#gXEaRrnIu1i*wn?sZ(O)L1taSvRw zC$c?0%TjAsbf{Xcb8|M#IWcE!fPsCM`5}|8b$r3L0!ya#oPv}^eD@nZgIr?6n4Lqf z0`cS07p(5hNX@DKRvIgn>32DH-=j>2;uAkaZ9Wyk6ly-|Z7s1-Dd-=Zj*Bv~h$<*S z6W(MB<`N4A-iqW%WJYlg+>th$)$12+FS_0yo{O$Bp9P}Dy(xd5ix|@qbOVTKqWfFR zKd7j`I__Q{bk7(xcsAZ@{C}i+@9G$;{n~LbCl3px>qgM#A_lb(3KaM+b`y1oAMF|e zHwh7+=$wk^2Csx*qR^Ql(eZf~8pV^Jpu*<^K$6)@YdWecDh+pn&{f&mtdO840cCAMr_Kqj}-UrA*q|-}mzK^i{XVt<`t=1!XgX$(yCi#~vh(lV+q!!FM6)RPk zq^uGb4?x88_kW)cyv{>CxFP;9t7-Sa)e!8{S4k>8J&ngm<>F#Q%@DNTiXJ5;y#VMQ zBHM-A4G(#rCtS)3Iz#kdT=!IRENL0S1~Cl#?=+>)fZI)y)FG}{yb9}#xnn4aw6ZRp zA{SXq50vtajIh*Lz0!j)p>*R{hQq_RRn~Z)v6Ub$jNn?W!po(QR>0H^L5TA#Bh^Z; z>mbjGjW=;5T-^$7X*vD6l+SjE#h`NGIk|P(yOi(O@XUKcBTcU18)^laxAgLy{<)-< zbL_J*mjnugFA`j_d?ZU^L#ahoWUw3^6!9vL-mHF{VXwMhasF6fM&%|@ZP8_eQfx_cryBrt+F!?kxRsJBg1Q?n0&2ESs=o@O$eI^y%HN)B8#>a`Yv)h z1II@{!g~qHbhR34CeGy^^5AQGRpOw0l`*;dhnRk;a$S5e7J$ zz8tlH^s(qrD`l2a1pNqZ%PKrtD%cqS#gNfzr8iqjjY`PK1geOBZysT5$EjV;yb@yO zrI8bqLo_R`(?lv?-|1Q1HEBgJ_;T*zRhY8CBB1&Q%Uea-8{LiBq{rKik#O}8MZ`v| z%AK~xOl#$_;+DyZpv`fxYeYSgGo}i17^u>$V%z7UuJ)8(u~N9Ztu5`?oE2`z;%wF9 z0oc)f)aKOtiVf1?k&swD0+1^ASWsO$UUz(UwuJ9wh_}f~@4$f6BrkR2V|>EI2#C$O z-|o+h@?1_*9&dYj^r5bQI?le1xmHAx3KQ(?a`pMh%=uxF4C|>WVa7VEme&~bP`qbd z_Lzzp$$l~Mk|Bw>`?W2!BgsZhp;-Amv0U8!y$3YexhHQG#Of%xeYO)!puydoOGegw zRwM{H&%ZYsuX}Y~Ip%7yE!m}9yE?d|e_H2yyX8DTP9Sn+X?;-c;iQN^7Y6C=;*Hm@ z8|_G2YbW=x$Bs%2*2|iYiAY+{JL8mNiPD!y^p7yv{xC4y9=NS2@O36kmk<2goY{ZX zdl=emrS|cQOI?k=$$ZE9x|M8&KTdc5$?p|(%$G9TFxT=XkJlmMvm!S3^Eb=e9#$v8 zrjrv3^P8pxFTV58c7$ifRY4L|YXx;&=5Owo8vK3UNK@7(>(wgaiI49zN3L_Hk z!qTEYHQljp6GJMqHFLGidFB4hWlUO*+%oU0i17X_8}yijCfd$FACkN%(rWFJmna&t zv} zn>S90Hk#3umlkfxef%j-*%~j~u0~?X0Bm^tq`&wUvR(INUpxq~W@SC^P%a?kX1?O` z(mfsQk;z9QieR$e!pvH$ERq#KDk1Y~*+C>+v~1SpUS&i06AUs2Y>?^1HglXQZ#ny5 zs$*qi#mO&lWB#;uhb-e+5+Vq*;0xRB(sv&2Sg=)lR;nyHChbOInQ+KU8wLz%1|w*C0Gteu*{Ue9V-K%@d%!gd~AAuy9X5|o74 zB$gMF0-7AmlVOm7G681m#6&!?ypbFtFME?~TD*3oBx#*Pr4ElZZqN_jC+RtkOI%D@ zatsx`li5z<`Xs;EXu~iTL9>b|c934Iu)UtFCI`8g!o5F#N_$$io0LqBxn4%MAT!-< z*&u+Oaq?K_ostc2uCz5wW|qdVjo;d54Nl)o?s8K5iBnX#>*PESKh83+gvbq&I*GM6 z4pmqoO`8wQpuURnrlYgO@>cm?D##&{Bc zF=sE(39QDX?-@kqUlmw|Y%h}?BQtdRSKakxx%pZGm={QNn6+EddpE8fO)!z?;G-e) zwJnF@^DQlhO2N)bbn>{5JS~~kolX7IFK>2lOw1fpqEv+I;b?wNQ@X;&R;|-PsFE}4 znOyiTHyXMzQFRpOOpFPU@N!m4fkS0@=n>3<^>i_RZ?&vp{v~4BiFAtdx4MyrA#^@m zT5#wEp71Bk$XZd(BZJ7Hdf`31Bqi0{s=m*`V#^#15|*Z->&EtmA!ZMMmOlPDTr0dc zt97EziuT!>U~}c|g7Z#a>4uV+t-$89Ij2YuoH}Q4IZ&QDt!H@MzH|8HRGv$Md0|*+jJ8xxo+;G~QXgtWGcWH)8f{X2X z5B2noH1Y)6x!L&7$KLrHS5_xdb;eJ1L@Iuri5aM3@6F+#f5wcAQKag-b!^S$N8R{Q zXg=)7RW3jw#Xr$X4(e7#oL+qbI>Ro1Z~V7D!R@SMEravl(cioscF76FEX&e=t;djA zHN`)p^JA|WNU_ce`p}uRK4voI=HdyFn8YYK$l#Q?1NxZ+Q|Z`SfC8O1AaMHOFvqdb zXh#&@Rb7qyep%bCg+IG#<<2*+_vHKFBQPKzM>sesxyj)4JNy&BVC9{X6#_z-1R-=y zO}Ab)-zeOi*xO5^`1?OdrA2AzC2oWc6GDe>zWVXcKeaDcL)q+6o=f<->>HAQC%hea z&nzsh-&I<(RoaurIb1`(Tb~%V=T( zuzz~yyd8g_%q)Dm#p-Y5vK^XJCZazPok*H7>a+HxQ(#F^|Jl&efE_>A=`C?(@0|y! z=>RNwRtqWLOGLz~3d#wvr-%nM3qF~dnc4(0dMe#S^E=4!!IBca#`*%2hWH(;j*M7u z1|U`C9OmLD)*~AiI%ed};>oZ~Y!X*mhXiJ*WJzW^Okn@-%zgW;xCZt3wwCh6=hLCs z$g&8|fw<=jk-atokRP3i;Ga6W13Y}JJGp+zTGKm4ymnOZ#>z|qSXZY0XtJebDe|o? znsCsiu$KuyOC3TsywfhQ#R@67Fg2`O9p(xk4IG&>zYXWsdRE^hIUWbLhd>_{4< zy;pdDG|umq+CrLuVx@SyeibMk)bVvT^CWSvz4R*#Rn!%+PlLDF+)2DkdS=|llUuRqPSH;Ud zr;iEJv8buqZ+5F(N#~jvBi^}kfosA*b>HRQu}0Wmd-Qi$FYkz8|N4ykF8ahna&mF~ zwo?XoOcli$Jr~VPJP(&XN$UBl+Tmdq{--R#0c7uCFC5Xg;Sml=ukfmQ{$}wh%d0%h zNx$UdMD>^rgUK%4RUU9d7R#hprfN*S+gdpK^#H6iz+(SuzkY zzyLtNY~_o6`lwPIF(=5kJkx_|l@0}xf@AhcxH=lz->+}`9TxFCiDgKYggMsQvq;JK z8|mqc?t}F%PYS+Vo%yz#b{qgQTEq8`-bn+*7;hv60Q5`&dNKZM+LfsFEd9YN%t^#J zH-1MJJ{*jXsLypy&HNcVq?Xz0$?u5KbE;pXprmJy(c|;e@iptk;Z9ZNb;ky8xXz7B z*x17J=o58f9v>Qs`}Y_$v2QBe^;3FC59^y4;3^B5IY3*iSR)Eo=Fka&!Ut%T6#EaI$^VT+mS_9 z9jv}ukIxt}&|}V5$kImRlx6xGlGYzHUt~^_sJ7?BINGvo%(DSsrqVn!{oIM~QTfc< zAt0LgHcos;d6W0qFErxSFR)Qdq{zY-c1)wP%rqbne%sDQ_7}^R`(Lef*RU}=n+1IM zmRs2zNNJk4-=0EKqTOVHUA&OfWYiHUyvp9D8Xu0;M{lf8xnmGle?j~8>Agf3Fzmbd z7qtZ9>VF@{12V2z)izy36B-bLG7KU1(9Iq7@w5D^f5lhnW=9WKITeZHv_!`IrWgu@u3>OLE9&s41f)rE-EWlc(5{_F|xjHoT=~X`npGnXEyIK83OM#P_-m3;WL?^U(iX zQVJTBkAX)&`I9@PQ_#y0`E5S>uRTDM_2+1hfOW8QnMMx92>vcd8`%LCBCb}KdpPuh zV+(j$BLQA?<(p5FqKoZpEe^W`f#{nkP&2!YC`Gk(mnEo=3Tu+)?qHOoouD-(`aDQ0 z%+EI6;lcXc71e>AX0KAk*CV{|)qa*LG8M}v_H!@X390!hkCRWlDquWx>&epO>zy=b zs3dTeOV)RS!y~A-5Z*hyw9dRaVD^|DTf(Q6;SN;jHFHDevQiKnsVSZtuBTZ+eBD-h z=mKh4+3e)jjeqr+exCbkUwLnay#3{`I}#DQ6!v@{rFHlb5(R#7{0&RpM_IV^#7;)k ztcLAuqdZ+$V6uqY+%2libT~zsrh1)~Fx73;-KChh{jbbEiUFi}te+3w-?l#@%geyw zxH9(Zs}6cOu2ODk|7}#BGccy(hH0Cm^**J%o)l{4PZH>DCA169K{lL&J5Qfd`wXX* zMZZ{{EZ7F>Hw^D^g@CKSE39A}MQ|S4-ZgP9nFUFD$r2v4l>W74s49V{$~=PUWhF~w z4-QW2boF}R|8D3{`fa0I#{)^#1>DHjlr-Rh^Pl?vz8k*zHMt&{>?nbQ$OdqZOWdf2 zK_AJ|rzQWE4v8%AZ`0^jxL*;|v<*^Jgw2XGOB(zY9&iQ-hzqqF%l`Wjk{C>3nVys^ zv8xHGrC&w_Z)VZQNf8^8XG}uu3jOhfh{VOP;7!!sfAv50D(1wRWC?*irTcDBuS#P7 zYQrTe^xiV)wPXcs9V|x7BO;d?B0}X~mZ!?nMi)qV z2?jZRTxNsC$)R<&{5M6z!==1x_I~`v0leK?%>rqDFf3nk`C!=NjjeL;AlW%}JaDn8 zZfSFiv06^d<4s7_4)E(gcAP;nQ0um21>=Uvu!4f#_1>+Bn+vkALi0%5FK+oFFyoEQO5yYrwRuo6Eh zn7^r>N)}(u5$EPJ)?3(icTEVDKNicW+&Qeg{rHsb2!+dJQD?A1(>==6!bKLp`s7e< z%@dVwykz*g3$%Ftd;smx-6#GCO2cLYG&V1so;Nr=cHlol#W1W^4VKfW##YIR{=9yC zK1gx!?SQe?A!x~EPbw@eZNjfp(UQ3;zx&gyl$5MKiF?J-W}vpO4H9BCMu;b9I9|LE z!gZ~as`7F&&1tAX%GcF~EjD~w9_Z@awn^Op4ap0^<&>`UBhmIVbq^a3*x8B)MXK0m z&jjhLU?s~ydt3bvH2i>)ET2y~{+Q0Hv(`*@d_b-5BAWt?l@A%cOyMHY%azgr5>Ez% zJyEQbcI#cf-TY^mll0X1h5d2|b&tmreJs2M!o)-KGoP?zzCGKk3L0koj_}cb2LHR_S6B&4 zY2bc)TSL9m8?PJhuPT!Q;Q z6J?I@!=X3}s`&|uA5<;7nQ1-QQ>L`_2D&KxDvXVUu^&uaT+EZM5pEf-V(#m&&t88a z8%6`!cCWsD*?jU&884r129=23Y;?xkK#fnnIYbP_f@v^{>>?H8qQ1H#;TmT2rZ)0w zSr*>&%6S5h{nbZ#h!TpGd|xIjxrZrl1`Go%-tnoqj8NWw82aDa58Q8&msWsaMRk2W zo%b zP)fkbSCQ{2`%7lz33Hu0%yatSv!9aE1ls&BS>{&3%NO9)4xcn^3Vsp9{h{IIC{{g| zi^2iwhntu3-45c*66P}Y-t`vJ?~nMwro#&?!wP<(T=nYuhW;@f<6|4hTjo1Go#1?b z1}Z1=zf&=dFCH-j9 zM26MiP!_r@d%`_CY)mNSpTDcP)q<$qm4BA3%jSCmzvBbmBS(tSC?ZT!`E=TE{%fK0uA9r)+Pp4r6%PCF z8SNYCe&GN)b_mzLW=K;6be|A+c<|%V>{yb5s~FGU=QBp1w&E|?sC>d@)#g4?eUrzv zJ>c`n$xKuAB$r4%ZZ}6&hQ948UA+2)lN+jQy*P9{$&uUBpr!iR0$r#nGu@hGqcSrv zSTFrLb1paW(qM)~PT#MnrOEiSmQlkcXxZhEU^<1X8E<;OjNVZ(pUv2tBe&$U=lNTB z7i+5K=SZh31i z{e%|1h7cW2@-*>Izs>BaGX4v?e4lc;Cgh6bnNSu~jgW-sd@1d6$#z0+_@b7oz3BXA z4tV=PF+ia->Topvl6lnUVsxJ_Ytr`N^gg&el11r%56oc3Deg7xmaN_EsogoJFx|;J zyXY;@v&zvs7;Qa9s`Pq*{%G|EZY$S3&noJu3{BRJh|BGv)<$~s4D+acHCtTgeOCV& zNF}*2d8fo;)_E^20#vjhNd|V6=G<=)gJX%mo~x6-Sln#T44-O6*!)B1s7p%$o+Fh~@3ZCDwqJ1m4#k@62XufU#|Iu{b zaZRON*B%vz!BNn_Bcmb;1R^RhBWMWCQBV@<2zH7MMT!9uq!$I1VUU(kgaohzA}UxY zp(8~wC;iSPG^KSSC%=RWP;`&w&7r&UDa1Eb0*QO>$=e{W6n%$;Jm zQ=H@AW=)G*67B>stxEPzo`@Dyb>EGxDj?mkY3OP{$lP{8{O#)p&9N23iC#;iYvreQ z+0kz|8>GEPH^fSgB6QH`Vy=;)4endOOIdSyLBJtQ>rq0>!M%6;43?3JCu%*zV(I)? zF3kJ%F$n_)?T^4WA{7++#Q4E$-hHHkn#nJ*Uj&I&a?s8=>S3hp;C=}E{b;y;rr5~~ z?1n=j%}YA@?=#u&I%KA533(iYLB>C(V=Un^Gr4Cjm}MjMlX5=ud>ZNbD64#0QJL$w z<1g%Yq`*Vn#G0izJ^y~R^+M={J@fVB0qtDP-#cKEG`VLizRJbRn3Knj{un-dEpXGs zo(@#xtYOHNj zrBb_*NZRk#yO5`7=#QMo_UEtHm>%h?N|*w;sMFrw=rsjuhD(GESh2)CqP5sr3)dkf zuc)S(Q|NSJ?@WH`hR-VA-AewXUfBXgHNS=jD_gqpOZ{k~mZhmH&fj-xeU0FXYv-=; zmHOO!Nm|Xu)}d zN~_%yJg&&35>pSWT11xglMq|z966!%$Aw;%^hu?VU$De7np9zU)_9!jU20x|TlcDo zZbZHns!!$p;QXqq>4ePJ+3WVXV#!a~w>o7bVTN%lQ(8OAbm9+FlY9cLU30sO!y`{) z$0C9pPjh=|y0kX+$`k8wmR%}MDm#4BWQvZrthYxX-5(qJdXIF6ir8G-X*?Ep5|)&d z5^oPeqgeBkC1|=o%YfL4^vaWw`N#o5cicO&aZ5g7wo`K%VbKx!wQD_-EvD06M$UPJ z4egr!&=UJfF)MOowNqZq!2}&$&O^((&~IbYU+igaF)ioAi9-b~G;-i2Z}xFmJA&!p zp|xf$2b4-TsO`i}<+-7ghEv5F zOT=Wg^2HWey9XMNdr#?PQRH0MyI2~lEW(`*&2J@w!^d_YysgrtA)H44yB)VoM3Fu3 z=g)FA+kF!4d8szQ-#i_BwWT`{2yDZV9g`uK7P=buHV!%*z8g<0B(vHjGsjRDJQ1L? zubQVD-J{y>F+f~SnC2T4VxIdK!t^sus+xyQdRWRUka@++pBUrb@f^z)o}|X(4pQ#% z<%Q(#_SExZygP7;C+BYl9l@g}b~}$}xp%%^k^B6Yr+HAZ@c~|b+Zg46XXbm~ zlexMHU8+Yt26h*I5i}<4aRR*(i|db8{gZAKOd9Pm}i_Qe2{{WVZg6X^S^v6NmB3glqSNh3uK#{ zQ4c-FJpG$ja?Io2W2Skj(ql5Sh+cpZT0j2%tnQen@5UFbkdeggZ~cn`u}S%G_hy6^ z>Tal3-QhM6fNc&-B9yk}caDm=dZeG%o-fq(zE*l12!u0v;1?EiN3l(7GiSqCZN>*R zF;G6RSjJyka37njx_@CAe{03P9;IyajJWBWsNd0-*Ts21g3!Cb(FT5R@;m4F7cSbM z+C%X1CQ4yTiZe_Yi1GpZeqciej1%e09WZ@-KO(%9EcXV@rP(f&)*g39>13fkj-o0( z#9jBbru_E7Yf3O|vT=x$K8C#WF-DCX|DxlI=@PM3Z(654ZpEXA%fiUg=2`qYxGnlV z=R;q4{4eo`g)%32`C=tHmpj8IpXDq|PR4XJYUt!KyW4FjJsg5te8qpD3V?IQ0ESU* zC6iBcborn8b4F>WHW{vhigLV$C$~FABAE|vs!4Q1DL&U{vIt$<6CM}TtYeOE(7Zk7 z;7m4uo?~3k!`&VW-R7x$TN~(qxN3k)Yg4Zvu4SU|3QPeyqSsG__TDJfh{V8*cyInp z7p!jwPZC>#boi%kx*qUrxa2IK>!jTalHV>-2W?5h%)SzuW|nFsfByP!oajeZ63VAU z=j-)-2FrA_f4KiUBe!Fri|&KJq?1RNB`huJS9LD{C14t!tW;QRm&2{Vi|A~>hJ-s% zU*K;%3en&Pe-T7)9ge#3PSlXAFK#F+Lx_CvF~nd1dH&JyE6}&hb`h7@>kuRw-=J^i zB5Q3noQb1+w;`i-QI};Yze+?f49j2Z%L~e)XQEU+T>C(~AiQRD!xg6^?XL<2LAPA! zc$d$DP^MazwcpfVmh@!2i{Zt%RIM*wxRXO(_WQyF10O5IWv^9e))n+xEd zL-`zfEFwOo#S5P)4JAgG58hvGZ!jyMJ~o3)Tj@EPx?G-_~L%@1;u}C%emRIer#Y z)F$3>3*GqbWPG`frgFfb*>t`4tw7N7UfU}+wN31}XmbTJrq&XjItG!@HTq^0IMc7h z_tb2zP&i@YKSh^{m_<;Kn1M-%=C!8E?Eh!oD-4wX*6&B&>0Ro~}ze+~0bx zEvmtBd~mExcLr~?+Mf8jT46lYhYAPbt-r5u27JF2$50gn(I3b0xt{no?fj7B=zQ7v zzGL~M2wF0UGtKw#R*Ke<>`kI5n{#5AQW;eBo243@c;#6EpR+*n=nR`nuUI@n%|sC5 z*kfknQ|j=w((KPchGt^0XQDi6%Ghv{C2XCFA-iKj$}LGew&{e4l9$mm;K<@^(ED!+ zqID_X9px)|DdBV#rIKNXkln2%>KGyRyDw`iPA0*4f|T=SvYWk5!`5!)>dod6k)6W+ z6e7<<%*IZtc5g!e@8*Ow zOm($-Epv7juFP%)>fzs$QC()lcqYA6J0G9So-+|tcXn2NCshIfyv@(?|l zN0POKIW7vADV&Thd2j>&3Mb=#Mgr~pnIs2~(U_RKKr$thlGuS}xGryaoGPD$G|fMK zagOg-BX4}AzM)sSX^8*Jym04*Ted6zZ-Rf&GYwaU2(t_vS9so2egvt-eze^nP~nD) zy$PqkEwz>D8}4og3|xDjoANJrKfqY~pmNKTt?XwLCjTrvGldCDln0PpNt2Qy@6uzV z$m}O=!4~%KnSj4sEnvc!0nOO5&xm9}Cz+8?m)SC$ijztf%QX|DB70@24EBn?)sFN@ zJoH~ew{R-mR^_G-5GsP1G3iuIRj4NxqiSn0M+97eK-CT{5z&=iS{?y$SB4 zCg{5aN`dBmn^2w^P)^LdL$v@a^+tPIp>M9~9*2GxCV3G#v}1o8G1^EbNEhaX*`PdC z&91I;HH}sfjqydEVs#@taX~)a7}fbnY{V!lBHsN)m}E;VeTbs!;U-_)rYa-LdExJ3e)4FU&4>}ljZj_$YbN$qHB?(#c(+fx$t9hj z(eV1Q@iL?$&DS=e`I&aU@phSER&BA)<4|9o8u;#!ipw$%YWcKb%t+y11Xge2#eN*8 z9Q1UHEo9W#SocBA)4T@VH*@HV0@O9d3X4>@33KP4>4Ri$Mqoq^il?^~YD(FL@;VSD z2LVl(>|uBj@(S~0ZBa^U#GuYSXN}2{MQEN4Pvor#5PmPmnVHSETr{y|0AgboULLng z-i>;wDnzr!W*m6iz`!ZEh@YUaB<>`Fbl{os^LpT|wP`oINNaG=?9dW0gJVj1`%kw zi;d{7fch1yroWO#s3shzI-``{JMhOLLJcC6G7pF1{s4h`^FpF`A&7nFlgLSvegyhb zt_>*MpNl+nFEmly;hC)lEd0mXq&s^SkX1eG6hs8`IH>haOU$|3)GDP|Ng zJOJxniReL^&XG(s7W4?fWe5k{37G{jUR)Y73Y2%oK{W`9h6X!+dm+NiU#jAQJ>2dU zqCeWmbY)gL!hH4KzlNAQgFSENo>_g`B>$uNW`+_g7m-6*Zu!Dyz^-gFU2ijW&LlzI z+*XQfvI+gwMeI73S)hHtMbW;4DDK*6*d13z$fo+Yb4!TCJD>%k-e$TLSebF!Wx9y4 zK=Qriv2vAg5GWUxXN>C4y8dmANK5?0uGl7(swvqOrjj~jX2%RNTxj=vqfUF0CF$lD zcDL7>PMF>B0-}0JQBU%SK0sN@9v5Pe=aDk2#I9P?cUKba&x@7n31hx z{g7F0IuUon4LeY(?be&5ITj}aE8<69?@7uv{nsxa>Ek`4F1VEJJ*pUuZl%$>l1wJd zl)Q{z{QRm84Y}aQ$QMn;Z6}kFt9Zif=kuD#ib;H^Jm<+RvNBt5hrPD6dQ7eX7K!wD zWz8*?fYP!aMAMdSK(iB+Trx9z-fJgAP>KNX)N#N?>+S4!MD{r>h)|k<1mNMkCK-(P zb3HMail_k#KuI4}-H;eKx&MVB9Ex99{_{>Yw-qHFeV;(K)kx_K1 zafAO@=mr>=Bs|jW*>B8QNXwG)Cf%Fum-oh;r_rLEy~u?ifcHIfdb@oM9L~{L%LU`K zBAg`$d-Re+se`OHVeh!cFWyY$uU0;-wYoELGv4GSzbt{&ns)}E(w%3>RG-z4E*xE52n6I z@pgxd#<)l#(q}8nBXz)$N=U&n>wFwC=`OkQ`u7eEB(01ULN5R^(KUr2G~j>EA*6d!l;= zsUQe3zl!W5q)0I90vvW|9rsMubT>;Z_e06+p?2)M&zLsN0ZsHG?LX>Z|6sXkG0r>w zQV4m7ro{8)bXP%Rq_osQ{H^)(0?alyJrZT6d-pQhYqbNWphpgsn2oi~yGkV0SuXJ_ zbhEGQ#(b;&_G#c#G7KW6LuR#T;;T^!40A9Y zrSw93WtCkduw|HM%{0?Cq=Wv#mm#Ld6FGj?T%=L~pa$O7J8wpp^xH)DOK`?nLLEo7 z8;Zs+xt98J|LLQi7VFF%){=a712{ben>2^n#_v{Iz_0mguIq;O4rREm`J!9`U$03c^PW6Rt+XCjXCE=h{73I&=3owI_hig4`-&Fa=zKgeQprK1FRbu zZ6tPtlw)=cQ)ednH~`W1eWy#M7+6H28$zf(MGl1jBru;aJNl`oTVw^f@HpRg!~|Ow zJVI=EkJzqQ{DbD#D-1sjRtOu31%wU$d3Zes@hLZj`)yZb_H{N|F8jg?Na2T=P#IS> z0JzjJeQplDj6}7-`lF`d!#}_i?AbT#y?cAJ&AQ;*x5HkqWPc*$#Ldm1+FDs%UL~)e zlf1apadgtx(RyF`_^Darfu>#Ilwrb}|2H=d0G1f3MT_f#WkI$u@EgfaaO| zXU1m-*J+%yu%5OOAeR4i*XiQs=|w0LtJS}J`vLyfL7fl4vY{?mM4cT&Or?Ew7v7NG z4onv>EC(K53x-bZ=G`kl-~+wNUabhcGJhU-vRbZfPI|7;94&?o3Yvoa>ukk`%C9%Pud?T_*1GxPYTdfh*>6v`Wv-pSbq{Z#j7nd z;{&pB7As(RX8u{c2rw`tY0|&g^{>rL$@;e(uc*xPmNZKciw* zt{Ahj()l=IjU;M5>R^s1} z=Y(&w+%nv~4_L?P{SEU-53c0Fvx<~90nG5k?3U8uZ;|=s9}m(myi;F8T++{8#8*8d z|LB^3Zv03d|Gs03coK!@60McxYH!UDs6qwmtXOm|AW-vYzy~oI#dyQveYAHHDiIWl z0g14+5N&LYeyYk-1xo{EJWYL92v1d-9rL?=jpF-3`3?5n9*a6N5ovLdKGsM9UB z#)_LkkN9(|gFzsIX9H(y1LjT~%d9OkKi!3!Ui6n-182anO;qH*3 z(0amn@Pib1EHCHY?URSLv0|K8wU$`U0J()e3Dg9aq8Q`LgE0Buj+)&W;bVOAts=Xp zM@a<^piMns-Qlv(-c~%#_6zV1LU{+>Z%N_o?%{HnwqnYrQ<>UHS4q+T_qIqR6Gr?OA^w3es3xRHad z7>C`%A3w*a0d5=j{~go9shc9VbtmzT@sk59qE_7-q7S=8f6oP;OKCccdI>K8p4ue8 zfhV8g4(-*v{NlIJ$K~y{$ve<_9X|EPdB1j0_dQl6-cg(HEfs+DP=6r7bQ(>{iiJUY zCRw$0{RB8u*^lBF=Q|}HBBw@2w#ns8lFOVlEsEBE77-1gPl0G)r`XxwMe{z@Ui0_2 zU zr3l|2un8-+-T&mFpID<9D#WfSrya>pz;4&Al!p!qD0BcZK$%@om_}JFtqYE$K2TAH zs}CcV_TTT&|9o>J!JzLD;lXHc=Y{@uvHzoyq(;np(*5qdQs>WikW%y>F$yuZnM;^gUCx8PQHp z1V0|F>6GKC($tMTr-?US*_frg&MpSzdT{d{=v0gDGa<%1B?j8`t$%$%N?QTh*kdIp zE6G1INw?kmp5`lEMYx^H*I2UY!4jhht9(+XAaIK-S-S@_I@%?O({Yb2DIzVcAYxnH zRik)b9tmxuIGQO#xFC3V$dG$hpkw zSW7<5w7^|}$@I^dh2KF{hS<=csw&O2IC3F^@!H@^tb!m##~ccggQQq4i-fbG78Uc> zK~gGBw`{fxdM%Sw!lcl7UvI?>8Kn4eA$Au z`^D$PM>1px%^IfwfGtvrTw^W$4$ap?VRD9&_Ui?laV~7x*ELQ5Oo#Kt*v0~qgiXU6 z>%e54WXj=8i=D7mPLxmQY6LZXGr~%Ew>6HENnn3BxcfS$71s8kn||e82ghz-ET1i7vrS*4(a4VOc2Ua^0D2kY=^}DTGcFN%x4o z@{4Jq+iig7tT@AU-hHP8S5_i|8F$akxF(-)u04+geQ(!-91VUR``f4Rh5@B>cY9|R zxt~&qo0(R|(Bovh30Dw+1-L=wSx3mR+Tg52YttG*m2k@kKQFSweFwpq zDj-uW?*a=}x!0OAo*{e8*UW@3WJP& zM=d0eMKFW}Ke{%ql4z{@y%TOz&qD!34;TSq@1(f`9X0aGA-r$PQzvqFVaFZ|(Hi>@ z&~Fu_=@w#kB-Qj}YZYO#FGlD>sgI`K2aFz%sOKWLf{;Q>3+^I2OP9~hf?N0Jg~Q7c zygJO&iE=y?mPpxyB?gft3uNo!MIO=~u)#pAbkwEypFDz1o2C@eq8SXt$c2T%aHdql zW2+vzskj@FCxXTC^V|e&+=ULM9ge+-92zKHM>atKwqP(4*9Ad`=N>*empxetX5zRi zNvyyVJijX2*mt-XY=jTZ;AJ>sR)I6?C^(DTD3oHIKReB9m~^lni+(+pNrJ`x&V9pE z5}i8+Chd(cOoKYBHjF{G#HIbCLJPO{5AH~}(h29@Us#IB3I7gcc{;E+)fO;{9+#dAc-c`0Z&?+cOI184sMFtRcIJyjMk=&PQ!frQcv71 zG)v>+!rWJr!X&UsZ+A3S_}A(=-;~tES#*i7@Y9Yjxz*qisQKB4ky^caT0mc)18~a7 zf;X$4a2`0w!h{X6f`Z>*`dbyrqr6tV?Bn2{VGi!Yjs{5H1@pSZB1DA1VOyBAiI@Dh zbNr?#ZP7g4AI-_P3_ZoJYhTDmaO8X}FTZBgA=@SXAd4Ie_i>QkHbP-E=xlx<`^$!c zq~&&1-8%zkSr{L0xFJ2jKcCo>YCQAS zO8Bh7@}<(U58RKbf}}X9eDbR{$Y0=WAjZ$-ke$H%cjkFvfBLid{tbU|Ein&W2fojd z-h$)t!ih1HwU-b&f_c@Z*fdHX@*o()xI$7&D@L&`b>o&uzKq}M!SCy{A|yM)p*jEd4rFPEhm_F-2n0gi3Ja2|SkT%agoSm$en5jpo z5*$jpa&4+ijt4j=T2ns9$JnE0;ju4;Wnya+qJ-2Qb<>C!+o5! znZ{bH)pkxixZumBjK6^E-{C0oMN!NF7t_BSaKB zC32lMV!q**+!2$fNAVB$1*Ki=baC7P4_9ezhR0s(!U&CE4}6Q3rt@BswV>+}go5ZB z!art<^uGgPj5oo)4bd+L@W~#ZyqOeZaOgvnDulT0p zMK3TEzI~As^mS#sqZPIJ7n{l)1o$kQySiq^A!p-)4{@W<4n!UFbUmd-iIgEl40QeH zj!x8Mtji!KP;T!f9ZQ!vA|SP`8bs)W3f{r0@N1r){lLo625L5 z#;^OW;Qu7y12i?Ai;LZ$@MXoVbq!99cDRwut+7MPkEd7yK&(EhUYA;i%7Nw_gcqDEu%yh-R)Bs9x%Baf{+W76em z6sQYe*nvJ4^TvbJrz5$Lg!;o=JkkDog{9fA$ub(pv%!2O=3J+N^EA4ugS%bgAm5j8 zwuyRZAmQw6%)eeR_oHI!sDs3Y?&n{(bJAUg@=GU`u;0}a2JDH)n_G_mfL@kCxqYIs zP6Mwa;nA>JXfH;(V>~H8^^|zc+rz3wO!r1=;b;Oc_ieShalt6Nea?jFYsAvcZ%byM zF&DhVc(%cDNL=Q&Lb20b{?~lWm?w!Plvx4yb#m@J3QC`uB+3Ufp(ZhF|C#m#&Doe^ z?j*BSs_8^yRIn>%z8(NX1cNE_0KwpF)G`E+QAUPiUipv;b*O47gmdO%0T|I*uP`u{ zq+WLStVzAE(V8}{DA{7kOqB`ur1%DPQ{`lfadTBBcz8j2Nlzv`0(Xx-w7!i?;Q;d= zp!=kGms(o1v%_a&Ebn6A6B|JFj`Y`IB6T3T#v3^p$W60(Hgix?y)&M^hadA)qH8z& z-Gg|QIdB8Wc&?7yf()RdWinm4a8=h;+Y3dI6As32b(JwpnIdhRWwHg@T$N&fy#-pL zrS6)RaQ~KvxiibwPYb8^xu-e{jMtqr0@r^lQ!`-nn6BHjWH{BJzEl8H2 z;z=9&dM5a*g=|vsL?0ME2`hO3@K9Z<;;tYNyJ_}hrakdh^`%kDi!dOy#^M`ng#ll_ zhiXTF^L{9U2AJa4oMFmtcej=Tw6hJonz`spGfD5<5}4q$aH53&vE$RWVMv?p}<>8mc*hk+p?Tq3zlEe0VZ}aJX?$?QPwh>EIW#gnnG7zinj^3U} zvuVlg`|6~@9;3z%1RH`8W!;*PrmBpUHhg&~yrg*4kyjwPB-ocL@*k zG@We-L{;1q54Q>=>`RfLn`xjMZ}2iqp-~uyqvfD9f{43>X@@0@vO;6|s!zoNVXe3? zKM!leHdGauO3$YmAN=ykK~M-8lzbL+R% zno=IHBd1R08f#U5+B-n;adZ11i0{92_1PY5{Go(OWC!(=6fKt!Db!p4L`nf8pU1P- z`%qe2+ZXZAnUh~@<@)0`UBqJJt)^;fz5C)QBr+jCmBF*NSW2CA8i&bF-j&^@U$wW{ zx3m8yvT^WEZBqu6FzYP|UpHo|dvX)3P&Ku8Z)IW@$NTNbOtDu1KwHr}+Ud??8iyg} z?2H9>I)OeEXLgr7>20NEoh`8gG>A-hW@v_0L_NFb}@MIvSj%PAT_#Q=u!o%ZVOG6g&9;7xWS$^X8WRUf4q{?C&9C z9_LAFw^NdcM14=xlbDFB$?x{POw^$EKPy9wQ=30T`7aoLB zXk0_)^8INbvDtK#j`Cc)L+d5rgN%ua{J&!g@6 z{^iho@so|VyX$JN4ad>RN~1c_t;^ceeOI zV2JDGf`*kkni5}npW(~#fF>@Fw$>#_PAEw2Y`0EB`e+R0=h`PqzGSQgSp2#_BqKkx zh1gSDqMmHv@L{BOk~dOzw<_2<)n4yXqspD}{$D(e&lloeL)N1gg{pz|d=HIhE%4oG zS(W^atn4k8Miy<)`9LH2-??=ic1GZ&C_a#Nui`tBNVy-S%t=a3cxSa`uJ-+iS+9}j zheYka`cy<|M2;iNE|d0qD~NJd!HG$O1z`$70=creE}hts%_soNZqn%@+a+-9Nm7^F zL5*tfl(?rr=<-I&+%C9?7hID4vN&!gT_m`7AE^(MiaLF|?Z5UpEZAm8{%OWiC>!jqStJdt zxixfqMTiJOpyM*sEu$l*l2Vx-Ne720UGJOzK%3k?Yy`svyH~Y_75zm(YuiDKauFS9 z%nucz`b*0H)i7#azl=Vx(vdm*7;}qTlb=;2y0}{X*L?JJfCQ!$gPT;q%*tlIhjX3$ zr(j$mXAzJvKHNXAs)Rn(DXsWTkA6GlK~ki~R7l~dun(k59!FK=@x=;xjUpligcLS9e800T0A>I*lGif@b2FXvs|$Kw0XP;{1~ zV^&;^0??y+*5Qc33w_m(|GBrKX`%1eH6&RKsW~r2jVuxx9L+6y4POnxOQ!Y$iHJfE z8+#oi1IZ)Daaza4@>3Y}NcufrO|9b;o~#)gD)3PBH9fjNeCHrK*bntUkF+%2ZLpjs zW(9NWo>K7W?1Gs`G<^vuvF|znpnB2`e-u-XKuclNMm}f;CQRdSU7jP$kxyPo_~dcN zUZiGACI+60G=^ACQGZ446HAo10BhO{@kP-)S6qLG z4Sh!CjYnriNZ5ACd{Gd8kN(P6 zvk0LpfUBt!uQIDc=a9tE$_py1?onHp;iKqDU28AIUiSG%MaT^zqJn$i94Vvjm-k+e z?G8%Tdo5Gd8<}+&?4}fFCm93;L z({Ox(UeAxvHIJY0)x3=;Pm-u7t6y1*Cq|0Yg4DBj!f`!Jy-!lnmh`F`*K`3I;Lk^E zO>bc6Cz3pfn*<&?6ue0o2epK!``nz$G0H_$By0ALH-=|SV zJ+RPTH|h?jAm2wY+hjW7wIz8DS-AaqNHsbqceAC;2bOz~&YTUE(Vn zAFhmm9{UXHz%UX>%Y0;+kCM}-~4{(5H~!FZ*MQ`L^Q!{gm9BmK=K0WQ$!Wev(YWTn6-#9!Jb?Z>zWy{%jImjCA+;9yVDcu(l^WE=3r&eWN0%VYX_x1S8YDG_w#U}N=1M zYL1-nZNtdG2Ud)N85jJhD>ua-PXI(cm2luyecb5o!j|I~6ESD@vr;yJQ55xXGB*Vg+Nrq(z85QY*r6!E-U26Y z{U?z*FqT6SL6RkWaNtXH;D>7)mqmg3%@!X=)J5{oPdV0?i#dxmI35=o zgeZC{#LLL`WuY~G1`CHh$bMMyU4ENW_oH(uC&o!G|NoFjEX z7u7uDN+ua6RR90S6&>p3XC1mla`T=c`N;R`nU$O5C%>UiR|G_K94&+Vx0dq!S0#t& zuWbt!zK6ZN?DLxUvi$-s+2DOBFVp1m*!9{;@QZ@)$%^t+#o~!DvYEZ_qIG>7`gWL9 z+CxYo1uGv(-387VLX7L!@&Pd1-ZuV2epz(Z;8yCq`H|-GOQXU_IBAD7ze{H$9;eWx zo!C-PHzaRnm+Zv85Abf5SCmx&2rfBqs===PRr7U%uB7z;zabH@DJk zg1N^5Ld^&KP4K#c0QQXhDLde;=9fov{W8FicjlxW*GYYSyQ`xpJ3CqL%m zUJ)MiKajv)Qyn*L&HEXI!tV?lC;9YqW*;)>AI}SeoDr3QVsQy-_?$42qgNS%oo8M9 zT62sZU&J|QaKA#vvy(gx$$JL$3r~+;&WG;i6{GN;0QR}D>#t=#UWV{{hy9MRHyn{j zWX|ObncVZCDu+Tc&J8uxTzh?dJM^JVFQzKJu`WDMusGD5d5+Rplk<8k5#pu0>|;f8 zNgIW!xSdwe>2$IB@1pW4NRK|3SXr|JrouuAeTUM%ONv`Ec(m^iY+s-K7gD0(C~dYC zx5$7rXc5iVbiK>@@)>Ni^A4CpqAy_ZFGbyRyu0qW3McD+pPGW?j#AZ5Pw~^QMd-0@ z^|aO0(iz2nGOVMKiSy;lk}4Sv*PUW-oI5n1cGSCprer5WdT_bHx%uEXr@kYzw;Hgl z3J6Vbez1NKTo+Sy5b&;s6+p^A*qtbP85Yy$Gi{uLo*=^to9Li}Y`XZR4EpP#ObB{* zumum+1#<&7AcmN)GvzgGMlAVUsRm?AfH7-YncW;kZc1FZZEC6ZI;I37qiIT9H3^{I zM@eAEbq<12+G=O2m1XqrCER@|F;c|ZzyoCup$rbG(rSW+gY7QDo&Hz^a#C}K&65Gw z8~8aTp0`ruKnC=8jf}Zm5Q9ln+wDTg`z9VuKY|vAsY@TLO#{!MFA8yb`@EK6T+Z)= z)RKRT42LG&A-7nmb4gDFL}XapS`O(I((pu!rk^L?d7b?uHmfzUD&)JJubTNcxVLFX zz?b^G&&m^RgXFcnS87@+Yh|q=uAZbD5H^}Hx!-vEG^xK+iF@H+^ru+rbtG7O^zpz| zRQb6rgEgl}rk3`vrRrnD_>Oy3J*yB7I2u-cVoHtNj+;FXJ$Z*N#WF~vp&P=fJ@ye1 z+P!gU)yD*hdpxUDa6F~G#9mMZC$F3yfPrGQGxT6sSp1hD#a0VlSXu_(^^VTCt4_uW zH)-&5EWN!-a(5tLnQ(xoDFtGi1JUZYA-EXHbN>k-Ej}O)V}Wz;+4;24nB5kR*fCG5 zsY27G_NvvfQJ6&}Z`KbuL2hj0er=1pRlcO;<@i`C&*AbNYOurqnWUBYU2%yf^Q(~I>K@|+T1{mLch`9BH(j^&ycwjv1_N+? zbg&hKaI2&@#o4(TOM22~GQy2JGx#P!RWlvUO zLu6b+R&ocp^K)pZHbVY@@Iy?W?_VW*p-BZ_Z;!22P$RU&{dDB6wQ>18rM^48D=dO+ zo956RlGL5vmn_0RKj1NH7E+u2n{|$ka3Mq5?ur#E%{1Z&0NPv)+I*UN+k@YJD@1&k zhr8lt9H^FldpzH(4SjJWI zZ~1;sy76P@uG@NI((_5bw|+@lej8@<;Vb77u-o?WR8Gd7_@G?!i8ku(Q4)zb5R{9N z8=1$P9EdjD6vC-pbJnFB=$a;tf(w%UNSl>wbEFwQV(y%0+|~vrQT80v-2q$xx-wlJ zVy=K>5tDrAeGi8#$eXt`a4uy)+JeFEh1S%TQJF8o?#pk^@glk8jjzYIVBRfeHqNxR zP4h3#rFBTw{cfM5du<^3^m2cjTCDTHFY{A&0mJ$G76CZIg}Od{E)8Pl&$5hT+W_-Y zIDll;B);yG-ODV{-PZAw*A~(R;Ch9bK;v!Y{fzYy-nfUr6YQ@L7+E@pOeUgEx6D28 zDKw}|TDA#X_xigf6W28AP~;vTlS6*xi>n92$7Ypchk*drm*{)|hbxWXgon#DQ^~Mc z_gTH_8IOUN7m8v$t9!NJ-mFP9mvk-ED1dN4r15b6NSTfJ-(x_xE5i|bm@kG<5|)M` z3scmp$Qh+e&1-ber->~_K>i~DfzQU*S;lVd`8GdIFti8ieaV%?_+y3SXdV?mW`TyR zW~lyqmEU)(0;x60Hzu{=^u|IL<{sQHq-XHpG53>)*?)yHEp7R-h*){&hG^p7CFkZc zCmQj)8&fdm;f(i%?s-Yn9@QMu00V5YWxDKARU0y#&c?@E@<9<7b{Jafhw(L2B*^oBp3=y5<=75MMKg zISQ|7L{D9|;B(Fq<9}h1@6lND)uphfe0Puj#L9DwSA}P*0mUc(`rISbM;nGU{2Z9% zP>M54di%~ncA@Gwr-7G3R*OvOkUHpa)K?)v|2V>S^bmUt#}-0IcHtqPRAWbEbu#=k zgu&gy&F=wG+g&Nleipn*7@Gr5Fz3yN?5M3k{j|AHTjUak5#qNiI~dM{Z7XlX)|5Y< zIl|bpSLRE^g9{;aF>TE_=(}=)t=`^s#?`kTx z%TZ6(V!)i?mIb}d-?~1+{+v9 zA2_wdF9Re#>%~`W)J8?_rBsWn`oj+(l*#8$b}220(z^axNb9K8B|-W8YI2uJLag<4 z6j)#V{2B}#FJK`j_EMW%#%Py`H@+X7vv677?=-i_M}8555c69fzT$3(J3Y9!H~Mpb zl)SfVG}t#59KV>7({w2Kl46icgMw@8INsR{e@IvJwyfBI(3SOUIv4|`U}*b1p#Zr) zw#br9B`ek~M;HRmh>V~fEF5j*>WRl|=gG>FUX67rwWOdR z9NAwqzC?lD6TR@Z^boWIBmD=zb)`p}%;W#@!rN#A#!Sap{s&H1-e8o0yQ{9BrCM^4 zj$LL*NMl9taCbER738dGg)WE-9)lGbF@F;zByh$auDUv?{Jj33EiLnlQ02yeQ2``#Z@++&9ZCQ&V~u$V*Hu<*pG2rOVr|xHDoc8QCDD+; zeX3v3S(Y@3R4yRjVSBhD?w(8gqer{Ap6E+DjKi`rvxxFA#zhl0h|q$BLvuaxcG>`M zNxYG+08a+tt-f%F;$>T#p#wj~*7xa#{kwbsF@JKmcSZNJ#6$mu@z9sAEdz_%`H_sC z4bgT(QA%E}k~-)Qd##s{Oy~JReKY61@FN0H2KrmP)_>K+-Y^z5Lm~ltp5V@d$8Pe` zagzH&P6}$pOx)FeW2ySLAK(L(I*Y9pOQ!q^8Nc?4%UY?ONxX5W*qK!(MWmW*@1TX6 zP&5(q(i46n1C(?_Nn*1cbQn`3m1^7xmpIIsjS-fdnk1Pmb&SJIdaO3sJGqW##2|Z% z*On2ENf7m!0s6509!gp( zpL}(g#G*n^V&Go+?FWPh*v6=d#iv8gH%iBy-|~$Or4Az0WY;Eq9f`4ZBUNZgn$jt+ z%{b@mPbONLO(t2Vnc@ESB)Mn-wzarxW@e1Y#z4u&;af2osniB;!pi}Z8IsXDE+3oZ z&@viRVUH~AOr5fWfS*0nuX7WG685|Gv=u$+JQ|1Z$&8^<6&e#5-7yt@7{iz9-Yn&t zz5FAyq#2=l6s3#A+d&}UfN{@zOS5WN0pxHod8Uwxq*5DIYT`~Jb!>DAk#tH6e7)Au z9EKfJhM|=&kF22h=~eDZPP4I4lX9is4uhnArltIas)U!A*@@KPZ%9J+)<#cIti+aF zh%=Fj&}O>RsoG|NMl0LunCN|$W19BzB@lT$JD|L=Jem31Z_AkzSijU#4oW$hkj>E` zdZf8!Sz6Sw|CjC{KPD%8Vri2-d)x}f>`1C*A{PcV#?PIUIRv)0*sc7SBX>y&2u-u2 zkdblip<7P1Ai3H)9yOD1spND1?$&9XN<$_;mI}Yv^8z@S^rnGVmZT=+P1dvAR?omG z<6y|&u96&3;>)zNuOZckMAAOzplZuRr{#b&qz%Y+v_*bx!vCB1El7luws8ge$rQ;$ zOofRok(=M~Zkd&5 zBX*sN@qPvSD)mF@JjD%TJ->LS?s$7hxl1v2y63DXp|e1<32NJg#RC3sZQvqB^h-A{ zLZ;&M_I6%l;JRBcL<~nDS;X{pBzZW#1ZF4p=S>|BV#W}&=837?&p%$^rUj2r zNF23?rbLXWhVs#*p#KvAu0@zLN6HSFR@)E&g=Tm_Sdg|c`lzRp&2-O#7yNPwVjNDI z?DG(I-cQ7RhUt=*o4ru=YayYQ8FE4Xt1+eV)9eJLz{Bl85n9StW($(cB9zBB+X~&U zM#&z8(n3g$dvD(5Gh;lv~L9Qog~AAqIV*i0{_`wpI$q z%}w%+c_{5F7$-MEN;iZ#mwk`@^_?m~5;B*uv)3IzA0A+MDb@~SYd7^IKrj@=#0Ee! z&cMUX-fucD^>!TJ-z~Zb#k2W2Jd_gShz1)7ddoh(!yJ+r?7y42$(c^{C}}nu(|uC& zbB!H4VDyZ9ya-IhW@|C63bz=J`dA%e$uqdRng#_)NFn-~EpJz6BbEITg02y)Uqn&1 zp-4gecD#%pVsS=2gJ5SU`hG{L*pQq@dIBH|`id`<^cB=oHiQgS2Ysw)9t*0{m7KcB zNA3GKL12fZ40%C#ZRSAS&P&@%enqYT1#jBGT8%`h7o!1)?cH!!Pt12p^NL5JVxgjZ zhxHN>m*znh_~tj2&M}AF){ss~_zOEGF3XCO&<-!N-H=4*OSLNBrutVrF~1flZfZw- zxb`fO_edzN+d%(!i@fn8$#o#Ef{2yQ*6wan`83v# zMBqYxM?P3GA;jYa+EfZLkUZ%)t84;qg5OE2eGf+ZfiR6^np1OTIYW(6L`enmLvb}?>=Fozae z&0wTjtD$7sVM8*k%D>lMdySkVyL$^#6WZao+|D9KPo;v?%y#-m_`@)?GL8m6N0eK> zN&Z@KlF}Fvx7CAuxR81q`BlC$Sm}S;EwX_=x*XeUZo8(__2!t1R_KX96w;2^WzK8u z=n#0JkTfmthDe=YozL8uwxrXeMBINKT+!=iqnvu zoMvluyG;Z}d-9h5XZkuwy=ZZzt~e>E0a(df4KqW)AFM5CRWY6K=OEz{qABUs3NC5x z)XUyv3qP`DL$Au_QFsaE0>J&Tdqkwmv7`h=n4J6JZHizKD<7)ml6<;j})LYxj zw_8XOqM?xH_nCrm2#97C`A<1P(m&&IAH2x8;yzwqZS+j-n#CV#@aq^dRC))B;1a`n|8|`}qCg@tDQT-1j~AT=#XoU+>rR zrE+jwrtTm-N1bORpvR$c15ig$zu{fwT5#l;i_ZMq32!Y^%sb<55U>>VZ;G#w*2;c9;g3;oGO7`$;da zj9y#zd)4kimJd_(>h>H5Unzp6PiqW_W#xF?&DTEDC84k=zu+2`NQp+?P@yS_x`W7U zdiS%oz9*PXQ+V#L|8%{XX!9;2csOJq_(TW3DjCg*I=?g6`^%SdP($Rh2AT)qC6d;C zW?}iXhB+R9;nPUG!R3Mk5~%^^a$JO%pMKCdh%Bs`Kv@CNOXskSRcb`$EGV{^ zcYzd3bqjAX>0kljUMcG}z{9)%Ewlxa5xI0l{^OS(B6@TS9skZUbz7X6Mi`p!!^KOAf>+YltMJR7V;7*{I#* zpe~XmChaMZ&PLxYV_h^f3GL;;kOZ%;m~2VJ*DT~GhBGSCNb}~msuP}Bu@4Jf?(zn+ zb3&>BwgtU)Ib7@OJ6IEQNAUxsvuY$4G1+tjQi~LRMB?@#az8HwyQBUEy8j-lypGH*YyQ7g0TS63E2Dub7>`x)8Ti{YCH0X*`Wo-Be zD(TV};1idz(`DB`>KH$YxG)2ck!|;Mg=UMb#5Kc&5^!?Av&kOW*Yp>K1P0aG^A0k^R58%tLPHR#4)rOleoe zdZ2#i3GfgyG~$m*mv!s1@_QhG)qpshp>6LVtF^AFoo#7Z#4SmiAH*C_sGc zH@KjKM!mI?)$4#d5vlLA0xR0ju&kz|>$hch^W!DwpjlzT zzi90!*{QGQzu~|MI00{-TdBNi;-~f*I{9QCWpYu|EAoGBWTnH<;JVQXwk%`E_o2}- z5Mj4FFLQ~|-_nSu=2gkPX_Y2#1DgK1Zrfm$fx>6<(*zNK%W`9wD{cz=*}+-hgAd3<_pkS~z= z{~Y~skKDf^s5FW!mm%T%(ovdgti-FWel5kuq%V){$Hh=z%k!d?SJ3-f7JQK2j@*lZ z<+Pd7S68xp+qHcAhG%yEZO(Dl<`UP0@H<_2%M%uB2RbomLc`Hhyi67PLwOZaHEx1EC+}A|_2gn+5le+{dhuS4WUpAhxE5ioy zfDaCm&U1?8TY1uppk-yeaoriOPRC?jsysgoDbaSSys6e;N8QEH-ipE`lFh(#ti=e5 z!5D|_!-5$bf}N2hDvIUX(f7?@Wb0@-_DiQY-EH7Cm1bBBJp?y{4T}*HTYT%_7l@OC zFkiMUUzORf{-==0%$Jk0#+eB9$8P{jjUSi+PJr{S ze1*nW=5(eNdyEYSI8p`_lHUJZAgi!mpm*!&Vx z$^ppaT!{QIkQWeYYvd9IE1M{dF1y3cD*W+soEE^v%R9&F{rUCm-I2=EbC4-xSti0w z7w4{~r3`aB&mJDFjGhCN)XH(=H7`iByaafqhjb2 zq9*}TZ2wT)0`y0iSznk?y0(eN()6zII&CeZQ#HAei{=G79UJ>W^l9I>SAm1D_5=T9u|Tuf>5>=Jo)+o)$J zC!&17Ey(xCj{<>L*4ay-$Jh#(HYpM)DgT(;9!YP;N_UE%b{v@Rgho#GXcM$!lMWH_ z6EvMo7POEu`!j)JZo~d`e2~?-c{**TI{PfbqWkr;eV$@}nF%V&8tDtmrgH=NY=<+e z3Eki)(2XkiPr2dA0%{4GnykKeG=n9+!5Q$lI_a0_A&YuLpELMIO>iw#Vwwd40t0xN z0*=MEAsb)nhM3buv+yY<`1~VMH3IwhH{A_c49V-C-3bc~tHEfHiJHj3WM+91T5dX2 zHk}y%bod{y;bkT2n(1;Nty9ynJ%D@xT&kcEgGL)iBq&kqbIOrP62#wSNKcX1gSc9P zD?znTvg#5xE(^HLIDJGx9{$u_pPJ19LKDI4z`FA=S`PJn$5_9OqDH^!J*=H>67Kt! zQWR|rgq)zNmamqUO6YWRc12XOs228Og}nzZ2GDL zF%cT&!!j9|i8(emP#LswP}?AhP4LG%(g(=D<%Yf7?gvd@#~e!mkr=IM7?AJx3KQ25 z|F=W5M8pxrcibxZpU|kC3?v3kZO9q6b|AQiz75WYo&fN0`ASz0fA5F1T|zukC6wKc zCM3{QM8T^4PN9vKW=6mGC#!ygGlE>-Hcu@8gS82t(h+Lm#qhDr#MX(81Mk{^X`;!$ znkmv?k|7MjJ+d|1Vob-cA`$;g4G8q0y;BiOQu3Ag@ZSUV+Z+h~`I46A*wJ^a_m@SV z0rV;GKe+RIBc+TaM2U`-$t53!{b!{Dgr)wr7~VVx>Bxw0Jr%zco0!ul1{)V%P;XrW z!O{u7v%CTjWK5_FSaO&+!EHXccXV5(lOXxzz*VwnmXUzsz*RuYhD((zgp(vK9fxGw zyr8QGySo#EcS`(l5 zy9IX%ZgC=dIt^_uz|%WviUDI|-Zv?@Jn-2{YG<8ny7+%iXb+OLlOXe?^MB@0yK;t6 z6rt9XJd$w+`d5&k>(CxjC_ak~5Nq8@B(Ay)$rh&CR}n5X*5)|sO@k=9Q@BW8)WF`; ziJWJ!kC#Sx(^{M9q*qAAr*Yk#;!Z<JK@ZM)v0MM)#(xmXQt1{G;ZJq9Yrc8Uh9nMwpPBALPteeHts1>`$K`d~6 zQQ>p}BQ!Iq;VUvzZ2izgzZrWh*FA0ms+pf#{%evA>G5p3=y&&-TBG_D^OGmPIo!6? zZ}^649|GEV16OLpKx$G|8!UT2kK^^w`$-LUW9d^+4*@u@2WH2VMe!m4MuXM_&cyazOmkWGLEQ>0;S;mRN~vk zYHgS17HB_uRaCxPIX1(R|K60yi`9Kiec##t^LzQu(x|P;eth_^K)E!|;c;^n?bm8g z^rwuRJ;5osIQsMUq($0dHLf`7J?v)k`7vOUea2f9=*4x>&rLDCJ!OrH=N~0CTtJlv zyqd~V8Yj;k#KHHL?)xTUce&7h^s)!@qzXHP+@}~XJ?#xus4t+``hv^ifsL^(Om64= z?S3fQV?;ZlzUV(YOBn9WZ-~rIf+w?nfr zU=jMEF}gc*^?W<&ilvFo+0dKH<@^}Ve)5?;gx_dYEb_1mCo>f~u{fXI& z%1kB3tfrog>VRp@r}<4Ww(StP2D@!3UfZPEi|fto z`_A)+-=DWFSK)x!#}>YKKkJ(pJ#VhduQz2838JS#ujp|QJ@p_}5_{xqDzrP$#i#I* zi&|>MlvLOsXqRtt6as#i;uJH%bDB`hj!yDxkp*G97u=x8G5Si2S&hDoLjTFsuTOuX z&24$t3UTP8a7=Qd(RA6takY2-n>;{bLbg3>T27bO))r&HV2Be3X|Mh zWqq!XqHKDg^=_UbYTXz;UZ6MMg*!9FNB}K}YibsBkcIp31B*>AbdT$5>2FI;OY$7Q z&kL6*v|u`L=D-skLa{=s=7+Y|4jg57!o$xi;E%xXO!g^w^$LsND`0zrL9G5mPs_X^3rRu@d$j(}- zz}%zAIi+MNJU&VXj20Z`E^;_H);rd746N5m^YQC~F(V#F8OmH)z>S2sD5> zFLyg8kAU-Cm-vTM>dZX`pKR`ih}0>=j6Nflct)|}nnF8yM>XL)p;TKxdGyNOohpLT zqR27}v|=MwQrLdd4T0&$AsFgC@?a#3^R&s^)lQXpfQ5i}0>?8PfKUv=_Za5TH;6{K zPI1xXyAK>^i9J1$f7Ps_j`K@Cl<^$SXd^7Q&nmMj7J$u|{x7pcQ~xaxizBoig@6?g zv|syYV^1&nxEdizLXOXie>@%`m!V}6W-4$do!W1-S%BO8V5~{{3W}?agnLMJ9a5=T z933qW9e-6NbyxwUv<dDR<9y$2N>xaHeYk9L1l!oUcCn{JZNp+W?HW z8l@yjL&03eCiX%bU z84YHMdyRGb7{l}Da=qbUdLlHgzy<9Zl3T&DX|&4#EUWYF0CA4{JR5b$kL%qP-Ok)< zF#Q54lG)Pc*t5xr>dicX+?c-d5-_(C|C(ag!%jaYJ5%G*UWPvU5g1H3d%FD8AJs0Z%($rfm6a3 zTOH({JR26_Hx@TGcMdXj!4MpfY#;Ug-26(wD0roMFgubGrQu%%p*L*IV`Y~+aEn<< zd`$g}5UF->6tj|8Jjio_iBnEJnk=&LJ6IMPtB>o=E8|*|_)7K1H6VA?_)QaI9j@W! z19(OmxP_J*j@B(9K|Qw+U;v;TCV!oYBHxkXr5XQ;B=~a&JaxaT;66Z_94ZC@&p99o zfr-F(wwr^T%_b^BLx3C<-Oeb}x3`j_7RqmEl|KEA-L@FF4#sf^G-h?_hvKD#^UXEry zR$45Bsub`4I@!Cbs`*~@XLgj4hnoVOa=~1LAd6qxwG^qxEUl4dlP28U7RCg4>?%mc zSA?mL_3lD5=8*2+9{2-PC07gk!;_@vM7M=ymAl;EF|KeYi$^4uCp>Ip9guHcVH#a5NoQpB51Q@`0GIS*+i3|?Qcz$E z6ciCfLhv8ia7oknz9P0NtLBSMRxBsQ2`o*6Ax9dGEs4n!gOF3pDOAdy*PHXt(R1J8 z1Mr@IN^csC%fLIn45e~8Z!9NeROfjy=T6nEZhna3uiDD%J#v`KSh#nJz`5xF$Nhy3iJOcaO1Q#pVGnmw|!Q;2EaYdA1 zON+EDg-44cs&GvjeRE{nt=5E*2e+_{cPYZo|Ct_tcjR;zHgpUe#YFXA1oXZ(@}*_Q zwVS+h^z?lJM-86AG97?VTU*+Xjib2Ts?~F9&i}YG)j@>H;=_6gjJb<+_c%=7P)vU+OW4q{*P3RY%}5&Jy>{AmL;_E zqzJ=WPuU=OFYyDguNN0h?uU)@(ml$JNTiCbI6bJrWKCvoOx_;aacls0-=xf)75Z9P^#ug<6oA7 z8|ApygsOiC*DZ;Iql3`kv<{8U8*O8Eehv#`M+bk`%`=JJS)3q0jFo!rEK8y$9xI|l z;PH_EjNZ`g4(1-0>Bj->%LV1E7^p0|+eqCm#`5(+bqjip25!^9S~nJGR@K4DNOhCmo&9-)Kb@Nh-qKfYvMji~)^D&bU^0MAJRiD|jB!bmK2U z-yK4`LaA0TwKL8<`~hO{a=95Lh`+0~5_8)ZHbE$+hcDYX^g3)Im@}aXHR2>}k4PY$ zuG5Qehp*R)t7f^i0u4DP*awKodG>pV5c}l}KCKrm%-BF?hxwVV#uwiSLNg1|aS%Z~ zl~#3j&sQK3D;)5avMf#=>4Dqq*W3(Q553@(7v$}cOCQsGK)X!Wc^dBP9$6x!Qp%!3 z4SFc9dsrrJa>Ub2uJP@@zw@*Mp0^p?H@1?g5zL#Dj z0T-mOW`TR}1jV{XWDAGqJ~fyD5M~+e66dBMYNAOoeI5!qvAC5Unf2+BKrg-MVtRe4 z$4t8U0EF)ByciOX6`$H(ss*kfd~xC zap*Y#CVQhZ&dd`!P3>X*4Mjk@IkU6z;&jYTqI)#_lZ&@ejQQaPcm(yNBs&ho#JIUf z7h^vFK6_fB*HiB<75AYBU+$D)1APJJ$J?R7P`}Ad?_3e?Z4c?8bNF?yyN}G9I(k?& z(>xkfOh$rGN0P{NjD(}2)O+*r_dP5wKYH|y`D#UD={Wk>OUPRdmTO$4r~5HjjL5m? zW}EA~_plzI#v~8xTU;-CU|hufBkhjQ3Y(X7?tAm>2Bv=CRKx{J$Pp&_)NrJ`ZN&4` zW|95;56OonfeQ61;uTxxxv$c0HNMB9xX4A0G~U4oV)fRsgw;_U=@UupB(sfj#JR``1nb9N#DER2)bOTL&SwZxcYg|x+wq4^;# zO!AHK$ozR%c>KPqMWiU72)s^;Af_hxS~N>1!iE%b&k#8;G3pUEVIg7762DfKt7=9g z`MWoCljBtR`2RKd^Oe+{FXVrpi;mk1m{PQjnydboVHIEZ z`a(>|y)XWzgX?}HCNr+*JQgYAue9~W)I?tNI&Gn*nC<5VUk4?$2PL;wDEg~d@&EzSY4N$ znZH-d5M2?OM}&N0(5-(1T;I*FKW`?7H0jFWjhet@4|H4<>9Q&s>L{RHD%EJL2ITB; zU*MH+!i-i$WdkBm)-9mZB1mj9_jWI$DT4?3E28?K0LP4jUuFkhFJZp=k!;j|zb2|I zM6ZuLve^60AZ@2&g?4;@72$iNdL8W*Fcn(Y0Nu? zmI4R9aKiO%1xCI?=Iheg^xGg_ZrJgCV!bP@<1FXX>zHq6yD79<5(mm`blA-A%Hf_$AP^S5z(Vebr{ z9MfJBScFLj7?i(2r^eR1JJ;tY0qo~G1}fao2P$tsqztOM1u{^|_`VA1&K2RbqINsr zc>Y|hJ-pP_MZLV*$-Xe{a6Nf1zbi;!8^t-z&i5e)^!6HZ`tk-}j<-8~S8X-{P#H!`Uk)>Y8iI> zz2(r+L)OQ~Z?!`w&V3n?hFyvo0EJH6q`0<~V;i}f=6c#3<1PcX&|~2XEg&vgtwH(m zsCSwuR5lja>q8JVu|9A}I#fCqqpl~Ig0-#|-*aOCI?a4lLo1hi5jYx5YA6k}GM~oy z04IevNr}phHGe@)%*m=NaKNwTgAAMv)fPeKQHFPnjcVAw`L&71b;jcFsSru1HC9d5 zA?Q?HqFKxEU5%j_^eKYHbqFulNY;t(tlZ{+KQ;?QW0l4sJWHb+GA)l?U2!M95pB1xzNB;Zk!ks^9hWN0jeqgNqViotc=@ML zu^1cMFon?j?yYFW8?2BFw+8>c(NuZ;CSI_RR`Cq>^TY%Ho%C}ueE;l{Hr^VWp{Q-= z60P$jUqf*N;&JblShq_FKGUbjfC9{Qim5rMyj+6KO`X0=N@rw@9_^5A(@KJ zfSu$w*Snh%tFi=05oHL1Z_(Ov5&vkb)cdnwf(93%=y8EuE$1+gS8!BFi8mvI>8`@& zm7fL?_`La@-6B|9c66XPU)e%e;kV7OhAoLs>P?I$RcuQO$ow=U{SQMt)9LpKkxU9e zxwXztVF_8QF#bT!UUMwQGpw3&|C$;1l5jPwItD%ntQ`Qq0(=zPwJ*VQLF*JNag-yR zdJN7(STv^pD_Dum=^{D0L@pM%I;{0VBf@Cd<@nJC{K{Zj9sE+~hM^h4L*HM$N6(B~ z*%wHHQ}8oh-o?Qv_u}Es!>_Y|4!e;>`=6Bn2$d~v4lkcx4F8k~-k08T*Du3%01F<$ zTosb#NAa^SJ|lea>!n$Wzg$tD7RZ?K5Ar6YAW)d^97za}&r^QXY8O>n#OKxZQ> zXAwJ`P;#sZgAHPjZICq2d>XJXE?NSaIB}xQM#|w#_C+Ihy`f8Vav`zYJoPL*yb8#T zvDCAtIyOSFz?RX5@qD{8ExNdar6rj16XPBAqaP2U8f}GXFS1T_wjY*i0B*8F?(2(p zr|L7EqF)veP0Y!UvPm;0vNuw2%Ca|*?Vdfh78&g8wr;oA zz`*p0w1q}|ldu%)QeN7k8amx1uYT_hUsI4n{B}PdJ4BUyh$%z)y$?AAJ2!#x2z*BQ z5n;xOZT^|0Rufs0gCOJLmH|kkg_SYCx_h$fEc13}e1|K->K?3%?!Nxp9p78 zBYjz#?ZJ)?@$;94y$9pq_J>>uWXHFOiRMrO zTY|xN!@)1aVdCn@n31F28+b5_XygJcV#&2jNHrfvoe0D%d;e^8;Hu62B-Jk@z_rDA zj4cVtTEocW1&+0)Qn-pq8NO@=y^7WkAY)w7Mc=M^wRvPCLGghG;>8Noh7&mhNEm*O zx&Q##4IOUAf@V*DK07B)m)vEEHO@+uZntSha&q_Z;nR-8p74+8N1Jybv@QOfQ?yAD zvDjkxaStf&(MnWeBsfzxxUt0~P>yoQ+u+J*&4I%wT!zmBv6zZ(KXC@o_NA=)mF%e^ zw{dfFNv6@Gld=I*(kH@w&1X}%o=j(Q|9iLcZp?WnIKxtB{3c^-IZk>pG^}JN#@z`_ z^8hOBlyu#tz_Vl)z6HGz%(2JY;9nRQ3)%4riE&*@ zZyO1izgDMFldhK7af59cr$MKaAu#{7zp+!@k2l2_hFOp6-hEC>VXP0^l z-q!V*^R4WyOM;4GuP%QFjqYgl^F-4TIqI+gwGw+>kCcmT>STZFuJsv)9Nc8@sg|F~ z_Aq~TJoA@edz{RkwwRB$WScy<+)m1Q$3(}Ip*!|TC4i9@E1|xLc!cG45`PFDh^^~K zaavFZsdgCJo`+rT#E3YuEDCK@&6!~w1dTdiyXt=GOiL}pR`1@01kB4Plb>Q9T9dm9 z;GG5kaU?06)IXWP_JM~12Yt(yJmdtRFqwnpONLOqMC_7R7)GOH$kUTh-$S)=xD#nR zbR!oZ*r62f$OtN=OvP)xcrsTX^Puf=Z#p#SMT=Z5)cP5ZdGJK@6F0qH4t2YQs-Wtr zcN9!@v>E!@h3shbnseiREihCIN*kk3-J=8c=@XuhviyJ91QH*P$L`uN3B1DPlh_~8+{WCJ$3m4lFb!EKSw55?@ux=f^G@W*GWhu*kLpMmq*1#2(I<;-Rs-c z^0_7Xv2*Ox!mU%Q)yBPGm}gBuO5^vkJ`u`VQY$!LnHh-WTR7_?8llD~Vi4>11KfWb zi+E^=5Dds)U=qVRr?qOl4f_x-n!NyKM(FmEBQ4x& zx_PTTv2~F>>zkWxsgE$op3>?nb_JFgS3%cNwEF!t(QlnhUH>@Um0RIU*jOisH@QwX< zyI6NaQ1vW*TbfGk4Kz>t?ft8pd~S;Lmlx=*3dvl(6@ILgJUzZ{oaq$lE$GZHqEF^y z2YcoQmBE0V?+{y5=swlea-kWiM9s0uO~yqX05|4R)|5pW7BQEKcV>e97|H*8Kt=)J zv3M62KgFt9)Y1~W39hoe#}X2DALjuXpGAQsLu#|7qX9ov&$9~`Qz}w}){oHV^%XLj z{;)GRRiO90i(XKg2@R*-gFqFocxHLH9}K4k_b&XV{dUhiruIQi7D|3i7l9uf2#%ra zBE&b{Lakt)@PrsQ#VN!%RiH`DcMU6i2FS3J&>KNk zQOdT`uPM9{=vx?)PM-UCH`ykTIs%CoK5Uc;&-T>`N-9={F4$)6l!Z42FnSgF=iiNDl6JXEbb>tk(nk;bh# z0Qd$yX|U}2()6Ue=zP<7Gf&1f735|4_7lJ>KHbBAv;kWi4n~7nE^KDD&!VQ&C; zwpLTrh`~SYrJWnEd9?vZE9eTPzpY$>{~;m_C~f`s?la9nRz<<&(+9U)t3Y+n4)B#h z8K-ag8QQ#~Z;*bHevqQsY+lh5l#HXAL`4iT`KXSH_~S2Dbve!+|SSW*ShA2)=3{>ehAuAgqX7Q;pJblUH~8BESxKV=yr zDz5s+FwL{BxordhV$v5rxWb8K^j$3!-PO zyy9)`(B3T(B-vm8B6*dhOnSxjl+r=!1Y!3O-J$(f?Htx@@L=YAzo*Yf1|7k73oBn? z28Isid;)^uoeqV2lr3z(azlA^q zB{~Gt1#Z}bgmJJ1bC(}l@qepg>h>r83db0Suxr6xe2{BZ)tSK2`t~!nPWmGACkQFC z`M*u6jX!O6xxP^mY~9ai&mT$wm#JciBj612Lw?$%mzwp1;7ENs3Um5P-Va1 z4}N~v5Rq18C4>wF2fF*wwch85)CI*UXtfWirXXZ95TGHQ_o$z_Tr!B~Fm;E{JA-Y~ z>b!Ni5`>8Tc#MFwC$DfmjDm8Q9-ijdYHybaaLJJmwYw)ITMUO&OhPVvF#dzZ6PSL1 zPJYXZtF7h7EqW1e!_Op93&v;sJRpb-Xc$mBuPMYjlzm^Hqna}XG7x3_9?iEF?q(?8xr z(@75f&;+&Z`VAFi`C*`&Aj4`2CO93;uwm>t5lEoB7%?;i3!$VLm;$R}H{!?+$;?xb zacd_|mA4+1?%}YPm0Xk+BfDCYW9%V=VzNGpZv`J(tK2ln-q7pEVV;yXE!t# zP!jFVbQ=4%fQZ{TrGwaRS0!y!Qs00|+pJZbPH85$jK)by8sJ{|5Czm)w8o?(r`S5H zFXq_eF|VhiE_i{F!Pp@1zN`K^lykN0y}zgSaioUzkXCI3gg*!vml*H%6-WeDO?3uJ zqm7?Nm|!kc8k?S+Xlx*z4#Z$|1?Age5E>(;%{2BMKrdJKskg5ugFalc6!p^=efpIF z=~NC|$5)b}$`#2$;;_4;uAIC{9-9``0%65*wK+{T9_dkIUPgp#<5`cQx{xq_e(~Ip2egHJW)M_~f~uilr?vN; zi?R(MzEs0n11-4^c)6vRF@%`@YmWi$qc@SNmij6=@kX;&Wjcn#MNcnAIr|Z*+@qm# z|8}C8DzK-GP8m!WrhDX&i=BE-cy$*!Oc&b4+o=j!Co`SUGYap>LQ~S(eL$T?ZOH~{ ze!AXjxRS;6YO4{2Tb`0;s+mVe5?9lb1FU^^Van8oU-#4u&p#%ah09*H(C_QLU~0gl zwV4vV%pv*v@#zP6eMGr${7KOz<9={K*MAv(Xp*FvD6H6~cet}Aa$Z;62cJ?xOT5h3 zDkohay!83V6RXQc8|0>6K&K@-Kk^n_$KJ6UOkWo18L?}|=SZJ!xeb?)h-E$bz*p3Z zzgI#bUbeu=;aa@hic8r2?3%N)x<`GnCdHVymLQEOL|)dlj}@ji=;{A;nXBSQVTh9` z-0@Fe>|im5Zi!Oo(8|NR4Ca%g4VIO_rV@57QAdpESVqlTme9W z=kJ8~c4#hX0jdpPP%cMB*2NK>#c{16$^ewt7M7DGnchv&d&J$A-QIZr5+(J^jQ3p7 zuw4lz!V-lU)A>L}JM;x5`(#@ixa3e$!;E_@p+T@8s ziYFFRipjMUS;z{07^_tctNw)bPEg876BhVhS?Mq^|0=pP2}xC~aHhx$kPFcx=xfPT zl>@+obI__B&&=7UEl-f0m7sVTuPuku_Hz4KjQNF}!;Bz!TyJkr%?gJk!hN_746868 z-_-e9tTbWCw;&tp`#Xi!WjTr?18KV}Y;5EdB-LW&N+`mYMHXc7cEa$mVGp+SJ2;oI z%E-XW;>hyx3!BnG&M~F0j8P^mkc8^toyw@w3y%fAFNp1?vkVT|1F}#<1*RmZR>Au9 z4yC};3vJ56gvHM1qunIb*;OX1HovP*Fdd}n&Gx}&Hcmave*L4c|A!Y|v=~S^ow}+v z#TueMUJIhM7S&lW-{Oy~byrBpo#wEDMK+ZxNnf_#IZwj)yK&ouobB@$b;Et}-NoQG zU`4<*(c3-E-&n5Hn>e-venS9Wdg#eNhn6@Sh$zv$;)jRh5OA3xB{%*8PEy4+J*jNS z2#>Zsm5m9AjeZY?LrM0-Iru5S&})meDHc?`OoDGC!v!#Z(`Wlw|Mj(n)eXgOAK!Jk zB&mNP=DV-EcPUn}H__NdI$aTsI*D55;^U2x`JBD5rn&5`S6)mH0aQgqIAjO;4#>16 zjOh5L8-7N^tm{n+XXet?hgnHV3joD;*H40M!a-3FJMqx(Gpa3dn{yL~{>{N!ed+qvEHcZHDSQy#m-@vF#Fn5Io zwPLA4M0zlts_-tMcnV3uKW=^eXDNmpqbSv-vZqHTba6y$?FAw~f<08DLvv(rx57b# zWQT7_v>APjKLn&C2u;ao%e(MrgCiNmFRiZ{5t%O)i?$7rt$&%UEfjbarq)?r;Gk0FYy}liGjw2 z?=imK?rJbS%U;*%TQoWXPpz9kbVuQ@Xj*$WfWsu zTb!!X3&?gDUBmq&OOrz(f(aN=W(0CsX8t3?-OacK{is_~`lZ;39&|*amJk}P`SkdGMQvuF zeWck;6w_zo)zImfqZ9gv{G{rOhHd)6WE*q9(|z?@?5;R$keb`)lGJ@YFt%m+oYHA5 z#!2_`6;5kCq9z)Z;H2Rc3cBZJR5D!B2Rp8B>)CLp0Tk-)S8GcgvG%HF$9PB=mK5Xg z5U7d%C3MkV(pzW#`{=mO^~p#rpcr9@=mriFZ)M)8zJHPJVOpWt+kAV&#c6`j`2Fbl z71!uuazKC!5TrKDoKs8OB$d-8VKz1JZt& z`|Q*lOJoxwv59UX5ixhp3dp+=oO<6+IRb^GNSwLZF0`l z!7pz-!LAah2S*#f1f)>jN)1Y1r_ASv826A>MAa0K?&{cV$)s*FJrZRTdFdq z@e0d5FwPH2KlxAHC{lFVD?+5tPpMUnI6pP;#}Z77FYyFh#@pTTpoLuPB&Y2ZV^|0X z=R-?Mc7Pzrqtfamx+wU*QOv?Fj2`M?_zoiGDkw4kxmZ|Rn5#q4*3aq)oSZc zs3q=1-EPQ=hdJag$W_P^Sr}!NfV;U9^Wy`lkOxjo=q*9y6s#@XT%UauoHbj;^ zCzq%Rc7pQCJswe*az9F+8jF+6CZLH9zIR^7#*fygMtsB>KwceV3A1jA%qiGko$Y?K zf&kkiXpa}U4ug&22mggAwgbr-Qh$mE+>u$?RBOnIyu9rCCLu!B#~7YE!8|r15imLM zT9IQQb{wLRW|t`g&9Sko?f77BG@oCK*{7%T;%qgF#Cz&9@*sKh9RAwPh(zc#kZvN3 zfma?fA<*Y9FYEaGb7?~#TL5>YC*f-#SX?(~(G(R?T?c)iLn5QAVdSf5b#lrGdAQ~a zegV!m&1G5asLbUNZT--)f%c8-fIHr_ig3ra6^ObEiM0UwTz&9s3=(W%LrLQv`)$e)ISjvTw7EQrz3p0GYW8Nm-+g5*EHU4`vJWMC2)C(E1UEusuVbG|JY zwoNIY1c5Rl-Cs4sa{cdF%$CIk-x9zgdLwKt_tmYh zdL3ZhKNB6+X;tu8 zfwK5TT}#!2HP+oe>QkoVQ~a}%xrE%q>HnUp_VPL#_`fUTYrJbi8DCn=zkLGtsrU(_ z2^Ar(ib~U1KQ#MwGuapE*Ux6V8t1_rI;wX&(~Iy?Y|m~nD}z}-!w3Aeb+8trEcy%cKTPV_D_z`F?`%ImYvItrN&=>a9HPJbRzSP+w{wy*yBJ<|*SanyS%3aPp8=4G z^Brj`t2>+;5CT{=kY9Ul-B`%W&owEuT7irFGQU>J>TDb@YSP+Lmp+Ur2brYC5;Bqppt0wA4Q63QK9J*I} zfY9B!9~%VL+Pr<=;n+5tlqv{l^P0okji)uo+nK=DTY`oz=G1ZbSH+hZ4Ds4acrIfH zB|AGLbdj5b`{0`X`USO_E)64C@;_}!Sp$dTZKZJyOI*e}(!4?DI>fhq6|k^%##N1P z0)bikVCXBHR9}_G>+TMXzrAuTz{`{+H*X=hfnq zx7N_+puV=!i!b=r{0F}tvVQqK@YfcpF0Aszca3)M3D5q|(tPf*)lp$KBlov*#5Z{i zJS)~YX`wW-XbC-YmP3bTV2aHrAC|o|;rEZ)uyfH2d>J03?lOBt&ym2C|H+nw?PT0X zm~=pQ!w;Aps5h8+_G*9SKVEq65*of5G*VQzp2MCK|Cty8-+0|N9PCO+_~rQY2b7BY z?l-wPJt4B8;=*{dt?A8Yjo9EE1q8;;3vos)%~-7zm_u%No}F<(D5?!8NY}Ip`&jDd zJwUPR9H!FTKB8mtae=+o1g~2sf2oOf$G_>~0FGg{7<*3rCkunRHo)yKnb5COq@!h_ zMEY5wIigb(JkyYZ91o#J4<|Ku;iD$#d-AiJ!!VB)u3B^u=Dc-p&@uX!m|PiHmwhGg zVMKc1Z_st};q|h7JA^|YZq;UDGg!ba^Hoh2#X(cH-k-Fye-1&8W8`D1Yq5V`^s-Uc zS{?b&->d5^0mPqXrDWC34Nt3T3e8SF2BLuP48{>wN|l?(CnZ6kQ&D59G~#aIkC*7| zxlGHEW$*~w-`%R%hK(B)Z*>11w|*dD93S(V>Us?T7#304LhT(`p8@ew*MZt1%q9!U zpR%yA-w^mlO8N#w4r2``#iQK^Q0Mn6%y<{c!wLT|M~4W>!;siiuyziRt`~%6JfO$v zqsf+Btt(;sZo%0na2&qOqewiisd>@`qlA>^D%1zZ$sl(q{+!EHg=OAA0ae}8=!^aD*pOn6>@r19WuYVeMRb|4lFo7bee z@JS?b;-7x0S#iOOP%)vGDPLq*Jik!>D@xHaU}VH-Jqq)nq1fO8;(+h6ZII^?)x4K) zRTq;+PJ1$gu7OldgtX?c%)2`$0T}*O>&jb&WRN%y+Z{2@3UL^GgSx_9PpMuIu)AZm z*Y0$*&sWwynld+9}nFL&h^^>rtf z=;%KDnkxC#94nqBvS4EWAG|;@;$`VYRb9b|Or&1^fQcCQ4(Y8)Q_x#>dGwrBse*Rt z>M2@ZCS$8<=wH5n%#St>rU(gT4uU=3i~znw3J0N(h2`%G|8 zX+&<}c{@JS1SeNWj5Zfa$~0n_=-+ZMO1h{YkOi2!)U!7!<>yI%X4%&}MJpiHSYRa! zoDw?X?y4xMiWucOd>F*;<9lfJnW5tCknl_Sh%C9$*M|?o)Iw8A%u?4ggLuT0e!{Tr z@HqH>scE6b7rPks8K}e$Nd-_LJ-ig4&P|S51pCKe6G+>HXZetiJN#~_K646GWHTqi z-}&|MgU#zoVdd+H7i;WL_JryYels9jP97}(rSvuv|7=8(RFEmS+tk?!N#vKh;k9Uu zI826ykQA~=e;dW-x2?Bf9WEGg*iE*>0JKGc6fMw2Yl~gG)N-47c>NZ#BEyG!u7O7!h|_g%o8vxY+P`roY;^klhVf|=CcmA<8Q01+lC?r7OmG6! z-zR{w%DQVLQv5-Qd_ksO72Adg0c8=rP>B*pZfUCS^GmqaR!jHWe&d4%)XKbmxYli@ z480R+P|ruJuSD~fr>*htzpWX1CP8PhCfcHl%B}U5j?u5wk4U}0c(c8>;4R3(Q+r=DL;EtB#`p(WSW$@KkKSHqtc6E;@?P-F(hbY)e{?Bw4YWlL zQ03qEuBNBF|L9D3cKUatTLoQBQ z7!-q1gu`tp2v>Ds9y_w$7bbPQ)FrqbZZ#f5$t9m2(%Eix%36^r^CLpPVB=}Y%xplxieoU(gd|j3F2RY zJ3JitgMp_tX(`qE=Ja^0u*4RgXj->xspK+8^#)zebEoRj*G%=hj@)L!NZNV#?4c+d_FC97QX5*&E>_wlAE^LXPf3e6e9 zfD^U4^7CIm=^l=GM$fL3kR#l1<~y&*SBTPkb3RGdeLu+`pRhCKNjEe+Hy>q0?X#;# zWl{UjF61FUL~{n-b<$0sIm5620O^&py(>}gF_jUQ@g$55<(8u?7@vFc;mR+OoNm(r z(CmgULEzJr2)(nfu1;oPLh_c?&@y^)vfv#j(ub39JStm#gMc0lO~J@Q481&tFpKwq zeF>$U1hjyg5sM<~Y#}fTOoB=9Pm;dp0dbm?wJ^$K~Vb>2Lnp2IZD);>AXAEH`@ZUT`BUI|@ zEW^vDM8uX9QVR9zI_dJT^wNI`!Z}#hYn=U#nDCy;V*Kcnr_;d0O5VlPVHh5-*`0c&XotiV9xD)EryjqbQNv~SVqQ0gi zH-jdc)V3~&MQ@s!A(VcNbH1w`n)n92kNv6l*`U)KR>(ea2F0*pB{OLbIC=sP_lgCq z-JZGq^klv}Vy|yFxQ81atJsw~HD&R6)p*dw`)-=r=@!`+_M=@3zkywO2gX}u7tnq9 zu1`P}=m4qd8@|{Re-iX&$WRp6pCPXz_1^N#r=|i2gY9{GQ(bh=Df|A}sdZ5BKI1pu z^*a-28Q;*v=a?1yJtrs^(7r>R3sQ-9*PaBg>nQcYs5WDoLJPlhkDPvZ?e}@ssFv4YXV6*&|j|p zYd;gNapP;Jbw`kTD{-e-gpc(b6a5lq-`=|L$j*GgHKQM2*XVsIL&0LpqLHQ16jP)j# zti|jBW$|@1`IV^s*!QRWUam%}6j4zNpz8{FZB{!PE}K}QVIX27(P$tlI12tr?f8^$ z2BN&3I?LV^e5vN(M8($jA#`&g$vk#9`xR(fv)a=LZ85{upiwc3JpH&>ad)OIk07m2t~;5}{y2pL>xNAS77vJ$n8nlulO zf`+TJ#ajoZo0h5WEI$c70-y0iw$KD$#`c{RPy!N7^O6Qk5-!t-FqKs|n_b$o^jYG| z^g-##{&^pafeI-}gxK{RZbQziQUI{EKZk0^mTjbzi?TE!$LTYkd>xh+%6tv{pj%QK zByt80#?1nl8FNCN6fJ7>jlU@h1ZD#wXlk_HB&xu0?gS^o3JC&yH{Svp zw6WYUj2WYPB&sHVCeno2_8}K2_w@QAqrN?T`0X{hx8d^ah{F_$B)0P7 zHh4kaE}Ds3`QfiXWHJO6n6EPjO9_2t%qV{6|Fn-MYx1{)p_-q8gYJP?w18C%cW;fP zz0pwq`9LF2<7Zd8S*|8=r~(p%^L(`TK39R@G1Pwm$-q;-dH;)p43co0ry-b(dqN$N zBI#upxqQb_J#i|G-hiQNcRR}cRTjg<3w4lOTM!5FnEu6@Az7EJDcAuF;-^(+QX!dv z_B*zF+9z(3U->9KI;Icc?%7CV-%pGkZ~C?bR@ueZstBD45X*J=vwTr;NzQZRXHy(_ zELazWwR0 z%)HPeo&Evtri(mR!I>rrUIlnAN&;|f|3Bu#&*eCLuRi0V6daejX;Y!BNI2%z*p#F~;lwKKQ zKY&qA8&7&7@75Z3h5i3py7qXc_y3^SE#*`qY_#Ok=|*#@I5Bf6`sJJ3Qc4mt zlql2bwj&*~Va2A@Boz`d#EKRpmsTRiGIM9kbu^dn>*M_Xu!rqo@4fc=_>hL<=GbLv;*m`{?57H{(^@)1Nd0{AcRrm z!#PW`ZhT?unsws=z3jhGp}g3Y6ye~FEAeH87Rn^IF6e_cvyg=nIIDWXJKYYpfetX# z-2G?{4zmWn0MHcr2pjXvGp$(6w+-x_{<_(2v@dYPu!12ma?ag~% zz~~(aul>V(?h`MDlq1&Gkr!%pp3|$oV(W(?%qKHXV04U_ZoW?ogDOIT{i75(3IFVB zi+FM*$8FVTzV|R-A}K6=B@`=f#fCLjX$+31Lbp}9gKJ}M7WhjPg!)`KgkX=bo% zOr#NNlY;2GPU?&bYLs+-T^~1Z7p)LIyFK`t_A}~urtYp}(-JdvsDD(!{W#xDy|a{~ zee3S?Wf25auQ-Z>egneB;COx|`#o8WswqB9O11GFe{#xSr@*1KSIp+1Msp;oga!{I z>76hD1cI++rG;~OEHb9WOE9-S;zRP8o)qSCFX0Bb#EmAk2HlUOY5gne7Y+Yfs=jMD;yPz9_tey09Qn5M=I>^xKlyk4 z&{gOERYo=mczb?vT}F6554myJ#oj37;mQ1xr@V}pvQ(ntJ=w6{7g`KTI;nTLnP%$7 zSS*Z;I)oOW6O2@E!UX3GiT|z;x(pcpEHY%VRCn&r7HEv>WR*iMranPGEn z?;*!CPg9%0^!8+`yNA|eVo79IuUKIUx)>tGARu`S!LJmqk&slh&?uLRKzV|DT@I!t zC|_gz?KryFp&$^hZ3f#k_`M&+T7HMan!I8gQkH$;9SF;1+*+d02bzdZ35F_JFKo$HVo z(K2(>`vf-1S%+RQ&isd=IpHa^aX}rKA_Ho zjbmbFDN1CFzYte9;NVb%rojpXk9P4y3Ch%1`A(c+Ur@_J%+{4C4QNs21d*QrmN-Le z4Z%P0VqzKUmApSgGh@q6=Wo~Gw_{_FcEWc1gB;LZ5bKtpRv4S_C^5In{W}a}6&#=7 zSt{ynxODkBQ4t2cp6Q(LSNqw42##R3rRb}aYP=*3*X`U?2zzKa0H3<9_TM;&yZ^09 zr)+CLd;+ekJEb5wjV?}EO98-+T6FF4dlGP_9NckE(?M9@G=j)kAa8{sI%>S+S$!tS z;JA?1y{C`6m?KB%c+nQ%nNd#=FcFpU#hO=z;5B6X6chywp0(2k_hgl_t_*>A&Q<%h zH<5oBRpvr4^`f<-T&5PeV73s1CBa8L5NbCvcI_{Q{Y397n z`Xc6X;UeI-pZ)E%QT06XJ?<^$yvC^}urVhn>)RWnm8iYNMXcdKf}-vJUFUFreR5t> zoaqr19OT)c6&xHC6B?r%esb*qaS!+-xtAc{criIAU$d43*Bz;>&l&OkJSI9NY}1<3 zaH$N26L2ZVsQFyjRfVG^AdHihHXE4C!HcfVRM1dX0e>PvUoS=elB>=PoeF{D5paTJ zFy9`a6-+SiKrEz6>zzQ6rP|G^G%0b$;&e#pR-y922tk$6WJs9hm8TlO!u-{M$Fe6A zTrIAtFSPR2s;jG=7REx*&o>*>4D!1Y9V5-$wD{+!aeg4FmW6*zvQt&kicf(10R1c) ztM%`u#5&A@sqT{6j#Cax&~YK0qu*>sSP&jAwYy*xhdL@%Mqcnf~7q`*xh>E|;Yr z^pqw;nk)jAjM?w85E{Fn3iVblQ}eHdQ)Ltl3nac7`AIno@*JP^U^kwAgJpMH(xn?I z`Mn1oaXqrH-Pwt)KiEgg^l~Ob$}9lKgmN2dZU0*9NT8z6JGwiO;66b4Ka1VYp2})H z(cd3NqF5|jf4gncuG&b!*0#i>5oXa^_y^R_{sL`c>F9Lzoyg8m^)Q2HN8wa3v`!yGPs*~C}b+~F0dtWwC=5!xAkyloMz zdhtQUlm>Fe_4?WCRCl}@P=2;jDP1yBgROwy?QiVUoP_eKAKCCksmjZstfoNRn+NEC z%;Uo^(ny=lKZS$iN%k@1g%cAT7-9vnaBGladm6tize-7(m5#uNsN3{gL-FeO0QLuK z8c-C>EP2S<<$n>azd8Oi7!IvRKQ%*9R3q~BR!c%gfY09IV^UAzNS;-d45CxbV)f%S zKjFNd%tQNL1+lq1_b8_Cj|(V)rh%IX*?UKAbLa%C-Pxc1^MftTkB@|IE=P=PJ9%@5 zZ@yKG?;=jQAqEMLGYX0?S|7zv%v(4;dJc@|dPbmOa6szD%NlZ<$iGYvmV1N|K5w7? zAed+)B3>k`TL^KR=7+3jb2X%cqnosr^mRfWeJ;PScbOd484rwUgNsYSmR5ebNReUb z2LqZ7K8Vt=k>%#lpTC@O(YpSrTvXPXXT3icyy;ONx4?fg@AUa-sGTNCMd|zK z)z^K80zMDmWVa4+(?EJlw8mQNKL6fZpR^D{+((B6iK=)!iUpGQ!TCN?5O&vVjQuL_ zi=Mvoe{$sdE;aR#k88)G8S=cby>hDM1VtS_lu;Mi5BWP| zZZbQ+IL(-Vvb!z<#1?$AmEfnv>f`HQ;n3u6PcgW{^;qKSc#v!(=sK}lx7Z?7Wb!oJ6K1IEg z@E;PKzJ878muIzqZJTTA_`cX%}0bVH?q_f1azthVc~oq?D-ZQS_Yb^c!+lDxPS zXTJN=d8+=wyE$+K9qd|+RbSbZ<;PZmsiWCScflJ&M^Z)6Q0iNAj!@Dp?<1=kD`#jJ z$SMNUgJbua#Gcon4jaB3!;d)BnS1{>$ZJ(tNU73gVi zW^~>%sajv;v@^8+`&*sjn(&{PPbX=^;pE*F?2SaPf6@pjA~!nQqGn7dD=ig9p?M|1 ztKjK7i(-E?RXAxy`m)F8|18sfQjA?aBQBjgoKPHy>yE|lBOL#}!a**U%r$*mTV2Ih zbfMFyr$Ra?Lg=u;q`%qRbFWebkFUt^xw3gorfncI^pz&h7sRc*MIlxX?d!&B;^@;c ziokHK41m^~%}T{OOXu~t?A&n&-b z+Jf>s@tJ5$N=fCz-no7mbu4CG_nByXV40Z7NO|9$& z1s@pP7Zo&nXKm~v_}fTa#zXN{~;9To6@P~9l+DGpj8jxy9 z-RNUdH3?0cA?>0MI7p+UE%{UMe}yzrLTVu$kPgr%wP2WG9*K^0L|T#;0%M1;q?kDZ zX>L6$i6l%q4w+y&ZC6-P7Z~w0`Af@mlH{~gp>bN?`(o+B^D>Aj>+r|ydj96G_4el-K=!N+SA??13yBW5xk z=8`Is9V(57(r(0EC2c1hgs5t1{jA@V=Qx^p{nJ9@$yY2)nIiSrW#M#Tdp|^#55?D+ zKo1Ge;rlDVck64z7$#GqGo7A(vRfo~nfOaIWH~8B!?8AOL!FN3tIZ;Y)Ma5EknI({ zvz$ctR!d%juk-UVM4ROzY4-w)$I(hs-lyzm6Q}c@wS9Y)CkGD=NH2;rJ@p?R8i*4+ z`xaFNVp4_ejgUKsnfiR=+j)4 zCaoQZxT`1Ks2|vv*yiUt69!Mse$UXYeOK-!9mkvh;&GVdJg|?yQw8B;zR(%}nwJgB z57o3dK5)IfH^FW}NkjZXbDRVjD-;!*E!>xvKfNJ)M`n)ju9@`e!8MY|cfbFBDMy(3 z>b#KcWgzW!pt1BpK_r)LlAW@`)NfLWhKD5daJPG7!ceP${2-5}co8KMaiQV0{2mXD z@4>>*xC06HU*~5u>DPyw9rDTMr#CKYR?7r}5ok|=!`=3GOIbCi?wZlAnv9+UV;2_5 zZ=Ny#MJX5(|A~!sqO!AQNI*}eYbWmO04=b~?K0cU$mK}b|x3JEZM-x+~`HIA7V%)#~;Lv0vFwVDARg3JOT>_NaZ1zQ&?-&);luoEh|1e~CVg3S6x}l#$*FFNL>%DBl); zBr-iQafZfs1};G3yKVj_RkmVU^bRr=z5U1{oGr@DpS$&7yHgf@$}Nem=}_(01fM^2!XE`*%r39>iz&FXuxfo?n)ou*vvTkmox2Cx5R>MyxiM>;2O2 zTVjb^2UT0<`&EYA181Nd8D|St`!CHDE44%f|ApLuhH|n;oOKv1K=j>Uy_lyKmPZ4P zqm)i46Tmnz#)#@6rK;bQ_g1+upH|H$z7%+<`aP~GqsP18z4C5pWzv7&5X}k0RFphH z5eet}y68X5&Jj*4=M9VmTS6ZTO6xWP}>E>gRfW8&W1{v?(bhPt{}fxoJUvq|KT1HV4B!=12p0L!Q+V zDSL#A!YQrkYOgmf%C)_BZ*rJj~4Z)o9c5C6eCeUlpW%$G9pVXc~InUVZF7p#Hf4G@LP8Qkd!>iRPEd zeh}(cp;4`i#njNly_NF}U5de%Yd6n|)WEcwHdslI?psR+7Wtn~?x5coKdRHZk2%*; z{q4C}dX15)CFHE4GdfDVShX%a{ ziITnE-pcZN8mpysS>4U`Co^P!Cxo@r*T&QlnQc3*Up-L*z#2ERAj;*&)t>u-Fn^*137e|_LQ zW3nyEk0He`{Z(-E>>d6j98mp7SGM6}One+JvCp5&+2JKTyzgd1uW8G1hy>+C-jO@_ z+`)n@IX$S&e=T|W+EFVu`J_z!439?Kui*x|74DXWtw@!YwbOe|U0Y#p?Nlp%k(LDZ zrnD_W;)#nO=A+GjJUUmt3=Fq_S)04lgiw)vd3m&b`K5VNS7Bv+*!81U7Qffp;$_7q znz4Zul=WR(TQaAXbtkJWyM=zYzPXx9JZ|{-hh<{{>jCamvnj!=Q!wXVmde;{aUb9QW$ZmodA`*0+k#Q|6lRV&4ugg%gD2LaS@EX2 z1=ZPI>e{P3YYjMcZJt5C-H3-DelO?02PB7??61)>=lj_u4Rju5<8-wb1o)kz;myJ4ok4HaMUSs~yY7W=)=jei;~)TI_}VqUbs2?V7c&c@Z*&%)12$DE*8In`3uPHOkRv!y}P!#9KTqSt1(8j9;GdQ zTx>F-n-HCiL(S`#Bbw)n{H9_C{&sv}|3K4~FV*?BfFcK~s%PH#rQK?=N%!HOF0!tDLiMke8ef7n z=67P#UQ+G^&&*1fBwz^`8EV&duf#v-E)oNBPkFkF?$9>Mt1C>zciSH1kn?ky$e zz|;Emeaz*0Rk4=qtYWz#*BV=|aPy0azb`VLIaC5Ya7MGn#FFzbNAcNReruMOUha;4 zO{4f#Z+I9h&W=fxSnxu>7ob5iOd@9qO8b^K#Zn&ZoA&TNsqo zQI>5UB>`yT@i}3V_`Hu+FxF91BYr=9p%HdP#!8j+y!v=(_MldSgY_cX^!NN+R)D7P zM*sXZi$=!MRJ7!H&;=V@L+PY&d_*eE5l+#mx$gzRJH5Y_bkB%m^jx!zF~;f=u1HdG zG(UMxt@Q!|dA@ms&C~|>m#k7jeQ974qo0eI_?r?SLbe2JT!+|#DeG>5pb>sv$*%Fe zHU}Lvu_U;t~CRovU|R8YlKQm;%Rccw)!oEhqA0Z5~q?5@yk2 z8w(F(F5^a*$EM9LIuxG&Gs-p#h@78+s-?mvZ(nA`GdkGWlgd3BFYF6#R?M!+^o*F|17A$lnlM=`NBxQ=E0NlI!`s0Wza(p0pEaMn~|EKD-`>t=hnDqW(wnrSh_hTR&-7@rq7e^Xpp(Fp==Uv|8gv4QTgoLJB? zs7_Gje%Ta1=wA15`-)33pgoq)J?}7_pudL8-QA$eop_kaQr9}^7vyBEv;B0tt_$HE zDUTM}x%csP(iv#nWVk)WR&~=7gWfy3qNmvSy^(^D>e01Yw@dl4YiFsQcvPjuiVn&( zDM+V+b)~y4@UzhJkF;(*69=!i0y3Z5(Q7k3!_778AH&jbtAFHq|Jiy$PTHwPwj+7% zY~t=sGe=E{`*xaBr4p871y>2dCQhqfZbqe*%+QuM9VfYsX=PLzqdwbfwAWGAuBH^F z%<8!tTr>ODEuP{KQ~MCP(#nw4%RCxqYGs-65YE}7zpvG%o_$eEy`Yg?$cs@bcw;H* z-Y$7CQn0jEzq9+u7Ryk`E%X?^*xiiW%y1Ma9t-K+x|r&d%II+p zCM(>Z(eJ*?a4B>@UOU)Y)=5XF@C)~4dncqi-f>4alFT&W5$-a__Hr}-Q9*8-( z2()ER)&azz7TYq`fYE}hH8P8}xv8w{1b)Ojxp-- z;A$jYvH>>!XtcnXU`((@iI$tjSJrW|?Uto`Rncd>yqK=hjm@c56A9W*aM5au3Ra1%G85b+o$V zkWlDr-|esW3C8)hbQB*IKlU`b%z0HK`J&@gSXqphZBQE?Mx=kTUsmA2J)>JdP>KD$ z^YzhS(+6+8kwZtd)YCestFK+<;b~9G4JZTMYKr1y&K<=3o_!X}_W)6EZU~&7Q0FAI zE>OLQECaDi9{ayh9FlJ_H_v{c<#|Ts)Z4f@<8`u)*mkFK>b&!)b?W^wt@Ss>M`4XY zW9&G7Iz?%!($;mx{sxKjm^gME%}R2eZDC_Fh4jSKnZ-IG6lIhYJ{0GrPe5?n8^NUU zm&d$3vh|sda8m-Sb&P|F_nq?YOuq1t*{7kAu&3OUVtdMlt8Tu~5Q^W+_;q1}m7`+@ z!RTakNxI=PZi;iFj&V24MB;|`JGS}2@A>mTfmaV90sHzG9`Y9 z=kw3CBtYxd7~}h|;-}}bJ@xHxd|6w*SiG0Z3j(N=Hv*#XSSNX}2Op)8-;3&=DSq>j zK6jrTxmMH^ov+Leb*8n}aBPtXd%mwGqNiee^b}sRQK;NpBZ6=rN78#x`72b82)n@jvK=3fQWy;x}7q zwmo)S?rDE@Q=%hfr{uXbHm?L)b3H1t+=2{em>Gpk*p|qKt@y_X{tsPOaZ3n$80fmw z^Y>rWL1bem({RSf|7i>m(G+I64ypxIjQ33Yl+tJ&H~E>9&>)-nzd<4y6hH)igyn>( zYf94g#V8}R)HyD;-~ifHbq-!X&70r)uYR0Ej5rykOP#~81qTC;Ksy8HM)%b565!;Y zXa_)!c+tQ?qCqmB$%7nSwt_6=Unb(d<abX7s|8_lOE$;??n&tR>CA@x+DPud3_vg04O?-$%`wf0LCS+ZhX}UJQBoQFAVxrB0cF zI~D4$&m)#0@~waA#qw`%M=4>+0%gEz3iV|>sn3!Hn$_4%65*si(XlcN!{9b}qnWcd zNk;232)&~uD1IftgI9hhKCIE~%7t3%%)lGJjxWjlYq>2ya19!F^Rap8_dZ=*fZ(db zZwHeZsWHypfVIpuW@)YJd%)guIb48BCFm#Ma>uV9ZS#WAKz8NwszYULJOk?xQ2p1` zVo0eysRFkIIBxlOBC&A7aOjDsWUF|Ae!{;k(;Gt=jx@*aLjxa4Y*!;{xeE9b9&2^o zyZV|#kldCYkCrO91+r^s;CIvXcw?yoCh|)tPw>@r1?Kb83H%ATsIHIx<{xunShw|( zCBpEZ`vTPXCT#W-MDRL{yV-qze+K}fM6^LM0R#^w_bWs&a*w^C{?y&T)Kk1r( zo6ZcJqNL{A3-iCgqx5Z6%I9`Mc(w`05nM~4D*sa_Rtc*m4a2o`-P_$ElxtCldT29i zN>Pk>BxQi~Oe4R${l{37&01&IX;m7%g|QFzT$DcTvCt}#gZH_n<$0+JZ=^o$1z~H) zn3>K?u(9hGyoCIpFqKyFzhKtyS{AZ)oG=GrY6gAP8WQhlteAy*+&7I3tQwRg`z7g->!-$h*VC$n z#Mc~+MX>nQ{!fC|cm;e8{)W1r!`H2|Q@o+5tS_6_E*d)3uL+7@b~3(%Wz*HiHO%Y# z`qCA?US~{KsY6$s1;NAM=^F}})CQEEbzOBkZc@nKjcK=(|4h&I=aso1pTw9JTw=vv zuM>v1bzU;SEuWT&eTumE^|QY5O@doIh*^BayA`Co99%)p_w(!}VJclFvFi5N@lR^& z$PEYMzAUDBUM^r*-Z3>RGt{mBch6ap51Zev@6|S+*5Ee(zF%k+r4t&}et-1S2?1$l zZ(NJTwCm&MgwpkxoGNzj=C^~B6_>k$yZ(6&Dd1!r!^(Q`&YKw1m`hmv+{R+V1=M+y zgPQx9%$_qouLnS}!xq$1-0`1O&#v0&7-hGsCF|oxb8o70Sb+2zybq56iOvO+_~uV> zb?==dQ_J&X!478mmu9YA%-td%Mnx@meuzH&?otEeZi|y&-*g%-X$apfVEtYvKWw+W z;FCW5^J0UOMd+s(CZNl^r*GgwUdp5QKj@ zaZ!`|A@SG~XgD7T=vBl%MsUA~tu7{k+8zIeBWU$K^`y`r7UpNA;8dT)OMl2a;U!YN zGx5e3*PMJ*#7onpuXO#NbDzTF0zvw(a{hB=!aMLxxM%7hy@xHhHP#ghw^k~Ph-PKg z04Cq>kwn={9IM;kwbiL++MO`{NpZ zu?X;crW;v*tk-g+iNZGXz9FhS3_XSZMb)jIE#+aMN|1H>sZyF`LH2m&d zQ(CQmzD=3z!X_bu`(V&DDbM<{>BCzYjjw4<)Fi)SyW2#gG8b=W8FiDPj0@rDd9_Qrey-nylqBQ*QtfkJ&PEI{-C-5HdA08w;SbT=yrHTgS`=R*1DQu>q8UNo}xRMq>XR&`6HpcBPY#C9wcq?})uGHZ2 zy=2Z#>XR$j1m$M!2jZdQFeWrkq1gnUKU05Ui_&{vj$i95PcMaZV?cl7I*tDx?QSs7 zuTK0&cT2lNUv%85hc-yJQttiSk??iN5A0~tJ2vKbVY86IsgUaw4^im+B=^}r&fdNW zlA1308C95iwAlAAz%zf`_ErAL(=jLW_(5V_KnN?NYyMxEt`87v(Gb?VF8M7oU8a!L z`=G#SI+9!m+4i-I;bHEak(sZDY`3t~WgsSxl`Z^pFHT$jb6#@W|^p||q!SfH-jl2CC0=VrXS zV2321KYq5|CurVof7>Ye093hOQ~U5Z-pBCO_cUL?f9v$=T%abg9aG!Oh4h6}jrK4U z&+2QYon2K>&;QZVc`AeROPqWZV*i~=x@YFYd_C)3E3qqsHM>j?r63;-BjGl)01kZ7NeVUZvXTKa~ zDe)^@-7#fPD~Nl5*i*}->HaIvYluZOo8Y>?ed6-#K8wka{jtI8^`4b&(V|@QT`aXu zNb?}^ZVl5~<8#gB3|G;}<6dTrT=8{lXkPkp_5OnR^1>;W`-7B)fA5*NGn>sCySwSA z&(oKdst?RaGKcP#Osp#$a0uRO1dCPQWnfUnubhx#;!D*wm}&6aML@vjRz}H5+* z%r&EK=sBGs2Hns?p+EiI2j$$(k0>#&eZI*pc?!;vlp=?c$~qwnsvE!lZ6x(L!1K_N z=uCg!>(HWMVCDzI^Gwe}E#ke(lj3=@1Xowd5_A}nQE7NKq;8c9Q4hMwA)mgwy!jDv zN8T`LLHB#ie4fX>v0KccZcY5>NlEOU{&q383U^?Cica_;%cW{_#Z43*#2A8 z*7=*_#B`OB86P?4qG+%fm>X?GNtpxPV=>45>rN)#+!9IMP=%) zoxZ#*|Kt?T)wg(GAalD&nPPc1F0RKT)2E$>;N9{X_5DlY*$PN}LxrVsa}g(lUdpBb zTd4u`z)rgeW!hkXk=a$(VvO@zBzK+Kd|qc`$K z&|+(GlS|PntrKCG<#Fq`a;^CF=zEI0fYFw|wOH5NV~~s%5&q-8?V+R1>bnzcaPPop zpFYJ;-Zr+HIvzrGCUfdGPdBfETdesMuziqc2o5Q{Nx^lb;lMWRTQMSYMP0dSN<96V zP@6c$bU2>7*O2A#bW=ddnOGPAwA9D{(n!23FJcVeOV(meZMVKy8*hIoeNI!5sK?3X zpNP8wgSUqfQ{KBjTyH0m$!QO&^zcYD*KVkb8LVM?$8E0-WScGkG4~Ib2J9w;gS!MoN^FU=r4X)TNBnuuJ|qbOST5!to!%pe2ZNZWURz z;%m#Bcd6}FCTC-v5K#MJ9DC55-;ZA8^=_rKsTOsp6I7_=AE>xsTM z{m+_#cCf?+Lw^|?u&`V6-( z!Q&9bXNmTupTM5?JuTg8krv9*gkk8m^F26(t_g2yx zaNB=(>nPe@YXX?waL5PAvt?xZggt6kxScIIKfRed)7@5KsirruuAb7|&Hg|=$oHky zlOI~Q``fNsswKa*XDHAgyP^Km*T5<~NUN>0?VV+mQV}wCIc7fgUCexOu^&40q{vDq zgy+@IBCX!`HjAaXyPo1x%bT38X%M=E6eTMb>$h_+aG*ntf!8p_HizwpcEC%1#b2Hl zi7Xav@6{fZsKmalc;S%-S;#CSHYglu)fulm1qPCf=52&>m5kg(;8uJr7KhihzFlS| zJ+l!hygVpD#=h-)gXdE$(eBd9n$3)|A84mJHYm=!gO8o8NGi7Ynjw_vWa&+>^Klbfb`+U=IYhsMKk zde%`UWyo_dF76ymownq+Qt+HQlZ~l6q?pR9Hi)a;JZ0 ziry$s+sxB~y5{Kh7>I2ib?C{4v4|f9svRHgea^!3X~F0C%Gx%6MN#0}|B}X4B%}`d zK5LG}UFaJWEh<;}q9?iR@e9%|5b&8lrsknCE=~eo5+1%i5zn(S4~^$$5w92L345UW zWQzMc!W*l$Jk?A@L_8?5W59F9Sz}0I%DSwI)t(j@7QqZWH&vflF7iYhVOg9a#WBJG z4KiQ0%N(Uou(1e+N8IsZ-NOpHtdEXP#Z6{}xm!i_nS!}$v|=`x<-^o}9{Qh`PH8O^ z3_{z`4~r2{C#OKcmxnnO;P~~@XXf#ksu76+GQr+_=*NhtQF>_`WQWDfnKG`wBPmEY zex%gQCjNI;(4`Uot_a0e5u&ptKEb^F!vrc(xVJ_OZUZaKQ|oH8!H*`H}LH|1&ao!@NuF9XHT zt$}&((o~mZwO~dYy&f@YHCCQ{L5m^oDf5|p;=J~zw2duacZ{zWtRX=ST4;lBDi!4_ zX>F|w!s4R!>?52@>;y)8Uk`Gpe-;aVmo&`LQmAG!++1KSS1H=|I*Es=xLYO(Gf?WA z0MkfOJBM#ROX$4SG8!h;SLS05J}(fTI#mp9er2mlzq@6G79L>=q0-G|k`4^XKQ@?p zxsME=2;5u>o8Z@@6IV83^>2_bmxq3dfA%A2Whz?KHUd#*r-7#rArhS{xy(jWY;72?YqjRrty(wLCNFX)rgs2I!W}3)q+2UqEl=m=u7RE zMrSvMn_rP#n-}J2q`b{0AXF}P6gR7XkHr;$+8?lW7 zT6Q4AP-ugEjhy+lhrBis$a`nbXoS4b(6LJB?QPR%8S7Hpz&LM_QoaBsIb>LbF?z)arB*eNinWA#LYy2uACTj59r zWLGutqY^C4wcK9z_@yj_s~gV;;j)0hV|uXmviOMHwSfKI*T-V^ z-1Tqj`E|SyN^-iyKFqzM1+5z*GACr`xNy6o{c$azG*M~uC{kY*qE4-Ibh7EJ5`4Jz z(KB92SUIA;Rbk7f8kcM3oeql=!>6{bv56XXEs!;)JBIQ(hov{qt8OGpW+|p6_~WAG378?{| zhuAnsW(+ba;dg5*`nFVkMCL|ar%Y7jjxHnT+$CGl!@e)x=3=mHkMWWp2uQf?!i$6X z#a`PF)c2*CT4ibYYu3O$_7M;dgFbOR=~CG0d}_6_>7bfh(eCv-A!0i5x1&09InQN0 zkb)lPo~U6t&!urLR)QYq#NZ{ScU|^acTHiZ_wkcqJT|rqP8B@-9u{kEubxX$b?U#J z?pi~}sFd2LtzzeuQ?T`sj9UTK{mYOV%MKvDE$$-*;wKh>9KsO~SHW!B-$XKk&;Kg6M6@UcIeCb#emm zM*VV6G__n+YfRFk#)h0v*PP(t71j?bAmL;E|)Wv2Z6 zI(5XZSrN8)IDujlXmo3f8z*V|g3inVXD?~)iTcGV*!hmXE-?{>(&@7<{0Fh0#i6G! zr)%&Ij1zZ8Z>Udw{+!GNWvfx8osd+owYXgx|5LZ&p#BziY1K=F6;rh*D(?12a?mGY zPw3&vWaUY3Q<=f%SGDqN$uS^9aUdNvPQLfxd@9G;&w>$fVJCSxeK@H1V!w{yE>s| zROtWi9)UP?r8Q5RFsaC5B+L1j179z{U4_{4bcw8Gdbfz!k_#V&^xDvYe&p!Ww&{BI z<4}qiDxP&Zn@@_$55}I-K7wGXjzG?+#3?Jm#nI|U$Gb+gH`m=iQ{&DlDa%O%VM_?% zZ1j(u@=@LK2U%U{Bnsgm7oG_T52u5+`csbjP;B1fc}WMaS2V#r4NisNy=!5>o(d>M zqm?>jCFVVUCI0b_bVSB&O|H6e#>=KefgvHkofYX1pL*}q3+^jrJ1MEkNL=9vF9ECg zbJqC4Hp1Rtq|10rWj^sVxQ3n0KEzDL-)zSRyLL-?e{#c>Gg+F`7lMBy|2l-q7egm2 zQ3bL1Z#%RXg)o)v{kRbJdLgvO4Polh=PPTL$O2NGDj@ioL(s{l2te>p z>6X-}_IhfpAY8~N+mn#P!uoZESYeDDopKUYdbcOoN#i12SEN5%vy6lsB%tCjXJb!{ zMiCNTK`Rt)yKCMZ0a9J`?$~Ue2YvA!U6V1&vi3X5jkkt3CY=u6qc=HM(_A7sX{1v0 zA$TD}NCSGn*EbEAhp-RRp#rW5cNuzXcBI()4nJwNU#M zdJn=zq?J@eAwB|Eo^k8p;-t3|C&khV$hNNZ4bA8pVytyt#z8`T3W9!z4+pwR3atG z41$xcnAo~Stf3B_f3P8oV(SYr2Nj}(Bn9XR4(AR??({iY_WF^wf9*L7;NJ;3GQP0)q$ZXkG;9w64Pq8vbCTmvyZPi}|If6s) zSF^DjOvNHoUA*kXS?}Gn#IH|@Me2tt#qH65n4q?rMG8_*Pm8B*fo8p zAtHG^_SZsWraf{=I>I(VgAvS4s?cI1LaAT#q*sc((nmY+U4r~-p}6g`s9Fm$n1T7% zs5IqL%`TBd{JPxh5XIIz#PXd4i@WPDp1P#7)yhbc5_%V*U1-}fdZD%}3oo5j^ra=Q zB`RZ~8Tvd!jUt`uyL%!2(D9^W&q-HjZcVAVs`*yp#?zyjgWC%a)#2XeETU4W)QNb? zZqZ6-6>4co5>Oj;nt+#pV_=)opRvPgGl`#uQ{DM?I&~Z2F)i^O+Pjw(;Vy=j(fD9$qeUAa=r~<%`(8nph*H4BI_n+Wuo=gL`|e&Le(xK{kgZFbh> zz48WD;zO4>k-(|PAQKQ?qHn>x8b0V`cX&+D5$t?iRD;Iw9_4}>i4vARMW4P`C^*EP zp)&DL%#LMyMQPyEDYA=5Q#7RA*2i4?=j@M>=2e`V;4LpjJ%+O;Fk%`cD;ibw75d@U zLWHlj%flxDoUSQ}7ZY|)hRiM^WXWBv8A8fwOsHl$*=I5iZx6Yz@)+C7tN(n)65~)1 zC^8p?Uk@js?82((33~rlA!#q}@ zf1tgTOg{Z}At4W)@Fvx+34J!=cz=Z9c{XD1GxL~d?SV&QQFm8Vexa0WvE>u`%244Y z3#L8nzto#;CHyG{ypY4{x$V{y!oNT{sVb#PU+*yYx0a6g7gd(Qri1lxHk92`R?K`a zii^|3-r+&F1WCU&|4=RPuCif{W(^&Nlxy}TMzjc=X#Dnz_(8Reo-iZ+$`n^i zzYyG;W8^>epOmN=-&XP=@RHylm{I2JT%G22RzAf_kjTXir9M+4uiYs&W#@l1$3%7n zs!l|4Zmam9$P{f)a2>2q9}fw48Xoz&#<1C9C6@K+J%xf@V?;v(lgIs`0p^dlhE!>_ z3;-9uC3WJSRi#iH;3+5i0~3b1og-JTaVefsT?69ot>O=x<}yB*PI2bKRnD@FH7Rd~ zKS$Z!t>P@y$B;m(eGq<32=_q%k@EkTC&5n z|LmraN)w(7*z($zP1aTfAY^K&F~Xb9rEK%qik&eFp-t$Y-IEs;+z1&P$qtl#ty@v; zM)1MOR7YjTg6FnPuq*0k!1_~ra0O&v)0q!Kiyc(ev69PUt!TKiuK53sbWFIS^VK>q z4?ng$PMvH147bH+;p1~sj{AYd01?hQ0_uqR`3H75)_FoulZ_PyszVNC7ZLsOD_lz} z@mG{1!)3*8@i5zVp;1ptrDG=rTgu^G=(5Pj_~h|~^8K|meFm97TWUdSIO$Fw0kxEY z_<3&Ublp1X8{L9b^tQC0%0!FeO354C5=Ly~@;2 z_kr?>vEFz%nVR|$P}%8~xfyOd)>{TApin=vVTZGTp}Ap_!HbEL-adG+E4q+6Q5f~FvecEjKG#!2 zoXrygJWbcaws4&X>(LQj;xRSSt!lN`AyUeWw!8}975D^Y&a2Dwzfe5IRb1iYdWQr~ zkFuR4G8t7%z(oTPWe0pTIaU>A-W8GF{34_VbRLZ*gsw&ZLfQ9Y8C=JJAtTRMsN`B6 z0|xYU$U=K0`V%4w+vhx*@QV=5hq8~tGAR5@J)SCRjCE!ZpplO4v1NdJ5E#0LU33Hk zxc0~N=0KI>k-$;zhQJ$M7{dUWS*T;#>#TT9{aR6UW5l^}q`~U^85GaP5&4?rc|7?6 zBd?b`@gI6ENm45De1I##*Pv{t0np$67cJZtIsFUO9-B|5_)`nh;|rTCt3>d$Ar zVDp5<)o76qplS5*F)gAjB{d#4njo+l{oTd>BQ}C-Tw@NNi$wh_f}NWIG?!*ZWZ?zV zyCAd(n<0PLs3N>>YH&AYIM)-sUm|Z|y$bCh{?RS;FB-YyUj*@bw_ZvwRCz{5uP4#> z-AS6AC5H2D$hBfnvG!k{x+`h1x~^<$r*86Hv8zoMGm!Y(*>)r-p`x~sma1HFWT-JG z$1tuX;#wLQ-#+Xi+!i|Hy_-T^F0S^6b2@vs6htLFuL|?lJ@sW1pK(>A4`p2F$Hr>W zq}FLb6LsysCDxQzchaa2*z3*`z!N98%WVH}<5@yjkr|zNiDGzjV*x1pE(FS5fpAq? zC9=>HAYEGO)0sS-)N-wn5Xp``1kROHM;4Qnn8MVV_Rhg>&9(R0$Q|mrDau{WLKn^o zSv@R7S%YpUmuzVTWm$mJoysTvaFsC(cao(yf#m9k_~!UG4o19KQuaZFuqnHiJIRs< z`3(qn7Ci#y$}NCE8O>amABmz$L?vps@)xqo{nNj32ZqVs#%BKbsJq!eLlgvcrALhmITj)#B}v?9sSVLom$Eau))n9weQ$*n?p z!gWjiR`5FzyosoW_cv0nDpT$%O}j~W$p+LJz=?Z5FS8R&)EIVWUFf+4-1>YyG+o|v z8N2o}kKg&U1oYz1R5lr$cpAOgUa*>4Qai?>{!?^ySE<0Q{JX4j4}|(T9aHgvOezi> zK8QIIpYc~)BBNKQ&g>zxYMIuK>bB>?T-hcK-X0l5{%z7CC{x&km`(VDV$1PDnCLzt z(~X>X1FycE_$(|WrIOt9(b@BJioYBiF>w~A{-j;;c4uSide~DJx;<e^un5&YfqjRm=(M~ON1utDUlSU63X4`~8$jE;dVug= zlFO+`U9uweYcE=nEII|%43Ad4JcTpYJBJpQSUo+APD>#kYXIlPQftu_jaXSt1foxG zY)Xm_`6>m;qc4x4z_}dIpII;`mrpBwihgyL43Kokm#Bp+zbv94Kk5h^ zIrWo$GEC|p%qkA%cQaLshS0Y_$spvF-wO+mK)vS*ZNwlt|2wFTe;Y7>9gUs<*v9Fg z&o>LizLR(|%-Hs^&KqD~Fi_}YNXqLD6xgpwp2_&J*P_`NFbLo&fR-Lfx@yr~8d=G$ zWtu~;l8LxhOV&%v^0V0hJo@N7zv#@kn6n{pvB-*yeSh=BR{Y2%5I8rQaD7yKmPn{tbWX{);D0v^vA(^0nfTQPy~J)`j=F~e2nVPZy$=AA#CD<}H^ zB#kI|;gJd8sH&xFT*0ih0Ij?8yiPv9(8L)~gf)osrIHnv^m zYmy>`sRwiSfcuLL`&MTFJ{5@E^rc=+2USG6gzx_UaNk84%@Ce2kwhR+cWUl^S5W8N z@@VlR{(D%s=$A9JeK6*m#q(q#44AM)Np%R9@$Z!d&vI886$1D^;DP*ouWGpoQX%z? zOy>6Sgl8&F9@5S-=P_<$0GWS+2;Kw|?o;FI_0Cx{6zH5;N_o*GKJX5Cm2Z!r{V7nq zY{Jp6FUQxVcBqATq`WtMJ=j(CQTq_jHh95)N1TFEreIKCj?xmWd`FOem@(Kj@O8?k zBmJ?50p?a>oi6+Sdq{W*rWy8*I2C1t3L;D1cotF&zfjj&eppc1g(1P3DQ6}qd zXq~O{a=DV0etC(Y@i_wV765#1)opW$-&(QDbb|>e`dWFnXl~_jb+nz3(?}71v9M5^ zu&N5g(ouxk#?6S&<%oVa$uB_1jy|bQ&_7Q%Na~m%2eFlNt`F2Cuhrnm2XjlND13f^ zSPl_V9%2-a+|vqaiSWgKdO9_IVG#%<`591GvdZ56dQwd|bbFO{LA;*pMMbsMljmGy z^u(?Y6si=JZ`Z`A0kD2AVIh#S>{EnEt*APUcrp1NvjAX{_LIku%)^G4J>900WXN2igw34nAf>y`ZP$Th|pg**aNQa>e+ zhabbkK2#uTVf1f>!V4J*DAk{p3a(QP8E|C)@v6fl2FQ?rl4VKxW**sc{2|VsmbVG^ zjxfS)RKHzb4GE^ehYQ$+eXl@R!5U@78uQBB(J~&{Y(b-yap~&c3Hl zv_}DCUl)!bL*I!hwt^rzP6d8#SvQ4A2(ujh%qK7<`;+Ea_@Z@KW)ULusK;f?Ib5I! z5e4Iv7G#@@es+4S{o9Ho$s6bEA?o~yb0a=Jw7(MU99}2TIs%~eJ@WSvtv|;_uZ}v} zy{Tvud}XAP2?O66NK#|vA?hgNVk`D$)|0s}=F@5VL$QDAH(vCMo|bUy>h*oqCn-%? z&#CpBg=Wn*N5xOZJ>SumWUfTs)$99%=QBpmx$Yw)JZ(n?8t=cIn;dIXwo?--RWaAA z5XlX|AG%6VW%ZXtMNG#jSwoN_d_wR8PX{(@4``_i=7jP-3hwT=Ei#8sEA ze$dipQ4;lZitogHjvE{w#qEPZzE`$$zxF^}^N^mH-P@-Pb(|pLK|G$)mZLW}nDQ}; zvH-w`agVH{Cd-f?|J|6_^K6rHMe?)=+dU?sN_j7Sor;H@J2}WS+qu`|l~gzZ+POaX zOf~CuN>uWAT=SB)vN``AR{W@Fp>>;!cR21BJW8b$nF&kv&t;n&e3mp3uT3m(%dvQC zqqbbGBKNjpqT1s2Nn+@oXfiN)V~{ThJ_n!@SD64{y(1Q5!Go)cALS3L-bO9Uxi(Nk z;i;eDT^FwI3*XmNSzvGO?gCuryHGm~z0~;}Jv#Z~>sQrzJyV-=_2>+t z2X6OeTj>|T1l#4NE^Ckph2wI-yHGfK3zQwW3SbdYxxFenU6JH|GX}iSkXdS0aeLJ0 zT%3TN+M}wru$CyFc|JkAIj4hNnMQ@!G&a#8(Xn!seEkY!E_I3_?HbBFml|Sb;fGL* ztWs&!lMK(LemCI+9RJd;kJ^RKW|1ovmVNG6t z*sn@!(H2^;`YW{0HJy}PHxq6wTRKr<9A&lUtW_tbg(PXOvW_@KfpsMf(g)tsrLzn(?Vg%*6r+LTlvv7bZQ4J|n5ucG|i6s$*M31i#!T zAb(N;+j1p5`u&R4>=*n5UG<40+NdD?x}ETuI;I1L#aiO3cCNRP*MKmj{x@&myL@F` zGr8#u0862dRS!Mq4Fg8;(z@oU&5s^74f*dPx~|<_&7R)fEyeTT4j+OG_1E{F0T%n2 z_?S-J?;g?L53#*>4^>zZ?h_qWifN5$>3evht2AoSB^BsyS)X*`&c_|lhpqsaRUkD^!3qlr3(IKy|Y zP;vZ;4v2KF`(f}faG1%>xPuIDROmZl8t1gM1A(6z0=Y(MX>J#TSmgMVeAt(mcp!=0*BZ)0|GrNIG_jI^=@xp4T?{pmO>dXWv zOae-}47GZnJUBN|?0HB-GDUh^H5ZGOc;!i-ndF~_Z>>{L(7hjaQNDVJZ=;+1Yrk?h z;(GKrmc6hWfKNuY>Jo9bc1%9tifTNM_M<27HdgKWZWlh(5{G(J=5+^&cobdd^m6E7 zD6DOjep-PLG-+*5y+cY0Scw|XRI~G%i9!80O3|z}BT&GZcALc~zb8|_=l<|;%XHFD z9(1wdG_lTyFQ${Axh$F9iebsd%Gx?JflOgY82Qdjc5Tca_z9+ zb>8hEYMh|hdjYOzdF$wGjwC_|C zI-Wd;DDJd;`kJjsBel4BE5qfxK7=kQPa*}2<>cA-bz04g!}0-;Y7Y1x9%{Cl;nxoM zB9I#eU;h6T7(2WyoEYfDPSmeNp7F(rk?^kw6um1O(xn?(?mMlu=pvbtdt#<_Jlx;}*Ta9JIGEJwNLl1` zk*yge77ksw!LV!LvObG~Viu|?gEbD74e9aBkG|G~(p6+0K@`A1Z1kb1i9B7DHYxEq%{fj{8S&eI=i zHhkQj*%M;TV>ARd1B6Tq%Ih-u!fNJcxQ(Utib-|2W` zjB}7|Jyn9)!^_?=?r_y#?LJ^jc#aU+O=LD*-<0bpL6}H4S~STIg*n?wLck3JAG?5^ zX0@G6#|6jPRwI0Urt05|&KHA8>5iNGfhSw{XR=P$Wkd`jP4j5E3(>-wB!3r1+;^_f z`Mf#$7#Ii2-8MQf4QKhEC1NZTj6@rP0G+q3!Oyvc6&j+Xvul*ZMeALtlA9{S|CY|nzu0lLK{ z9Z=|3vz??n5BO3NUZF%MyE&v4v;h z##ePd0X?zLcV{ore_W-}w0ae-UkMY@M*jGCebX|g_`377Z}Bn>I5QY}IHkM}^>reBhkss_erq+H7Ly=&#DDLi z-@}}eInI(Vyk8sLOw zc@ytktj=g#YqjtY<#MP(>I#L}XoWVH<#^5yxv zG&^=Bxg1T+HxTUSSK_D5r0+!4ypPcDSIQsk;RKjP>FcV=ldg^Q(AxZ=j0FD_t&-%# z8zgYg0=;Zt?CWyNNN?kAF1}1u^mqIGc&ah~p4G?Iy7{SWzNcY|Vfv24r>$uxR_>tK za|jZJ>7G=-97PQwu+F6jHoc}Ei@FfyD}>is?l4ONYm;+8#iAZX?f4RLUl1=g7dIB{6>q@hbt{<;N+2sPg5^qoP4z6D z(`w9^j=SRTroCw{jvr$ zwEz5m+m?aZLKv%>{pMr#500TNFO>>cL00>=s4A%B{wG$(+r&6uGrfJ!xT*!(4hDV3 zn9RuLq6p*O_)DW^ah_&vdJK7aZh}NX6m*gAjccgav$Kks;(u1acuxWfH<<>Q4=R

    H|@ehFr0JCE;w(9ImwiArn3F%gOt5Kdbz@Q=asCsz<&be z!3^b|f=wYoGuM-NCPb~PbwXekgz8*92?H1#Y1?~U?8I4sXTzUr0$koU*v5EdrmI=2 zUBI~1gBDNAmJpelzT>kXEYvVvOWVpalXPW9zzHxnG(dDi{rmnESG9J%jlouG|0z&Y z8W*Srs74qJ$ab-T^F=&BmZ$WnHO>mw{Bwkjwj&*EtEq$%GD$iFH^5)Do!8wFHaN_X z&vX?`Thao|Z47W~a8>J3)jnlRi#TY#KF&yV8=QKQ49Z^FiG-(-m|bibBOc^7_o(5g z1+=AzG&xYSid%o~6Z8BMzHRiUn^Cl9u z1&|W;srB>oCO6i2Rs+iixYo~g7X0hqQ~)^^Jxsl;mM0TV_>(q*nFW_|SE8M5=7nxCNu{Vke9V6#+nOFlyxXGDaBtX)66q;QsWzo&XjK)8A?3V-k4L=Qg5FiMnXDvYtb~Hs z^A%;#tGk9wTGslgrt1$p;`};J=0PdF(qUlR`Hcq&a6^+p#JNbFunxHHeS{Q z*u5>DL`qI^1FBqYEuh{l9k8j9??>R`WJg!R6lKNNdk+ZN{BqKI@F@H=uugV-9YSO;&j5C1 zv){s40NpzQuhE1u)R2Shwu|z!lg9(Anc_~a2d2zl`{B)43~?u$900g>$5Jh320vI$ znWuM5#=0EszPR!nW}|uWr~%4#lD9DU-Qn}GvwR?3U+_Qs;e{;5Tp2UGSYA>tI%t<^ znfj@gM8O;-lkDBhLS;Cnk06GR3G4Dn-lQhpZ&z-~#xPuqJ4$GLN8V%sEj`)f8G^gx z#wpq<@O99Dg5-fOQbC@goSdXkNZu7-?Eo>TS_$_{6F_3hHL~{x+_vs^8&V*+Km*F< zIm&L+!V!R8uYEcT2O@rD1KI7b^vEdax*wk5Oz zM+eDQkvhqd`OsL2OT!c|e{aK5!Al-;^o727ehIA0b>|f2rjNIfC9rJ!kT+qz(+_`> zrTgAdsz+18%Wg9Rj^{}F+-COUqWkYU($?F9fNO?2w%j1Ou_(tKU2TTnDkg2=r3Fc* z*9`9UKfXJ4c#P8Ijm<65=bpz$!2gops_}D1+vqxkCmAotlUm3=ZY*k17q^2*^iY66 z#Ony~+rra0KR)weW%OBwylihU45+|OkDhJILXvCr-Vsl4Cq9}dhB~Vwpi=H z0(;EY`MPTD7m*6L?KzY#p4g=GZF(dtEe(M16p?t_KXtrhz`eE6YAT5r;3FN<4iG40 zM0ZEG_%_eHK&+?-eoWPwB%u5(&3=f*R*L9S4{1+nlP@phL;(?Zz~9HPlq%mXRZRSE zka{4DDPL|V2(J()-1ArdV9)v5^?zk1uf1HxQh(kxps?2gHL24QfU#IBuY-C}AbWx6 znvHd-PlovkBEsqht$GQ1Cus9N1xlo94b7JQo4KsBEy$vR#f<7EZA=W#1!82z2vvTy zJ|}^W8_p5J{4E}pz?=91&?N+bQv;;iuYkYX6O_AU@t%3a-P zC_fY!>A^5%gniLkR%g;VdVanC5w4X=4)kG_QpdYU+?hdgU@pF)Jo6vQX;1cWA2|?X zQ7V1CTk52zM5_PhK9R^n3N2HL4((1i8qH>s%G>XS{KFtY`$=X1^#?fJG?bCBLfCSf zZc>(}BGg!)ACzCY7Cw`^ZSe~-jHCQ8ktBTuEBfOUsV^|+x8#u}ua#2i%@wXy>o|Yi zP@`z&3TrOh2fl(fzDk0R(dRV%@znQ^eYo!jsEm<#hxwmT87IqLMfJ1!r_)U^=bNc< zfU+0(-KJ^M4#8ZABIYKhIv*2p!wr~;NzcFQNhDh zgSq&i?_QFjs8FMHBfhL-h!d1a1I(|tAJ&4pzt&>ZC+f4vi`JOOv(!(s@gb|AoGCGYY-{lM5Sl?!2 zym=}I7kXt@bDTbzb&AF2(%x8e+e~Ey)dv@>4*}C~?N*sz?44Rc4TsXs!ZsCfrm$YJ56vRkJX68;> zjr=L+;MmigDD@%g&1w9?yje#mToFyU@v2j1;$`OG)?h(l zC9*IIq(MJ@Uq}epi4qS+MHnLrxJMt|#Cl0zR*{(Efr&9pZ6@6S{G=`pj)YH zeqX&gKui;MEZbZWt_rI(G@c0JZTpt{?n(d(eTrIYLCmYMQe}T+%53T}Dmt90#f+XS z?=)3d?Q*NAum+Nu7r*H5qwgTCY;F^Fx3a1=BlLULi|-Q)7a}pI+?Boht)c#%d44%y zY`iDsj}!9Y#M~Ek5uXBkVYAnMM6K_FQO=Ln!GO^##>n*3AiY^U)lC-L+vO`;)`EYpb8??R{le zFZ0HR0^p+Rl6@Z<>LhmlQ{0?FzwGreaA}|aU&UHGpm=TdXS|AM@ZX*x>k1GEy!_$8 zVJo1w?_?jr$1q=2>?_I3LG}Fme~AfJV~)2vvy1sm15|GD52^ zf1Dor0*-0q#lw=d#5=Y8g$%b(@6+J+U1!$-L@|9z+O zZkPm2*pUf&yq3_w{};L7j|RRoIRh5aiL(fk{+#?n>Z`@?o{M$Hn6_?kQ^WA9c&+>c zd08uI5SbL_^_opXqbYJY+2PicY zAoYm7FGvfTF<_c;hJ<&Q;lkRY{5xM6@7)Wuw#q?jbpdJ||5%~+iEL+2QMi6(N1t8} zgTX9D*nPBVF1^Ya^Wf8ZI@~G7nBTwl4Jy*B=DqM2n2h-MuYwGGDL-jY-tPo<0*|$- zIX>K?ng2+!{*eETXf^?mb30&Tn-!p~Fq_E^+!?7<*J`@~B`hh%T8vJEBW+wqXGa_pU999&0BkPmZsA zMu@Ofv6(o+irMt?RWQ-tKsnpC@>=oe{O8E+WK`Hz3kK!EEw5T;G> z@2|%f(~&>F?UQC1gnOS^c*&X{%soGz@A4l#6<#8md0klLn!J4V6V8_HprT4KL z2R#r#eA*>`2NS`OJVJ-FkKZtO`^WF-H<=+XbYEy(_8Of( z3(h?HJyW*ip~_h_az<&->%hpj(TD$N<%5V6x?vs&0%Ai?&$_H#*e$MIY7GcYJ;_j&x6j7r^Tb+Fo_vrS z=pMW=lYfS@xxitiB{GP={yc~`c{a~XeJcYoaBvsS5~I$(-nbYX#c!Xn@EQ{%)y*7n;o4_x|oZ@Qkk73@WluZknNPlyYp{RqNYz z)bvh!=3Kt`owI5w>ZV97(-cF^SOv{wbilUo`P0$vuoT9NkEtg;t)z-`#4FCs@ava7 z6K9G^LVL7AKGNeKztIM*UK6}K>-JLV$K0D1{Jnwh1Kd`F6=CwtgmvhYQ!kAUd|M7X z(8Zt~ec}5iQNKS`G1%(r!xuZ)iT4En*c$OQP<>qTK% zqWaKYQ#8VUCwzmd$1?`WNdIh&y2i@_9l!%sH+$**2ppD3b=zEfFmHPAA6^6XOjSjv zfnR#-6Mc-9bz;_L^dM280?UjlaIGOF&M`?V2&_DB7`n@Xh@fB!*)E3mLUtGOnr&<+ ze5}6sfPh#Jt;qnGTaF zg!Alye>csf{oQ7|51tb2RU-|+8l4z>_=hJRyUi4y3F@tn_btHWUWZ+En_-`k_>#{v zMrwEXR2k6Uf9s!Ps`@&iiwe?>hSu?tj&QKiWV>jZx+(V{p1=2RZ`h@rO(kbI@&KE` zXD1%K_*Uv5*_jQF*JRD|U0tkp zhJ1neF+2RdG{p~}o2AcBeGKf|cir`nr-d#Z?a&4A*8#;+tvbH=G{>6-K-j$%{0e#K z*Ig76(FTVtNVm7)Ad?=ik|Ldh4EClt$NJhK>&>tdu6*~ZvB=iQ56toHWQ8qPr+z#NmESMo4o zFlmfLRV?;q@uVIR@%baGb%{O}^~~(Y^;R~cz|yIE>D~kBlDI}|B87}4WZB!qT0O6W zH!OZG!e8jn4Gp^9RFv<5K zwY=0@aviFO|JnNmSL|oLXfWFrGkh|p1L`xfwVt@>^&eH;x_*e0U|&VEy4O{k;Z5Z* zyj^${jyt#aP)uxEa{++%q{0`kpocozw0H`-cwdkd7@HzyS}%(OMR;i*pnA3e7Kbl^ zG7+NZ{7FhA$dt(W>O6PWLQC~ky5kjSGRudB56(} zJ=_VynXM)=QNZs#z(I~Un}JyJJ=hp54n_BF?xe-K!*c}j`RR4)j(CXA7Ykg|5!%#-YJ4DeCxs?2`~H26;`*uf)N|^_~#WpJo{UU(f2!~p1G42y!wAw6nR}L zpPC?EZ6Y;^;qBH*De~YFz;*7a@G#&z0Cu=c+f?(f_3uT5EEl1t>liPs?|@cTlp-%!<0Su~hTWujmuzfI zH~;hbez%VG!?lo9>d(8nw7=p;%6J@z%(#>z4ivkMv+SANUFaipJLIv5xxFvlCHY>V z&qk;8-{Yh)&!K0nS`Q<}uBlIGrExY9tv?l6xOFm%La&GGz9S;qo}MwpD=+d<44Xab zz`Y+AUn9Go(%;H3+{DXFca*q<;*jY0GU538)xOqb{&oYg zy;gK)=Z-^?3K1M`;m7=9f`U`;@zC>QB27K$^jL<=Et+Vbp)k5dMJJOF71|KId9ek$ zQ{)fdgWp+Xu?m|H1@urP+6QBOmmiaRWFyw}3{(Zf2RD0ev@ zP^wHctsJ=nn?J7JxB8eB#`{2y*4OucV`$ahJcM}F44H>TLg=To>|qLr;d3T}w852WAcUX!+REm-?&|vh#=%=hR(^ zjP*xPurgcs{{5a4Q&!2eu7(oSnd$&cPbt56*$ z@P_2Pn{dTA#=I6CiVGYHSTj8tPLO)!sz-zq*wFhf<6Vd5&=U#5rF9r|w1PmMr}>aS zr8F?!^RplA&%$!~uoP37Z+gmmEt>-P^bSAOw~8&u@adNARkLb6#$^yRD=YQ|-qkmx z6v)}AOMC}Hr?v%p?b1i-z>*jp;zHJVp9sS>XaC zRozkNcES{J11t`?5$fFdYxz)y-cB-vV4o&#yy~-&p!6h(ynS2kXjuFB!vu!1oa^n8 zxV>Ip$5#+<3_Dx`Z@6_aMX`GE^Fm%aO!Jdb;PJcm7{zBEIJL5i6HB(QO6e z4_wY3$W%$GQMxSXc|E^?f{71bZ~PHQIBIj0z2EG6||fy^u@) z2KQ6apzu&172TA;YJASM!D$4ZvfAS3UcbV;?THUk-p&nwo+RN9%`fO_sT3bGi*Plq%1B0% zmBR0N!@Bk5Y(ik&rd8jtX)!LU-}U-`@Q3P@@rBOH{PBS=NG}^5aPJk>@&eJrbaT4# zW)3VjtB#M7UDelp4^I=+1!0;1478ujd;C#oeQrXZlIv8@X?PvnRMRN$;9}5)(vU-< zp3vo2rvn5zxDh%0fmofVer7^_#+;ngV~Lm`(_=N*RjRNtd(v9|Kx}Ev!ze**gou88 zw9xj9()kD+IxR?;(JjnKdg2EFobpJHdr&ea)-<(NA4Qf2gs$@o`D5=pgrWa$GOjPk zD;~lk0t~W`K3Dl`Kq+OW$8!0x@!+&Cy~68Md7c9<)+8cojvdi76#rA6$mJo0A25Kj znqXKJ0moHxU`@yU>`y`&a(lYetfmB{6_OFs_jyS*3aoNv=k%Fxfcb``u$u^Y7mO)a zTd7a&_i2HAkU3e88I>tsLlC~gEPerJdwrm4r~ZI*JNxLYrF($+5kuT{WKeOC%jij| zT_lJ&&vh%W=UO_R(C>lC{jB{EQ(h(q6&{norrxynETCF0giMzfklRT;7cY3@ zInu>L<~VenD}gz`*Cc0v%%tiR!7|e!z*_AQW>>du$twHKVlV`YWu9kySPP3W{++gZ zBkZmP%a{(Rwo#|16Jml$^mR+aiDDO-ulneMOj#dmVHkW4!mBzg9vU)h|I-HX)zn4> zQ$ea)1_KWS?1%G~zs!-4;GtL@P9CBqSN%u^Y{i=_43X9@jd*FYpa-~Tp5gt5zlkF%jQ1Y6#-i~E7`p_hUQ{3qRkejEKMdH2q6(d zZMBN@ZSI==Yk(`=38ji*PCyC%Ujt@srueqc&bRp(A&5#K31bhQb0RsFIYoUtGyn z`Ex;Fd43W~C$J*R+vIv-EmeDfXY#hjwqpQV6_Khzo#j?2l+@r_U8d}x8USJMz~|o~ zKp^!sGCQc%&z=Gu#Aj4wuJc#06wuNZ-i-d>{+F zv(eu*g@<<~ms=2ia+00b#QhoI{hWo`;wam*Qn1{R9x0@l__tJ8`FsbFRtCJ<}3 z!$=VCH4G__&>k15PuHU#PW0WK&xu|tZy4@-eXx~kOhUet!u5xGqGU#mDPp(vIaBcm z2zwtxXJyXa(~(H)rOc4MBTFceWv<6+e@xE%&(mip^=hiw z?n=&6KlL&36ClxmU8c|I$Zh5;HSa(P(wwk@vCk}8sTN%(1bZAZex}7b@X`tdR>`!u z`@v1c^3#I*43h$&D78t{e3Y$?8lGp zQ>_qH;`S~E)4|nugauBCiUn9P#F0f<5Hz}Y4h7Bz$vQ97(i$30t<`rzt%nzbD|EuD*SSl7cSkEYNz4U*4gK4LsOdR!=Uk_2 z(pZw7k52}(>2;%q-{7F$?6oG~^8YXn3w5#n>Co!`$#Z`4o)Da-`#w**|2gACWH%X< z>C*{!D<^1r^wYF7b*@I`@Zcq1i~S|I|8?2;5hYI0PiLe>oC6`zxkx` z&qUXC@m>Sxrt4&;?QY4i z6cYLk=(1!M&b^D`LnNM~r|&3Xg41)>w+WIdQV%TaY9MV|V5UVM2>z?=HECmLu+SG% zAB2cPw?@w8qy;xA@D!5s?7`vv_j4rmE|pT!bp30_-IqkyYuKoKtQD=Zz%ig=-^#Hj5bKE_Poih zd8au26$weGy&1>mTpsl(`_e8N6e(VT5$4jPVQqNiPE8Z8_+!qp&^^5LZ$!2Oc2^^5*Qt&3kl{t}F{kU4q=|-0vLQJz zwq}Q8hbr{F`!g)3l2n(xq}^jDyf#?USOkA^!nN|(8)kjk{$e`_*!i4yb1o^sStGSM z^H*4Zy>oZbeW$s&WUoaN{>_3qr(J7r{qo1aHwb;q8L6fIlh#ejobEMS$q^6!sJj&m zqnKrZO6UwQ%Y`_F>zgry_`7R^C|)ZUmgGeLD}6vpHy1kjzy+(G8UwcCMZ!$*U*(@> z{uq$aZ@r(9t@g=OYOwmR#rWAUNlZub?6Om#*5=QZv^TMltx?sZ5FYU`lvWEU_hQLX z3#4U5FW}pj*RMlLZYJ$FBc2ENPUO)C*J%{On%AdwWadTdeP?=aruxoe{Js^hPodmj zhSOFtw(;*KMR7)ZdUvjwRfg%V8nMk+^Z#i!yLhPtp!{5yR@5H~oN{X!`4E)$VczYm znhqp!qyGEI`)^BD(!y11^YQA?WxUPm$6IAlPiIvO=X!^Ei0SLsR>bW}V8_zBqF#9O z4_ZGIdk`zO5%pr4dSbJJc(J5iKS+Lm6sKhYkhB>wjrnBg@Q@FVW0?WNk9-y{nV)H5 zVD?SSbO`fnmLVReAS{zK9WteKR;w{Drefl2zD2$Bgow%v=S%?Crsi$c(F=f$4F-ay zQQ)kJMtLIK-1#G9-CoD+y!B9JY~DAXdf}_C(oxK^95| z>QSt3E$j;PVn0Uj&!Q#9HrGdOpQIMf#6MZ{qK68e2@qL8ZHMO_mrC>SEgE2Easm}z zct4y%AjT@aLkOAQ^HQ&LWWyDo1DGE!`a6_g>3oljvmkN$=vtZ(?wS z*A;F+4yfSdVXf%VtLD?vpWze0xW33luurI~@x z6_i*06NrT=)1-1T3}Ls%m{tq#X8R{hkbF^7{G*p5Dk?*)nE_Cxh_D379~MQS%rCaT;30dw(ZPolq=fc} zGZRSkbBf`)fiPg%_irxEzIyq212!lVq>g;mV7u%KB<=R-Z~3i`kcOb;`RT@Fs@bjG z?bLlz30XeNLDp91T=Mvax1k$@pVy|JYd5R zyVpfv2DW~9(@x~S+zutIEme(<6W=dw4(KK=_#F9X+2)|GuS9!mAy-a zHo`g}>IudDunh@wZVqs6`riYm$?uC- zwrw(1x(Ehuw)NRkxne-H9Cg^bG3E;wq4w5Kdh91B3lSIW5o#6{IYU2M1IY&S@f@Uy z82m_E#(|y#bLt3$TAwz2a5C$8o$*loY)$uEM+e<$D4Blrv!c!-Kz(#ONF|f7^R-Fv7vt1JJM^Ws{Jzk~A*EYO6SxiaDkD8c7#6 zh^|6)inw+1Ijy+P&v=HaNdk=#Yo$v=My-TVuprIy}5O>x;Nk zjn5uV+dsdp_AP>a0r{fBZ@mwb*Ju?ZJW-x^t?ZZ&QxA98M~nlktn0hB;gztI?R{j2 zD3uuP%2s~t3Sq^l@s*R(x(Cf~-$Q>IESneuKbg~B-Ur0D8A{WZx4wLAZ0HjbIl;|? z9BGKI0Y#I^{pLq^q>(B|fH}k+hhAWik*?G{u9)#Va_Uf&yG35r&#hsAE>)`(o~dVN z?R=|i+vnS2_7?xX2{z2~bUAPkVvi~AkYs%ym3PO@4yo|X-5drGdiu6c|s>v`7cy|}j-Ti8FL9t-Y*RTC? z+yfE^te>DP@9!wQv%N#=rw?JsEqo2X&t5l4<8m0(^?&rh-!3*gYR`C7Ci~&led4td zIJwcZN07F>)AiK$U4=+*5uLGI1f$9GQ^<9zQueyK{I!9i$Wi`-s0?Wv0qpdd z$lCiHti2lCrkw;ofHvloxBG0)Bd^Z}B$(a5p!;3}|I1GCu4-C4_$rhWRCwIctLxs%SMODxRMAM2i zM8))Bv+47UN8c=bfVP9W#YUw}UHr<K5#9?iy0XXCX4$9m$5z{P`c#k=|y8 zEIfhA&gh!UKaZNtR;8ZHCPNrU=5tvyjK!oSRsE zHe3-VPBl|y@KATTh005GYu$^#G0<_wzp=>e*Y7!NF0BRf;VEfrbd{W7cfkSgp@V{x+bjEG-(=)ff)>mFneDs#I`vUcNSrF7Y5FKt1pA>>c5NyuM}fWx~0MaTf**a2yz1B2CQ;-9nFFgRXo?@ z<0S}Bfoa9Zs>2%Jkw>La^`Xna>-nxb7gBxBbRA62JE+vW_xBqEKO>(qzZUcelDyMj zoK>?`PtHTiQ5Ywob#%po_7&tP4;N4%{8nId#7>jqCetPgFp5^& z`WlF=TPo$kzz%->^t8&n3}mMvIejjhuoDlEK->$;bd8dW!s6ZjwHmHpROS5oIgIR0 zAFWFGfE+De7vbAF7}|)Jq&9E*3nWVq=Yw)j2x(FwLM(0!2_Qz*c{r>bQnLk|NJpad zn|sz;733uUL4~I2ynATD2e;h)194y>W)BzZIMDHgF5MmFuE)ZT`bhIAU(4p;Hzkat zMtfD2Jo;4`B4`QYx;=Ov1HZYGAr7ybzvR|zIc7cxz;R#t{9eh8)k8>$MXUKJ|lIUB%gD;v6abN)}1WFbKkcN2j|~sCgDATV5=;}!_#KS7dB@qCaoVb~Z^)2>(j>KRzn}yNw6_EDq0nmloba%IDS&+Kye6fynadu^)l|&Vi485}6 zVsTiGc9aP6l$O=mCy`YEW|JOyQN^GULYR0FYrQ7SpF)}6Ey5Rcz>!AR9TL9-4S_)F zWlxKlVm1yr8x7m1%l zrRqUSfKc(p8TU0X#=$Lf^UErfXq59rhC6-$WO>sZJ&`w>KU%dRWwO#XRZ}#Ua0x-y z(rrm|UKYlrG}-!2#(j_I9em%x1225`1-}#S*foRF+f@iLDC3k{WX=uGg`vLJK5m@@ zs7{1gKA>BC?O;9{$N%h)`x8iH=hL=t^led`#=s8K-!Z4GpI#4^v0f|37l@~uAPy$L zel>Slg=Ij=GTl9`k07>H0JKs)z}`gtYv?%l37P1@axThvcLC-`|Deb$->2Y5)pT?p z(k#YohRaR-Wx0C#`vsk}MQ+E%OibNd?7WRji8x4XM{fibNxvT_g^`ASSbQ7pX}Fkt z1(@WFswlwbu}YngOz;bSQsVfW$2mhx_AT~F41V`Vpl|xfLZlNbArHhn{%%m#*8&%* zjCdIt9|2l-BnKIi-JI6Dv%r(J>Vhcly9+VRo!~#?tQS;-8z`beCtwvO=OI1u8<4d8 z#QAx8TY~Y>YMD&@QGiuG~^_(d@C~g`(Y8J zOIs{<;*2J^NZ>cCxin+6SJTg9=%g+`QBcFD*B=Cxj_a5v{>Bguv1J~lodvt?V&s~p zDS$59e<3P-{nAiSo0i7g_nM$QP;1E4B_{7@`fLRM7fijZ{MBvf869)H1Fbv(!iD^) zn`TFf8otsqUhpzYry2w66~r6{x^w^pcj3OtgxT!U6~d;)FknVeAM^Bl@Y zh>`xhVv5_)%VJDzC-vJHY0Yh@r5N+me^sj*5WCr`0xDj}MZS{YHj5HPf#(TtCv>+2IzMSPC{0iI zyj;j}a>uUy@Tb&i*aJ`N+laq@dXCTgGr3%a-4~Afl|9!>4(JvR_s zvpi|W_5ZkB81b}Q$#A?U40~9HbZ-*=S8$B){d{UNyJ+&m6t*?afb1pI=a%x*RL54| zM~oG8SA6ua^obH{MmCYNB%wyxx{Hn2r|hfVtF(_PnW80;)m0gn zv{fFTi8Bs_eL{u+DtB&1vLZ$=LsYv|usMXjl*&1*#GvkbPTUK*jQd`em+W*d^gHMT zA`G}kI+aX!NrL4iHLgMo8jbx>0&lXlwOXZeIn5Y;kLgQ%P=J@AffPPe0n&wxU2F+!fEf=l1#{OWkg)?yAB^NguaUJ<`;_VyVO_9%yI{Dp zG8;LEX6FrbN90@!Cy@wjA;iFK+_h-dheZhT4)dqsUm3?p$@3;-1k_N#^oQRbp74)K zkJ4xGFP$_%X!KTET< z>f$QxY}Dx&)Ga)vO%no0yL%-fBA!bs^HXkzvoB=G_HcAu$T__)Z6#bX(nn%U{BmiP zRNJnUyV(SxJ!X-m-I$WW-EIvfm(*&#f&Fa|>1yc|V9vpbey9VYr5PiZIlksXedZj@ z0^s*mw&Borh}jg93ILbrM(4;@>odhO*>?%9ahT+CB$$Qrzx3z~g6l<$9n+R@G9&#P z5TOJ!Wj!W2!<93ZP~%V9tS>#CLE#Yymqa1XqEu!d-(24}R92f>0!SB9)65Ee%`fQTG|JlNte{{dkCwVan6Pq5J&B{{ zW^kJbnzk-7+941=4uuLE8v^m1r$l=u2C&l^mnXMvCH~Fey@q&Am$NhRBDtRd{%;%; zn-Tq;0Dg4R1rdY6`*9-Ob7`4WD8H-PNC{N|`vu_!UU#y~gfJtMLf7ko{WU#_qvPmj zUatpVXHOE;zN?x((|-6mgY@sD;AcNoG5AHRHY5nUlw@9`i?ai@1x03dydtaTQ z?-+WXJRUa6Ugbb+cZ3yY=sDcc=h;UHYPOihznR+&J#IpZlD2$%;%M!RK z0@Mo5GAu){si(i-pln_G7`CKu@RXuG$ zEJEp#MGfykfn4D--ImhF{&C#$tWOTSKG4n1ABXDm@np+D@03(yRssXDck^*htiB1{qdr8KBEnz&G2V?pd3!hyq%4+B h5w zN1VG+;M{eTO4XFG2L(`>)d_#}uO*ZMN1IvA0!J6uk%Kfb!9aW+U{QN+r1qbWM6VnpP?!s2C z6nII4-|M{M<X5c$uOzNr||Eyocwb>x8gV3LRPhVxQ}7sND!10;{3iRItP3>2j)}oO91%7fv2B=`RDlJ zZQz_bQR*}$?jWw@*^5AKZ`1ZA%kG90Zg?R4U(1_^UEyQW=7~WNfQs7#&0YTLb@=Dv z9~iC=Mw6~y#nOwxrv78H=ElH=LyHFl?#fiN(BHalk92ocY(4aF_V3*G0(<2?P!uIO z`1uG|Kb_V6-eq$S?5X~ga{CLl$Q!Z{wak*%=#s)CDb8;n+jHBIROorH8}7I&@CPFo z=}y!dW1zyag88V7_YJI6dr13O)azXoccSKX|Ed@E_qrP2K+(!1!GM&hY%U+@1QzPt zlBR!qGa`jax5++7S=mWE*#_ttAZ5BJ&8;1YNsEdpw0ZX>EdEvOc!5 z;XS@WO&eUM_>K=Kt%Y&dw?1tAb(B!D@EFnpP)kg-dzWl6JjpSqxR30sS{g5pCcXCa zX@im!KB1OD6t{bxgo-$M7;m+;49^pQ^{A zLK-#36QZPLih`TYFY&ACf<{P52IJ2=##Z>*jb@e%67}0>nW%ep;Sv z%xThcz^MfKh-S5#=6x)16-O^QWqtzL4$8{~#QX6PvCaMQyCl!|eQU%|6KDasd6o7Q zAw-@KOjZ}XVN$5rkQPI~xG~aaxtx>v={I7szs!$i(yQfSP(_8%WkQxu8O@A8UZQFu z=yFfZOj*mWADAOR#x$WUJGaY$;2E8SHRT>=9{xW}y?0y_=@<6BDz4%#qQMnKM1=sN z0OxN&xC=J+{PaM6?|itqRq5V;;u@Wt->=_U zeH7_*QFixIVkE0Lc5O*uYE`u!mAyUPE#fIn^2A<2rq*+U+ARE~1)cp~%HK68qLW}K zr5GdkY3W&tHP?R5->4V+%nN(yIOig8w8lZqiWSkm)lvF%2Cqp9R_p^^6=>4+%KRQn zFjuNoZs#?N|LDv{;fCosUvEB)atl6(o zg-Aqvwh$_jCTP`(Ch*t)qs)365pQg?>eLR>)G%{Pz~%?X)_XF3YT(U^>^~xfD_}uF zdflF}Z25HPh&7J6HipV9p{M3S1VjqqzdyT6meBkSGocPs1NZ~m4Xixj4r%^zi9zW- zK}<-!3Z_Q*s9-_Zt?!aZ5r<_EuTZo=u{tt_TUxarf3m?OQ(i^zL;gQL7)o6%H9^sQ z5iG0JrY5U$$;E#5O78ya^WB)0uUjkq6P*CRt_H>`B|!J4#2+~#AP64mJ@|AGV5MaS zW2DHlT`ExHjd^6XT{Y9Hyv{)UXQ|{OJ~Nj1@~gICAH0T#bI!w9@D^(owL3HR`(Ad8 zUoCVZL)>M6OhR8lu;>;qWtHQGqhbUW+~hMc8XA;OQ|N^IUTYWc%kvzVK#Zk?FLNesY4ouEHSwhkl-Uz zW&x18EwWA;KOnJY43u{`i58RlQr^aMqLv#6bQZDCJ+NogV>J@!mcd~^keEMkw9~c~ zoX&cLwa3kH3G~?C7UQ-l;4LmCz8yFl`u;)be-IOZiZy# zD0rmcz5l8x%7=ZPmJ&>^~C5*DpWdIWBW(uH`EQHj9y4o?2~tVLVp_rEfK6cq0>BG@oq2& z@(|QYG-O4UEY`IUoc26B@Yi-$f=@dPE_@tdJieB`5*z&5A3wqKldk>Z3vsh=3%H=L zlK%tg7`nk>w&kg9!V^(xpW&z@ar;|%>}i|e)UlcUtJj4lJ%!RZBQM}5T(s_RLqU8E zy2XU9cR7emY-)eqyIBD4=$HBewsvoc-*e)0M1Cl%|<^&C0ZFx=aL1Kca0T?155b{KopuE&N&nI+d_W5{IGhxS zJpS~ZQh~-U_=M@3VyB#b8Cb1%Y8XkJS;AiBwGuD`+%WGI=5`zVxm3?R${8vA@c7e* zD{>RJt$@!aO$dFG<8WcuNEFBl%A$dMj0fw$7QsFV{}p4Tq%7bEvtxCH6pG0PgfRWX zA%x{y3|Mg-GNmfb#FU@BfEkvp9p_<%GbK~m;@&phz_&F3Ywc2{^uA7O08>xq3C5|_ z9O}^05NiYYqLx))jL0%Lc|Y_$02cA*YJV{>e8x!Gs)v#%l9O}()n~7$-GuJe`?c@3 zvq76pe4vNMgNNXr{F1JsM@>Dg+gXxiA6obkn9`YWrR2d$y`sUj0{V$|!RZ4nz^%qB zGIVex26AR32orAW?Wp$R&Y}CEc7f#g!8y1#A>m@_FKPRPLqOj1g&U)L@}8a0kgs*6 zXKd!hJR*`4Uvm83d;xySYM*A=i=Rm!f%ldLWHX4wVp>O;aCQn0J^9PEJf~)G-4bvL zPgA1q?j5LAb{#oV4^#3xrv<;A#L$tWHf#?H)+=Fu7AWy<5Lyr?2K4q)MQ?X> zh7i|SRpbmVoDfoTrr(h>!$w+K1ZI_i#TjBmE2a8;CwrbVu{X@=Tv?7>q-8)LU-g6g z1DJ>HJ^(RikbpqRkwaELE&Og_uuL1Xp%ew)_)<^rj=}_e-yQe_Gq@#-wxS7KafgJM z>b z*yaOwq)@H02NFZ#L$=*wxjG_d%HGfouB4XQE1r70yMoCWDoS+7Lm(j1tm#%@eNq1E zy#ay5(Oc{p?R$Jn0Wasv6*??;C3b8O@vctvfm#lv4Jup{eD5CsvsN8k%~U$WUeM%d zakvvO$Fb|pupi|(nvwL_8H4@`oW07vHu0@)$cPE!65kUPK@#SRENsvUUF>9l|KPkc zi>8C{Q)bF3a;&|=*71KSHA>2uSU_keK&xN&SM)oFD!7366JUiZN4q%(Sa$vT3#1y^ zr$&iV>Sq1(9ThVU;hS?1;90{Pji5|^e*4~i$PIj2f8Dy50Aq5)3$knK`1#bd!A}Vf3 zOPWf~yfNz^PItItD)|Ux#74ezP+5B@t!e_oEk@Beg91k5qy?K__o1sLe!*^F-bxd0r=3d+PczFLnl|m!cm_c-?7^nfp!-pZOliUy z_=m;;5kQqbzt~=}LN*A4n)OMkRC52h94Sdt&=V@olf&yXDK=2EM&eE*6tOIp$_O@B zQ;wRHAGqrX(YU$;mzXH(wMpZB-2oH3{x^;G4~k|rr8c>~j}(B1WJ+w&EHhsJ@Yq!w zO8I$_;tG_)uVJJ(5 zfeR6G;LcM2wh2$pqLf|&w09f8fDOV%7rvRzsyU} z-Y09S||Jr3u!px6T?ufRa+VpH$Kk5U?tbnm4EG0S*z zBUUC2`x!#1V+<;H^go=DCdLoyY4o|N)(YOEpIlMziIV(i)8G10%FqkVD{9_w{JfXk zLqIHq+@BmeDGi*VHcc>I-m5otHKvSiz-U%1oGY+~MuA3!rP7JM$nvwb^fX(}=fw=i z6Io?~G1yel%%lpg_O{MUUh;VZqYJrc4@ytR!}JZX+xxgK!P2A%Q4*AkB%7-kBx#nU(f~$kKsrk9ZOp= zbUV!0vCXD%XVDyl_;zPYb0_X1B$^fa?Fm6?lwte6kZkozO=9Z5KfTrxF|Zfh8Q_4* zjR1Ml#uJw{e%f;h91Eu*8@PZI%mX2QvZKm^F%&w5YJ@$FmDB93$87YDWl5&B^c`+4 zKToEWy>moYA8NEV330xmr!wWe4JxBsm;qsiwV#iTT?KoLXz;Cj5QBq;DRXxr9Jq{3 zlgoA#hH`bh7L|_9gZMjx-0$W5sON+i@^F^IFlhY-S;4R`q!B+aP`gwFX3YwEf8*?p zx+50KpX>q}j1YkjeOY+W0Qt`=_RDF&;;b<31Iro$d^r{SGyi zZPv6+49D;`D%H+#jZy~1G}@(=USVg}|2xe0cm6QKI|yzp;Qi;zm9(}Mtu$wkdHxH$ z!Fe#O7NiQRW*UGp-u%Jw(9(VXDmcE2*?8j?QnZ;)OjM zzkHBw`6d-*(+l~_QST6NjXv>$mld>rLCp?&kU-=!32E-(`9pFUSm?|6JInD7 zd>L!@eWAcMP47K6*z5(n)Hp}v(^_2rqK39X>t2@ZP@NRNZ7*Loe!fN7){b)T7W_U; z*evF2Zmts~rkB6^ptKRV%&_RP4bks|G^I^)f{WOQlWNY`tz5Ib zS-L_yE067VBRp&$W%MSHg7v&xad)|fLN2Hjs%9}-8=E$3Dd&0Q9;u{;EnpLw|G_Dv zwV$tn&AdhQnx0hymdw%DOL;|3QLP{&u(!T0>RuKgn!lIsY?Zvujg5e=w^dc$Na_bC zzt*}tCZu4A`uJsXWNaq9L8x}rumnDir^xBHx<6`o1bY?MI~UyHEcn-?iBYrULI}s1 z;*BdqD?T{cqivdn4ree0P>hk8k3D6gg*HDLz?|jVoR{??uI(F?AGXguSM4?VW;Cng z(SnoxCnu3*zjMsMb24Ey#Jx~w7?yGIx50MeESCD^ABdobF-v0cKh}}cADj-i)*Wt+ z53`NT%5u8YO8YfR^>F#0B?K(T*4Bf+4I8z8H1ht)lCD52Q8w8Qc4X;YYQ@RIVeNkp zRs5YYx@aYDo577A!AlV*QIDAPVp||0YJF{v3qj9Q1V4;Acmh0JQdLw_lGN{3#6Qd| zRC*EJm6e6K(BfR{3_Ied_j+B;OmVpA1zV2oGn8ncN#J4a$faL7Gf)LP-CDP?UQYWt zY!E_IV?rFi7FZMEQ0!ZoN?fWj9DCk$a-63Ti1IKWf*fq$3l5iBg=R)sF)l*}s&mPa zR=sfAA^LG4xWkp82e%j)rO0xrA6znYrV_XA5nsvwc_(ClmXo~)ZgKo`SUT&33+{0? zTmzDCM`P1a9S<9|h`73EVP+r@bjEWsndDK&=IJD17oAvJZxO+2O>AT8L%|S|m6vuZ zFs>9>mox$lbhT>-KFA|A-mk2W@t9RZ%in0Suk7Z$+sx92H$~WjE3uquZ-wOn8PDglHVr?G$5Tg9B9XQE4ce; z2IV!!(B7fR|C}`Ku26I6qaQk(UB5E3!HBwVFbqt_{*WnK+UTW=&s$6c7gOQ3I=|+9 zq^T~s*#hevB+n+xD-C)6`}qN|jsfn-HZ<#F_X(cNp!jD!xSwWLpa{5_L3bykUn^66 z5Hzk)Bsbek_S$vb!%4_iMbB42ccVIkpB?vEYHV}u?Q$UnM-DWxY=*WW|JghkI2NTb z_{FSm42Nv-0LmFuSaHv$hjdgtz78=!-;ALZ4e1{(2C{OWi-VyWb!m6)PQkG!PU;26 z#Vi4r4KyGbU~oFP>M&H1pnVDoFkW~El$0*K7c^Sy{?O^4Av}SWUb@>%5QQ6KdsOKI zyLlkql>cfgG90706UE5rQ0Z}10tZ%G8$w$7#DwM`D-p|V z4%M0r5qC!rYSH$6{_TL72C(7&Zt;bvDWDx=o4f$ZE2n!*jiJNC6Cc0DAQh$xC%7+E zKD$2@&54#Y0oXcs(R1!vYr{Dmr(d`_=k0(OvBSp}g znbsM&Pp(6Wb@Z-6rTkOc*W-_sEs{n3RB_aJsyK1%h1Fz}!anPjdPhO;p*hnU?|<}z z=rBkz($pP5F3tN7Qo^dhjR_;FLpo|M6`@S{L*|PRF^HZr-9(cZin_5#2%sZpFUXe| zS+rbKMwRIg7276_?}IX_Gkw$UQd@vz99OFe`%B>~q8+qCO~|yzMe0P*g&xr@t)fq= zCQ;+ea5Z#GkoVoo!>7V3+#z*6vnYnxKhPEfRcJ-=7(DFn z|IbeGj-#CT*;mmbU#&1Q$fkMzi25;Ay|40eH>@73TDPrJCVUFnNX1ofMo29KYrwbA zOYW5YYC^$rtapS|e+bDnqHtIS?-0UQWI(n5a3|~RIDkH~+_+r8I!Ekxro2|A{ffmD z5XM|n&c)G|eupPsiZf&pP+Rfxb;7231bjv~!cK!%5HrUEA1iq!%e(OVNCPT0ZxOj% zt%}1s3sH~of=$A+k+3JOlnc;h)&>69d+BP>?&D~sr&m)eCdMO|UNg9o(p31m5|NiQSNeck(c zJ5=@8tI!^n4Uz(YZ0FDLkj^KyXT+;NfA6Cj+BqsR`_vjfd-qYD?HxBU>BmjY)ECzk zo4o7W*8Ewvmuh4pob%+M!QBSa?oSiQr{cwAcz8ia=Js*BdE5uOtQqG>hULykQQ2I^ zb+1=qzFgp{X6}9Zl7w-P+bn9lHb`&nm(O>5brWw!^2G+GeF=ZnMcqbm+~n>V-~F;m zcuc~W>g!Xd=B&F3T+lEV`d2PU%9!e=S6d4QSe>rhsf{r}i=sPoF~`lQd*s*$Befm` zPU%AZML16}CFG!h7b)PB9DbiLygpmp#zuWIK0mQqKRES)VB*^{v2BDG?vq)2rYZbe zyRMqOXk5yf-Rm3b7{|njno-ZlWhfZe2I>)J%wladjDkn1B$>TE1C*ri zsRyGf!6eHs7KEOHM=%VS7z+n~Ia*x$uYoMd`q3y=oZ>jKfGWTD_2sKIwW0cpqPFNM zuk?jXBSlqnmB-8sFUtj~%9FexnSL$!PlM&m!rZIvejpa^*Ztj>ry(Wz>SIjm1>uyW zgHLaH|A>P5%a&m-ik(x#Gnov168^EA%oT9S9(Rk6O*8NCgIb{_JP7M)g0f0)4o0o z^|Qc;u1I|o5FL|0$XPpsL7CTVmGViBeI5dSVf&IZL&(1SfvIc@ljb`ip!hcDVr)s2 z#^D}bH0EBa1_@;03=-)6dFTrII08*+gAZUv2mz}P{Yrq69eyLUqXX~;|49mGCG+nL z=d@-hs>~$wM|qj`XDEibCbdNAEw+CKz_lhRQj`j6Ye9>%$M;?d+dcYhKwe+Z1;R6Q zqS`JF#sjUw`qmKjo{OVZe(jxF$%zSM^WK+F*D*K49(RscYezwMmiUbpi@*&m{(v(w zM|Mzg_sW3e7*%MxVha~3Zhj;iH!;9&c71BG6!&N9m}1Wi1=91z9<;~Gbk;lF&0>-| z_;=XzM=NcpR!!x|o*x5Utui1zrmY_$jdS-Soo#{F&c|)%$cU);}O!rz{H+Y4|;@IaD-^j4RJ-_W2b$(E+Lu+fN5Zcg9w`_DB3vKKw< zAjbC_D2`$(0Rr}{he|n>sshh=?c7-1Ye#ZK1@f3A!0r;oS#IdS{+*ItGXwZu>3JsY zc{`?(Opb)^E`PcOt(fZFMxl;9^Cmy45Gh2EoFN%dG&T8XEVAvE})-9`(h97uwyJOJb2d*=-elp%l$(U(s__g{xtW(sDHzB7Uf+cYF z?A@;VnFi&w!%F-PO7KWQ{6j~a#r3;Seq!F%9dythJVp{?xDOx9j`9Ne@<{iVvU+S%-a%sFHgTn@2XcG zN}wOFofQK^vg?fJzsubY5PoHC>~q|~&!g71pLV7j;L8pf9@stVX31!dp>y4xp`>no zXe_jF#sT$c!A14~#lLPy)FwPq7kv`Xr%W{bp#8d`^dD=ocy+~$!O#8ptZAJ~9?G(S z(PI#xWb9ZQ-`E-PAry^-O$~$?+elqD>D~*G+w$_$fL%G-pUjl)h3XVf9#SOc@Pq zdc2%9qQKlT+ck<9ad94;Ech&^*_lS@G%B)c^HMDY%JGN#oH7scefiP3GIsANbKu)Zg#R1BoJ zQiGrP`;bxsj!u|@TT{6xhB)0zS>~8Q^W0r%9HF&| zhiq(oAw1IZO2>GL#d$%eVIpd!H>t5b4crZB|6vQL1uCZ_$?DPJ+Bq7oH{d-?aHS2Xt5Q(I-5O z@!QTx?LP;K66ES@o5xo_!=)8#?+t-3*XSFnzIQbZy5E9&*@iOxw+}QCAotL-p$&I; zx$r)rzd3w&_VZ!(%E`ID-;es1u8W&7Ej~B5m;u#Pd%ic6x9Q#^N#i~#6pMpX^$tR& zNU9E9)Poc1uCd%LL!N_1|w)H095By}a|?{#(%iy94j zDmt~=0WqYd#r%yM+l~r8`Wc+%>%xT`kd0L{yr|?Jz)RI{%%t!X;&WwYyH@PJatsTRTwm#UvdMlIwxkD{fJ1u^;kvL8;~6JL{x@(x3nM4@4?h zz-&V|G~ROHk<|zv)PMhR#raBv+{JG`&>=8&=NnjizL9zl?Y|N`ICG*%n6&qwpzDD# z^>BjN_bLUJ<&Ob7f6ZB}6Bsum$_RmFpB`j_$7P)_7(N{kAQ4I#9+Rt3ldW2Tk}CF) zDRur(z>bKr6M^U0z{chHS*E}{sC+jqMfv~_d}un7E#-BjoJc5dGD zZ29`83u?^ycS3YmDt!NjZ9KFN(N z+6i|^6e5P-7EH)(22&=0i5vBZA7XgFi`~CnnVafLNVcK#?;V6qv3Oa|=fXU&M&P5pIam2ZSy7S#PrPkF0t|<HSWhKmE1RuB|sPyKvNKFaz zR_LpD4pEmdgNMkLgK1EulQ|7GUZB&=fj>P|WXLrl1N4aRdcJ9Hx5_;DA8c3Z2Fy4p z!p)!v15cf51>VvS5R3gT(YMKpzKA%SHCqRBRwK=d>Jr5H_`im7%s<;Rbo30f9mR6G4@q6j5=!P#Gw?_tvOY%~-Z+=Z-@xbk z-ouykIYP^8D!KG|Gx)XPnJF1~iD#^ZTm6?h0&8!&U3X(PW9T*d(W4#%ymAi18ky8l zWq3cog3h7@O{R z<{UQ`O!?2C&e7&&_~?J4pxjXj3HQ z(|$|y`Jg;py+pg_2-M-Dshk7fDM%fBehK#}oqzcPt_mgJIyq;@Z;T7e!mlyLb>~pR zO=)XqQL&6@Ds(EH8gU`WBP~`5l55kccOgXAyGi`$Xs!6((YufC=*XX;grDzes33u& z_wz&>t?Mi%<}2bLYvW5Ij+(SZAG#L)2kgUCs5yfghg_N4lEIZ}m0hwPeO?S8?Y|gB zPhU#9nI79<9s~wR@1aV^Vr1O3wI`oi+gq__%&uSq;ht5*xliFn?QQ90P`3Gr&Gr1S zx}sXWFy22iZ?50D-8#ZHybQ_6LK8>hl8#G3)T|k{N%3*E?t4?FP6i%p%yK&j#*v0z z+&o+k?g27QW$$c0l$~$wuK+@NK{MGSs(-$}0vfLHYTx*RziSUW3X+6|3z)l)h~lV) z(@W{n0PMq&VC;WD-Ls#v*bYzQ4N)+@zA*Xi{O11jSPkRUpo7Nj^RIg=5JTPSuKE@T zJOTdA*}`rJ&*gjNtv>NEMCtQnpbG7wxNDHJ4&=Ay@Z;DeflJtaz~G zi!yt$85yE`niTJ6ORXUZ8D-Sw0w>x=zFKRyKk?xG#7^fCy8vMnqr6T99w+4!w3K${JSJH{fQ#Vbp* zJS`1|WZ>GP9mBVL=SPm;D{Gg!U<)=I<@*B zURu$5G96JN4aHBLeTkw_Ki2$36!3A*1xE;fWj59&CYB!=Bl!mhq{iai0o0KqGLrN} z-|0q7R@qaOjr6-ox8`K(h2MTvDHA~E=HQ<+gRaSc{1`4L2eEZO+1746#=aG^Egflt zgRP+H@rI=wTZ*_{Z!7YlDjVBTrH&Ew(3By9kl}c^mF{iFd6?a|IcD3lr)}S)tV)gr zsUl}Vxad1arxyCMO{}pwxzd9CK(8X=MoD(r!I;?hZOU)+Q>86D*#}LJyb(OQZ>{*T zed_{7sv`cj(W^7#QTNV@Ke*a!nTf>CmT3~$hciB~inE@ovZeU1!*a<}spFfZV+?}a z>_o3-(}^*$6DCOKjd9ImGw>2}=fL0rkno&R|02^7ny8OE( zZTX#}VhiSYzUT^!{Cb0?Dk{^a3U&yZ{HNgmOxD1|j;eTU^S?2Qo=-LPp}CaGC(#M; zk>9Nf_?~bG4TnFlMy-8eZP0_>xha_HP1Qj7`qB_tHQm^$cXWeJEs>B7t*2u??$Gc(1tgax7;!>;7JQuUW zb+d!#+V`Zj95zZ;bI84I?TH}9)loAuZhex&ElE^}a&^JW!$Q*926lS7Mf6}`?4dSX zS_8@HLYq(;msRK@qX8^n(&HMoiCtv$JEucX<(1C_>`TshA9tsS$_b$^sTWj@>8QpA=nSzfhUuW~$&;2L zp6>)!vQ2UmmlMOQPCvXi>vzU8IZkcp(dh4 zJn8iaNT#}z`zpZ*nm4O>X3Cp}`pT?bl8frV33ixk_zcbvlxTU+mBPOl3Y~=8gxK8L zZj?+bo~q9L&NBzk!pPzU?Y}6O04Ja&^ZKU0f~@~P5Z(*gs3oy6o5zag@|S_U)*Ap0 z)Em!S@Ky)|UCkLa-0e!ZZ9g_$4FQC}6$u9uDmUOy3()rg9TWys;&VApuMt;REy+4X z-C!M;g0&v>0TYEuaAHUN4KEiNdsXcMbrz_o11@sjo~J6+4OF>?1Xs4NXHPf@ajlUq z0J0p`8<~yuI{o8?VM?nmZ@3-Sv1ivcLXj&Zz0g;5rlVf(#R2~S*bEGjMpz-e%Q-1m zQc2NWYy$`4!;gBUtxWzg7N4v2JyoS*(qsi}8bHYl)cKplZ&{W6uj4ek<8St$heo^> zM#`0Z&vWt_Y4d%q=%zXB6_~!tOZP|dCC2f{W?uNc**t=Ef#?eAHx*OiFLU9)3YQgX zfeRFU4tQ-YMtL*Y4l2R&$;Ob-ReXLdSv6H(wD^Ou6r)@eGw8* z^Sn_1KT6wOcHTjqfCGi})*}b)E-f~~f$9|Aru$y<(J4|zE=l&NfzTN70Wwesb&rSd zv!3f({-5oVe-mlv{lXP+Tsuclz@cL=D$Ih^6_}H)cR+ZdKbh&vjtVM zHbavwEXLUhK?weANK%&(1D!n82H9b)JN7~FuE%eOx6E!1UlD4SxT6D}Q5hBGU%LZ- zZ3bQ_cuDDpAoO_i(1s0jc@hgGQZO(5;*gH7Dr?`T`{)ml{KTBFMXFdT*i?Dh(`Tt6 z+$4m>vVwQwOk5o5Rr}^Uicu94sy%7L9kf#5|EL>9{VF?_O`;#T6R z0npo^4aS3(#tFSM9CG3|<&J8dXw5#r$sTaUZczo5O|(nnoS^h~{W^lbsEryB-d~9Y zr6300!>Z^2aUwoJTD!oA@F`AoCKuv0$J(w^R#ofXwaEbIR%-r+?*x`Cwyh~@;|Dj) zWKZ$zPsN5d&e(PStDT#4~ms7*q$$fF}dCO$D!n>+$Y-R zlp>>^Ue?5fezuS9tU6O6-taMD>`77I~1JhGSM(OJ72#p{Kau+24~^LUZ4k z=3`aIifKPKz%5&`wkFx~O^RO@ZP$p5l^~Iwn$lMf?~>7OhL~a`EY&J@$Y_i4bm)uymzK^FEj`ziS zfG-O`+nu{P7i$#b-6|Z5VXsm1Z;xBX%d;*LaZ@f70yj8F8&B;v(&e&3r>nmwMH*6u zS-2T)@-^Ol`rwLsMC?SEmM7(M+_Pc%5rAmVLX4V`sr0Yx>;xD#f`T-i8vC zwLGD>158q=@fd=9G3G>w-jkV##6^uoSx#itMmh}x&vmQ{9`zw}gFYt@$)#9P>!4xs zsWjWk5m!L1j}K6iXT=B))+-2{50V~_`ScRC|))5qa{P$mxu9M90ENeuV zX3ZAv@j!fMzWTtne#z65J>u??+Y2y8=2RJZc9`+i{G7N{DF(^ha8!;Rwo)su+mj}h zKnV&4kL1Cvoszo;d*%^RWB=3x)n2$ec`XzhfamqvwMYb7?hB6{*0ptGO;p0h!HL&~ zvc)%;T&>VM(*HSXQa3Ts7+wcq%wuH+VT|u*9BG*kYw~zq?bJY0ZMU2p)fn>)IY1{S zbaP!;_yWXbhN#*zkSUIO0<;6np)Vj>Js;EHod6}Gl>cnS7uv%uC#Y0+$9hj33z;VX z$2?>TzSx8A5WvbZj!EnY{{}p>L_~l0!qe^=Q*-n-6U-t0Dj!RXbA3_NlQC*S(lVDlJuOjX<^%roU%Oh>Fl`fqvrA8qHfF!xiMGcXs`UfErUqYG6eXq1aWiFL$yMoW7nMLt_qR^lggjq)Nz*B2UHzmB1jW{M-MP`7*_T2k&FO1{(-8OYAA9^`C8b8y z>XRMRKsY_FJwc|o`oWip;(MPKNd9W)T(rk6xH(}9lKeY3noAkb=5lB_V*72U#r(Qu zOJ8SzVPpS>d#Ly0s(sowfJ*jaE;*9nh*bx{;V3>!%O)2i!RoI zI>#1lj@R1A<0l5_&8S_z_M$xu$mWJE#Nza~1qHieN(v!Nx9nC9wj0Ub7r7B@J)A=G z>-cW{+5*(JOiGUB_ZWr#wk2UfoLQLt0T8cc41F;?2m@_@%eS~~LlH)|l~QUVmB#1r zzyOb@3d6OgA~xiz6j{d%P=r|6&GBSw!*N2syIy7?E(OWan{{93!4(0%wOrLChxp0C zBXCK)7>&C#OrUt^CBW6vfhhy`Ej+3+u{S$J7431kAkc#+ea$}fQQSZ{uM6vu{r%dk zpg*h!489RlK1xlcssd&mwN)tX*S?|1H{MKeoSvA2Z3RI(&axN94_70jFmH{V*r7b! zulCv;uyE(llR$O$-3xv*yFQbUI}?Os&Zd7>oF7BxS(_e*@H`3C@IU4p?!deXOybZ_ z*)BW)ctf4{o_uKr`U~Fi8Sy$#waMX+sM@pAll`F{%FYDCG^HA=`5{-jJrd=#Oh8U5 zii9*4Y1|i@)b#|#jHRy=+5S@&by~kMx_qzw6FX>c20}-t9bTgykp&w{hg>jDs5j(? z&qgso<3#HO=kPK7q4;8um+;Epw2k&@9AA1rn6C(4x2dj-C-7}xNE;m1pj@5o=B4{& zQopECc1(3c&Z>$hHcp*09^dC0d@jP@2n}1^bR{B!Mc;cdI@N0*iV<#il3pdj$j-I< zH-Z&p@ojs8u0utu4KiVPGZRw}0U;-KYMdDR7V&DnHsQ2JYy+b6oxm=6(7i#yjEA-g zC42)fM+U|k*d7VHaR~9#x#P);_ke#YRT4yE* z$8XXG(2%|O^JoR@(YH1bz4;QW&I;%i3y2Ve$G}X<>75h~-!Dt>SwOrj51*!%6u=r! zbOkh~q_8LUg_@aQf@QA#vAES~>ioQemlrin4KpYvMnYTI>A0POK;Bm6X`A zZub0F)+c}3Rk%k$CL-}^-@nA#3hn5YQiGph$n}mqyx_3k3$smwl04phW?m=AQ~8%V ze*v^W@1>@wv-tMl^&s9>+PzBR`UFU^SfXd&nU2zxG5p3Eq_Ki-yLUMB>#Rc&&xwN? zj*KMMa3sF`6eHXH{_s#hUNeRldJ;UH;Gf2!<-a^m+`1)r6m`6>HJ$wHNn(dY!O!k< zbF)86PA}ZQv(!%emevX7AjPXK-a!T0jTLAQ$@B+4bF&0@@~fWT z0@l#0?^$ap9$ZFI(8Zac_}9G77WCmUd-m|0MU!9%{92pUN^=+sWh^=*FY`L2s&MQX zLFvyv*3s*cFSg$1*CoHgS)}Gp3;YU98me5bm-()=3|QdL$Av~Sfn5QnSP(9w*CUwm zv_MfugRi^uff4hB6cY#a$DmGbzc#d#ItW+S#McX2C)5lfrFb2v5`pz0Ywo6Vku3I0 zKXv5nGR*9buB}`a1+68qjK2=VMbwTOFH(&01>@Sg=QG;=q){UXN$P$CzD@DHtIP7a zO({R-+*jSdUul8W3;7NKQQ&fE!c!(&OD#$P{QlTYvojv~oq;kE?azKd6l3Pt@OKxk zC(J5b2D}jFcrsSl{MY4rPjACQ;kx@nmJ?~vwsa+HJO$DO`!2U;#SlTO6a4Z?n`f&G z6;9sv>+`BxNdF3JZcR*A3IyzIO0?&RibWCc_*bV#A_f*}`_i5!jU$np_;l~bar=eWDkzuSC%sJ-Xs#nyU!S<6A{jMTlqmA0Z5{!roAVFbz* zb9eU*=4_6?4|=&q&Hbw4b~r(5>lsTeV50A3MRm=<-~yP(f^moU%_9D@KcTCfm!v9L z1D9Z##8U5??k>vX|AQ=ihZ;hNt8WIq$9jXQ0)=@zE#+AsH_x z%*1x6LYb=;uE2@rJSV;-E&)CH)8WkdDUm!E_f3Ip!#@VvD{hvLE@hDFOgQPcgpDRg zoSN=-gK<7X#-?C6r4Z(X=HlaHl_c-I2|u?<=D8zD3Sh< zB(gyZuac{?Lh>tT=Nve8Wqc3eDMo73$lP0pm)@RVyRR-<_x<^%XnXMsBkC5p0B>Pd z)nCFLryuu~{OcO3oa0c%%`0E%$tyqG16C!fvooHth}wrHy$4H{k~4o=+#Ds}PA*av^rbE9Ob*-G? z8sUssJ;UD92L?;Ro%nl0j>AA$?I=}AmW)B3cis4wJvEW^*Ma96zjRf1zFctamph7rS#6 zrrm0i31-w-IZVrTP?wNCdPB0_6gw;{iido5i6QEpTaNdiK;wm)dL}qqS*_cx?fy!s z`D~!!BP)AKx?r4N5qj>iB10>*JGl;dW+i`j*CdmmIyj*=#cI1_8wfvw{e*)W0dAe=;4ep;>x}bn7LxguRF*$J+8CFh$`1(cjOiIH^w!{iR(+6* z80n^(y?F~x;H!FR{7eO2-0*>euH~n5n=A0|EkyhY0_#E$qCnZ=wO>~F2ugch+Ha;V zx&?+fCS8%`CTIG!epH;bH-NUl?#A$?_UJ8+zbUy%`4Aurdcw%du+(sfjkUJ!ubl(X z!yz4Kp1m`3?~4we_2Hh?EZ92n%?J8HGR{fnuLdg0{_f=*DNyvLkvSF|4cK~9$q%r- zMn!2xg$X-6vEzV%4O)AmU=iglODUN4(>p4ls*FUHj7yTg(qn&JVEKZ>)&tz=Y11X> z(7yeD0N>$s%nTBfr_<5m-(24!UV^4iwNnvlz*ryPaUoR&tgrBsTN8TcTDT$u&87@yv#WtApMF~c>a2Z#?!(UFI@L$pRhy0|yB(n1nok)uSZ zb;iu2GPTkBDdF3gKod@)f^rU@>&G(ZyCbOFDjAq_7cwX|hMx*y4nn`cYXY*MR-^+z z7%~Z4_tXdns2R1?Ul1u8 z#Va2Dca-P2&6c`gTBp^@$ryX`#puJU^K01^=}7aw(XSblQ(C^h<_%x;ZFRJJ=24Ss zl=4crZG%bRnSRHrlew$#GlisKuet*(xBLIdk@|i~G7UuX3pksP6eQ5RNQ9~LAgfpA z-~Iz@$Y_nzm+H=u+WFu^3w%q5)WZIAa{vR|3A9lJ1M_;M+>p-7xq!b9w&tS-AJPrU zkY=1l&jndMddut1O~jXeXVUnB;JZ1nLhkp;saVJgHzKtk-M~2d-Uy{mAphZB()Ip} z*;2`7NrA|J+vi|Id4H6@?!Z5;{TF8o_>q%x=-ffq_YKr@gv*_zXGy!7GO|a?KO!7A zKlimDUs1O~Nn`mH8@+E?Ndf5wnD6j!G|Nor?am8#_`bq-Gxk%qqE$9tsr7dkO!?b_ z!t-W%*>rcv-!l)h{}-V$OH;pN%nQ_E00mzWeit|=!6S=;Mg35)=;K`QkkSYr9Z@LE z8n~;Ycmx3WmbNmk*s;PEVQdaSmlsm=HVMhS*?ceLRiQ<(NEftQ$Y%v#Ds)ux`uU#b zP0{06YQ6Uw+gCTJ0G@ZGC9C^n#34r-gw}$oG`tW*hpQF*sj&#UD_&o|Le`sl(heOZ zTFT{Y^jL3;+W5t7$=z!9WOqySe*@Wl(J{_NPgQ#(M9DNKPXs?^4oHz~5k75YLR5b& z2QL6zXh^rPr`0`PN+m(#~7-J8TgHjAZ@Nw3wr)~Wa zhbESaK^*OqJlJ0Acd?VNrr7dmjObFE@=Y?8d5j#%n^GE)dAHI+tk-g(@oO<2={hyk z%$7!HI2v-OiDYXBik@6HD=PJAU>}$ipzG1mHy7r2F`7tt#m;#$_duWG1Q^tuJC__G z7#$;N#i9Rc2b^dvatt;HoezhP9ebod%i`El0rtIg<%AT`6!SZ->1i4#;v88o^W@6vd}V%}y*I8k$FZml<4rc~I2Pn#+LMTsW_b74Y~UwH z4!rdi`4cG4K6@V6+}ltVO2lawC@tv~NhBR2L-elVzHC-^F2wXoowe_MHFx9SEF{;u z_54s7ERq#y0~jJ4u2 zhrYYL;F3e}LH4~ici$+GnfNe#=B?w>!WZq@S3tsoKJcX@sS#57$eG3~} zGN6?UkjtiR@i+PxJ$eLkQp!4iMikm&6uFek_Jgf6za0RXdxz@eW~>KWKT3PICTV~J z81BC(uyHLk7cSM-C4=Nyo52Hj{LqPS0v|BuDq0r3WvSz1n)E5@j@J->-Um$&(oQY3 z<&oMI7s6#vO1b*hX1SDM^!i?cI_%)7)ga%o&LA(fSuBh!ZhAPWO=1}?Tx$wK?8Se5 zqm5kq?><)UV}e^5rt!{tH?sBibC{5$>Z_IsU7x*pw(uC}%38+&`&aPHoT{jmt(VSW zK5vjNes4>pMcB^@6UD_Wb?y0|fZ~}Pz-V*p?2i zd^1D+(I*2UT|+^P5zzY^(aZ~Sxb_gjXZ!4k*W5ZGeA`V?n#_^>!j1jqB6CGGvXI9- zfT^W;{OH}E-|%4#_765_y@^zFMiAK2p{lqt5Dt^$+q1q#x_u2+ z+;>WPxofBO>X=T3yNg;Gv zP}}?=^zcs|hKEilm>+-3n&3=)-> z_T~R^aIQOr8u*z5q2=#42gCu5_;+?_s65iZKvDcbA7W?{4vRs?DgBN=U(tQYINdfE z^4Qa%Uk!8E$G#PrRQ{L=+2jUNZeGy_@`2zKMdgJTw84`RH|Iiz-5eIxFf`Es4Z)$e z8&YaCk(V>m;*uXhx7Ew}$WDg;EVQ{p@h7C$8Cb~@S6cSTEOfcJV}ZQ9MJ!e(SgT)K zL_oDKtRAFc10fk}8h1B^GS&rN87j{!6StWaw!x}GqPlc9sNn1{2svl>|);duMpdS zqf>XA^+W56KRaxE&jyA>OVd8?NY@{5_ej**)Cw}HLQ0tlS7+S~?W?7lwY9}-#zLM` z91y&~B;?`%D$F9s3ZzV!g0*o50%G)47|(Z8AAw}+FY2PId>8UgfVT(^y-k8RZC8g< z6{^hcTC>gMi#&g%m$Qx-vLf*Q&}9 zyRB!3-f4whYjL%?F~s5@4Vkp3pyPsZM!Cshp=hr?uhRT8FH13TlBeRp(}+OAejb_O z(6zz8+}f$Q)#uK9%;R-erKVMqe#MHuVEdVOuDtf(#J~&tXa|e^w95LZzx#OHS`X$P zXqX4#?#@`45&1W}R%Qbqk$llAdaY`bOdRJO0e9I20JoB5$WjS;+|3y%iw`;{t`qU& z$zeG(r-rB-Qv~aa=-m_Fqn;1xuk%dtOQzX0Md=TPB|B4^qm|-5c#FckoGGO$wD<9~RlwS{qCN!Ps553y9IJ}J+6@~=mBt052c?Zs zZv9JGG)3gkCh(g||IWgEiGH`+^2t-g1ohN<3PPM5Sk1GoJf?;aM({L3L4=>g+H7mq}ss# zje=(3bg(TiS{=zXI@QX$GNM0ajig;TqP^TOOD75>CGnEQ;3qge6lP=vu2hAgx+v#? zFzjuhMfcBtV|^Uqoe}7yK1)shQs|2AwIN4tQvi|yl-Gssz7A)pBF`3p)d5*Xzd-FU z(7+zVK@XWz0~(_MZyO44K!53Q>b`B*3iFm8ld9}(s80wRAN&Y`XeR({T>-&F;iaL=YP8wpe zq%v2Bc*YA(+ z7|%S{_6>Th^EscU4Il}u46f0lx4(HFN7<1ID{{SKeMBm+|TnxLY{ zwKvt!M;~jm<^OfVK5nvs zURXV9F!L>&HwrU%0wsKF8WLTIbW9Om_cRcAJs(f=Q#KM z;nzvQMsLTD?mYVGLi-Lxf@JW>k*0W+3QyPi-y&~h`GYA6&f`f_Nx>uJ+X@0AUSlM?L!$gcVfjHH z&vQ1%>soXg7DrH}E?kpLm6Trf(DG4&c+L8oImZ#S7{)frgN~bxxmn zr%L~*mp@F$wtqEyXV~Y8AD)q$z^xKA#z|VkN{r7d zv+vg--h?+&%<%og+A(%qE?mID$6J9^k%J$X_TTl{DzCdc$ys}^TH;mNSNRDX$~G-C zQ4js#z8tDw)VyXmHCrG0%tdK=(W4ihd(F1U8%j<;-?uWPa>84ySc#$KrDbt}A(rdB$>xp&`vUv5 z zCb_MYj3-&>7fRq)?Ie=QC#^(k4eS>enGe(HN0xC~GhESX)MpS@ulP~0T`7O zsYS+B%*ssIe80H$&SvUDim-1M`aax+s2!-l^dnOGQ(Q>D!;JbIEB!5EN8M|$&SVUJ z2-3$0h|vATW`BrVpF-|z_!I8D(YR4F{|J(NuM=xmX22f^DZAZkSMn_sQY9^|vZRZo z@Bzq|4$g(C4T@|2LaI%1ZIT;Lk=`IeG5~lir2@nskcvoi8FvD~k3$o+1r$Nh94Vnz zQ~XG*x`&9QK~IOXDMQf$<-6#6Bxw}UvydwyS$xr2y$Kiov(XwO?{keVjS zrhJQ@VModS>JA?f^!zHm-AlN3S8b{yQ_(x>+h!os^p57c{CCG4drLiLaU0ur6kOMA%dD`E{IbyC!?J@&p`@VJp@n_Z z9N5p2kL5c0@T-@&X5C`AJ!?0ng=>^;zt6^A@PstE8RBJ;dh2ExL|uK2R05aM%Y+mH z*JL~de@@4y2T5!N70Gd@vJl0_2F2YM!X^e`mX5YM*5GD^gA`wWG7sRM-~25+naNbS z9O3mXwq2aC7)l<}0G0jB3WlyH&X~r)bV>3@WNAEg12@A{5s|!XgOK|iF3LGy<|YRc zp5O)YD-U+D^gC7L;3Y~E3B=JcE;QkCa{{=ru=IjQ0NHGw66guZ(J>z@gvD=z`k-8B z*~k%taH+`4O6QvsQ`2FxivyaB^aqt>iCIb}p@*~V3;D(r<&8&; z$~>lrCj9I+p~dIbZKYJ3OTRnvVQ0&N8N!NQ!Lh)zw*40IR_rrcZ zc7zZ;8PAhVusk)}E||G4x0(jgj}hR}^k6(xYFH#;4$3L<4;m|{x%M@Z-y>t9y^tH4 zRf|96e6@;$&{DxFEos$Oi zV|$c`C;WtQEzc-1C(wLKGUFoPISo^xkX^o*lrZ&xZef*eX#$={hUGf1n+}_llOOL` zqoMpi;q)P6mxf^*)!km5WLjIC9FJ~~8wBRkQxUY%XDmKIcs=SK4 zr50Rp25|ARZY5Cm$jf=imbdYixy$>>&=)^Nf{OBx3A+dT`AWEvc{S_+hpw2T2J+l69&G=Df{B+nn)t$93AGHYBzZN!uNBJXuppG{xs zkSfST3)ykgCv5DLWdFEcttz+^xa!z=n!hoCS4Y!g&50MPb2KlW$LUYB_fh{(D(%V! zD}&-wz%sUxW&ur>ZFa#8*o96p8BSCvNexxu(#wC zeT%2U%17AC-^KpMaU(DgO0(H8g=a%VM@jyJ#XQ zVBmEM;}+o{BA~!->$mBvWbx1EDYDn>iJfd~O2{$@GQ5#_A#!sBQ`x;kuX-kCLLybt zjHBmC9oOUBX1}d2X$W9f6^<_FCt2kck)q_YR#%p1zXp6LZdP1|q;xWOBxu<|5U|UL z9?6_V9x(Th<@B;>xz}ucn`y|tBmWHWnu3dUpZ1NG3;mQdGAU=MISsPw3RD6oyZ6ya zRvZ7Vk0+PAW|}p;`cwKh*1e-8xf%HVlOz4)6Cb>)i72p{MMo$8QgpqxS)`>@^nSGJ z6<9ezUKh7+TYe9zJ00egmb+n=A-MbJx>7N;h-m!xet+VxxCl*wG?r-&gMg238~WYv z_*B>v+thvj&FdqD?fToog^SC~Wz}=0g3fUhI<(ipUE5>x@KQ_F1Y}(IfER~mDs>PLv@Aj0w6vr@*_sK%C+0@_>!c2}&n|nq zE;16_GjA&u?U=oo_7!U6U&ZD=U{VnWKaZR5J&9whdw>O&^mj+MF&u!rvhs}fB9isB~Qs-{WCwq z%>JPF4{c$yoQ<01546gK5R&yd`ls5}@{lz0-@ND8KmA_q$v0JiOusk$H!E5By#+CD zldZEYH~-xKX0#*Y&zcRjiIK49vR_-^r(U>)fo#j?=8>rp2>wq5NdNlg%&*Ow z7_B>BH!55&@{Z-RiRT&JAo+vZa}ZPf!|#C+y;bYBybw~<*hbC6F#L7O4dt3gL=3^V zkHbVV`DTdv3UhR83{1_YH&dB!r8)!aL55Z~rAzcd=S5zj zK1%G8cvD;1V!C$}CwJ!*+uj2goz|PH-Kq~8^?ne;Wg=yEqfv6jS{`%k^4xbP5s;)$ zRcOdILKlk3h9I4SQy0C6V^3o!ZFHBILcpIPf0mqxf#GB(m2cUc9G~EV>m*kXTK2^h zPmAL}aCObA|E0+JqY6)%kPtZ3%L3sTA9|ITFb0|-#RG6f3`@0mQ&nTi1wtx8a9Z}X zYEacZR-!1|fRS0aSavOxPEOYs^uP3T5iGF!sTrl!{Im5v9pqB`87o*1d`qs@&~a5d zX~~RtzDANi^QI(HpT1^;MIZH&!^B$NJ z$*lXu*d7^~{c8a#zZ!N9OC#eoM*p_tWJY3B`7*|00zZng=X0st@!w)xRXwEeL6AA4 zXQ)R%zm&cG$#`FpLmD!pGaga7vL^vTvy;2^VB`fAM5z_Mfn4`;A zV#Jp*T^9vT)kc^5?h#*XE3$9S{X&nlCs-0L-#RJp6LEAx_m!-UWfHTNPu6!-Kj@)E z45iWKr$>bAcw~^y|()m-TkuO45%wHKH3+UX)QUub(C*J}r^$9?>=; zA>sg~u3BwTY?b`<^YYZ67D{gQ{#GG{u4eidBR0X`rjn$@`KV&m{eSydh;T_0p(VM& z&WcYb<>js>!fNs`eFB};oFIDJT3pu^Ep3fcM@o4yxw-_GxE*Ke5(+KgG(NFAqss()@9>G6_P@Xti=;tduQ+lA3MlF z$FKJ37Ck9K-$`Qn$?7l@p!^cjDL+jticObCq~2zQ(~mTm*u$$;yS~h7?2#*a5zb}? z2h-n0&aaf8@aLs(;Nzr_8?NRt^EaY3&qjDjtu!}oyto#-sZa+F<+s$?@O)_oE7jHj zA!M>CS@r~KVS1%KM5`kiqH;0c8l_idxbFBRuQY3{mWb~0j!|QO1AC`8F9|AECN5Wkf9Mg`XPHQ?BrzGd-=Jc5GzcmGhYFN{@6z zM$rNd#;+)&2uf(f*VcWgNK|5M%FC%n7!@{YYs217b9X(uk=p)lG(+)Y6{FLqIbX{ilc*Uy>qZv_eEe4S|pi?@dS+IOpF6EYNA5PFAp^lGLwgu zdeL=t)}<)khDh@*v)CDL1hNsE+hd{axy5)U-=@Tr$aMtcS@*sImusUT|A?H;&+m%P z@ScV&Tug!R+tzUlj7Q|<}`kXRvJQj7tPz`f+B=?k3xu_g@MTQbE$6w zmo=HcG;)}$H+_W;;U`vQwwMc5M$oc*afP*yKrFS6Zt z5`xJz$oGs%G@v-uUKiUL3Mi;$Cs%_W- zPD&6=V`eY|rq~{}OSN~PT}7i2%kC4@|=u5Xv+Bg?vUzf>GhTF z1bd8tfqJH_*aPd*u7~!rsdyUm0|JnwhpKx~zp-o}#5kfvqsIpW>NnkDC zkkJ%VM(sPT1~W!7pfCYpRlc*Mf1-w$waxU`^y;L@zr=VcZ5r(ISc0&5a29V!p^lk8 zZ(@YEV>f8|t2)`eI40)e;{kWXJaV)FKhX~agC%1K)C59~hMg$)~PF6Q#h*A&LEyA9yjxKBYGmMePha?SP z>Xze>xQRNoAkjr0TQ{BLt<_w5(Iq0k|CH@}2cZbl3>7Sa%gknBs)P;RJcn9Gk^54Z z+hq=X_q5^ae|PA2u5^R=ZoyLe^*jI#&&5og&WJbwb5YzLf>KpKJFiXR@H(MEiF@K!D4-;J-U>KPsrSM@6-~>%zDr#d+0LR?Zx#&HwdUdy40C! zKHg#gd(f6athPR-tz zD||wI2DcD6M89;Zamp9n-K=rMobZG;7N&Y%F{a^=X62K1yC<*8YOhK>$`fPd}2j27SBVvaW2ivpYYn$meux&Ul~9# zOvH5Gm3%$D6IyCgjRypKVAF=j`H5R;?bZB#3#Id{VaB$ONbL$suj@mP*_*QcZNhdJ zd6v9?S#7SP$RQ;A0pY%>trq@?M>*8FBN1%&L(~RktDCss{4? zhVJ}KSk~WE!rZ0u^ z30$CG>BuW9TD_amL~Z@kc{0I1oXI@-$T=KR(E^0UI%1q%ZI3=?(oT^MT~hGsR9C8h zQy#`-+BJYfiixe2sTqe!h_oqsKaz(X$>ROV+7tm3K1sU1h%W5RGq3!8^yg4xaC^iV+b|iokBi;U-L-6fnJco(c4 zNK-;)&9z}O1`qLVc)bAiBb4>w$mbwC2M9Q;3pE_X{2y*#7jkd=J9pu4NMoNN@Q#a>9ofFK&T%DM(_b1H zU~DO_u#3U6H2(24Z1Rh(v$AH#wAL&67bZe#dt|abVMJu)ZU03TP! zF$zi=%JWZSjgDSz7R_Ro%AM}3xPEScSzP>${{6B`5ze58!CHcg>|(IGyKY6GU6izc zD~06DO%*g8f>HXVEi0a2+FO86l~@Iq=0oxF2?0xKozibNIxf#UC(+B5u{K9Je}RY! z@0%svO6MW>29kGgw@0E)x5)b`!u=jwUB~zxWpz98+vPO4JQ+WVc@<+mE&aGm$Fc`j zFX6(L^x*g-wJff}DOA@Ih~{0BM2kee_)|@G*@Xuk1hqA;6&FkYSsx*To{*!&5C?Cw zRS!y)i8V6$P$IjXZdGLy#%Q40P8N$^$W+GqDn1|9cQKOX9H~yB65?Ho>RvjvD51L{UqoTDzB^ll@Qp?_Q)gTwm15DYPmll(96ajb6_-|7q9B4N56Mc zR;9?^mkYXSv&S~pHr}eV?x4Mx6ir^hA>QvF+_^r;=fL$~%B9sl64to#ng_iNwxD?Z z63Fl#8=H5W?78$4Jv2 zHPaAHHXw;x%a)KX&4tpp_r3r2DVh28Ta6L3eiKX-kolK>TFNy()jG38?eBAY43JQ1 z5ebEJ?Sc)S%VNTCb&0w#C0$mg(*&O&?*LTv#R@G38R| z0Ck@-9!OvR2HSX&=`kbSkd{!OF#1M)dJV6)m-`Yvu%1b^*re~5gr zPCQg0z+$^kWl-q(?_jk-6=%4jR3}>O>~b*kUso&A(2u;ZYw{4kQ4k3M7M=E-yKD*X!dMNO|xNkwriS*Gzrs*YMFJs$!_14FS;Xck|TPC;18Xioy48gCJs!n&$p)PTpcT7TXN{|pO)7KTF$T$v!X1e3!+Ha!YPp`Pg_gJr0Q#-|dVC~D=h zHwarJ?Z0b{9$+ubk8v1{-Q`+)eOle2d;-Bos?aQfY|$3Z4VIcvfUL~=fM+Ef%7Ax^pYu}O|b5zcUGUwQcskM@DdYh6u&wH zv3laeQ%E_>M9QGKCg>}30Lkiq#ik?tWo)u*?OQNdQuheUW(~cN!Ww0v&nSXQV2d$B zvS=t-D&mUR!KaIwy#AkF_9hb&R!K6zF-VqCbyK8i9@^px%yaHWGxeFwokA<4VPD!c zd4cGd2>?&ATdx0sh0VKcm8{J&^~Y?HlJUYw``eL`*RVkr-M329m+x_}idzP+!!l&eKvR`O+VWJ%G54xFy>y189p?;fxODbx^e78 zicyM7z<3z#hhwD;?VKMoz=J|frQ2m$mPj?(m8V*Mga5?Nc8cGe3M=Zyg%P#M3d}bi z+Qy1dem+|wg|*2leg!4Gz*?f^h_!oi5eF2a*Y1pGDc~~1_C;Sloml&JQuwXnaDB%S z-r|_cKlE)6SSNSri+dpDT?(W@KVn@Hb0Zf{2?tnB^~G;(|MiwN`inrfw$k|_w~ixq zg^^h3^fWYKm!b$Rg)pViu(A3AU>wdL;%t*)TtCDY$HMG8#YeK6Kx5s!uHU)Oef^-= zrXt9KLr(yNV*~_pzcPFsCj&-5mkWrOQRM`}1bp&Hq2vp6A&4xh%3~A&*qbzcXoN7wo?X2MlLZE`}tBFju z72d0$(A6|DlI~q%lAHrpUj*e5#Sqev6F!Z{vyXh~cx0-879syVNU8Uzu@(P$xVqXo z7Es@G&l<;3jDq*##Q38ZmYmZIYX`DwG52Y#MC`{no!7mGdDFHo&Onw!wlvQpyo9}8 z$SF=((VTE}JU&8lcAUlNPE}teaabja{F;^IL$jG|YhUZy!b!svG!YO*3eyT`*729% zd4Y3!$9T1jn7)yefNY^H1@c;-NZs2!>Syx|m-uVtr}A9lS>B#vcZT^Fe>33o;j&Vl z2u*W>F|A%6+wj<=w;P+yW|G{2l{at)Zw$(B*P6F)V21ug)b~S2Lyvw3os7^g?IPbM zLXTgoc3ZC$ae9{_Yff-lwE_C)>q|LRFfKPA6IVGUL?%OBuLEyAHKth=n0X3+WBY9< z>3}Z9%HMZ~ECA`*MIgd)SoRG$Y?{(bf=@8P<-&9`!l!o`;@g8CVZHOtbn}tD;D*UytfLQSn^Kz=xyjc+W=Me<@ZycohU$H zx0BPb_^+i$4P+@bogQ$8co(f}?y^1+s?#sxJAn}0mA^yR`ZO+hHZ&=|w)vd}e)7lH$d8-mNByy{`_+MD(+fAR^xrz;EzsSJdu3serjfn^ z+9VWXSZ zoO`>-FJB}q-W?+;$y=@g*(1CwbX}<>jSTc(>$2zPt**dT@*wbH&t0wBW_<|73kY#I z_^Sq?YY(9A?QH29+1M&SVRSsqi>SB0mSkDBZ&7Wz?WU3&eYQUB+MUg{$>prnuWt$# z`r3DUuBF3lmha!@fp^_oact}$*TooRAmm}X6mY#RIlLVF1^EagPa55^dqW1`w)s60<7LR1RKa=)ahF;ni+xMjsEJ{P zCDjZ&N?8Ay_uE8xt<#O+3u!akz75ZfMmdNh#EV-O1QgD2EcXOLY{LlH#Lt-(zk!aO z-&64$p~bsLqy!YqI3NiRJ?51mtDO0EC%s-U1kwHToCcV`W!IG1u1o5M`n$H>@mW_& zgVim2}a(n4%NMRp$L7VZ&;E z1K32u9xmr<2v(gXx%^&5_{*WNMW}v^7T`X-f3vM4T^tl4)eIw^wM{?o3!Fyim6uFO zsb|A858#{eN4S3@-M4vex5g&YpZ&j~3#*r!u)rU$mk@PV;J!}Oe?P-LjQlPf1!$)( zpeR30lyP&1u~$FLuvETh#)xt*cafJIxT06z=l5wv);KL*@$W#vi zJj>-W5C9IgHctPFIg^;Nphtjo_rZFE*Ga4cq79df&;x+NfuE(j)v4L97~`aj6kUQ! zQpPhqDB&5h-Ut`HqWa?;?pGq?&5|8>k#Gd-iii)usL8<6NJU}3A+#+rafv^8XzOg)b`HoyMU1XEe6MNhDNcKvTJ+h9=yv+d?N<$>Os9SpY@3SyrUIgy2rfAF59JUR(`ms4_!8O`% zPdTnMtx0{9uJ}nRreB!glvtmHkFYM<*O?Hkq$J=S$&mjsc31?ST_@V`uTgT2Xv1}+ zwADsR+3;oPQI*X22-HQM@PqNUa(l51J49_!Kgs1{v;r6 zV?x`YJN!TO`Lw~Z1xE5tOwuy41$1ueR+4zo*}OryIF}CYk=G$qyMPs1|Jq<;@IDqo zN8N!x^OCbe_oVCYOq2?^0Tlxd0tzvz_|Mc}t{Z@QhBSd=je(g#?VaTJqGOkh%xI!d z$JQM6Ish6}_xf{%YxXMzD^p|cuw8Cj+O0L25P#|Ldkd@0o5aA%M1RsdqqF2~V$L;t zKk8q77*Yff6Et^-purRV+-s5!IuF;lbldW<#7R53d|SnRNdP*(+bmf!BS`!WPjQ~unM{7 z3bxC{##(xELLxIjCgxcq>dP;=xW=KoMQ(59r|%X?r^*9-#&519$Xa?~b)$TA^X~@2 zkMU+H0TIKGzvN6BEtR&7fU8Gj-&A+0E4gWU~VChbyW*kX|m2wfV1_QeY*-%z>A!es7Hx&d@daz17%dsKj_4v-><(Z{N?8 z07F~Uhg-S4xcTlIQXv#lB4@#Rw%79Prc%+35)D=npT0}nvH!o)xX-<}00tqy^7gHY zuM5mT-MevU*}6OSalL1u6rFx5lF>-`lxW)vb|2^j+zRFTArWp3UvJEGL~zFaUtN^! zB90nw_|%r$iQY?S@V8P;yh#~DkGxKJm30wbg0p%x%xE0R+c75@&PcHac~|uF3qKd&WwfjV{%znX1Q@Vr-YSU|9Lt>YsCW9LA80r zuFHN#=SL#5;JnV=r%YtFbMRLpK8)ZtBsdh`AZ%sp=87)GPkhi=tAfL_=qsy4o5W#< zPPACTP1Fx4{cJf8d5n>GqI4SruN0w06Pc`wvf!0}pz~9c1B5M5e5C8j$DO93nym%D z;L#T(skR-En$apTGJ&nsitk5K0}R1G$PoNjj$MPFp&N1P`sZ~piA*eViV(>#=a_)(!wi?WHHt*s^Dhc5AT4O+KerhE z@R#cScl9B;a8W+U_sl{{KX^|(b%~aEM^A8hKKRZAF&+PN2u?{4WO0lRE8C|0Q~6SU z-VG_&F%#x>sqRtp(4)TyRCjs)txRM8Ah;^{K@!R0i+m-f8SavV%&&_>HvI^v&;DD2 zKr;)T<&lpq1DAqmRVtAFfNak{`b~)bi$~dTf{_UzX`=bLYg8^p@RR>WJ zYXdgN`UA9BO{8DH|% z#i3j7^(R2SD4Xw(_@Vwb^(PU`%ZspJ0KjHLp`gPF600vv6@(tm>x6LUCZ@6{q<*q#V=;inu z!jlPF#6FfZ%KFJjsDW!#4omHMcITYr?IEPt7tWDb-M#58nzryvpbg=!~t%4@LGoS@$%1ORQTjnHdA{)^|MN?-W7Ah zCcV`@o@HA2-a%trv}x}Q0xo53$L%PUP!}AfHxU^M#(Ej&MF+~UQYsrnj3ujw|6?E1 zORdrSo!~_{(VOwj5z62k8QWA-5HvVf6fVjs%XnQ?L>fH=!vA%pRDquke3Zy$UG{T$ zh-q*H@WlZ0^H@qC`ma9573#OY1}{T`a)};B1{F8e4JGiXQ<>Mf2tMo7V~CG834KiV zV_oM47@#U~W4NZdmtl}I5bVT1qeJsYh_#VMo8?;7M?k}ihqoa~^aKl}7a(Nz)~CzZ z#+xESip=LliVENeXTw8oxQ~bM z3P(7AjvRnE*6N7NFyh7!yb41;R{=m}-Nr5e=oBWT?eiB`A z0y$D7dP7ND*u;^r*^^P|Kp2}qSXj#=NyTBOBfOH-E0Gd?w1;tW8;0^vSZrlfmVkfg zRU8n&G?{ZR_4MNq@>;8N6%L>`=YH@&j%HxxayW!He^MSeNXwTY-PB$3ZK(G$i$`1D z`XU^3pxLG6Qr=c@WRajb!V%a2gGtgmH_TI47+&CTT-VDHiTsnm83H#fgF69F0%yG0 z3>s{*QwsPSNAlBvBc$2UG8wz)KWKGr`@%fPCz`w#&LM zr~pp23&>sEk8Vam2N672X>Pp*GJNB&4aD&`l7^_K;kE})I9h5S)r)gux2X1dS^9{Im7$}DcF6%D?o#rBek1V=X?IstZ z5b_JNy4@k`?&7-MW-T6LC%w^MJjPym_ttm>JoGvRME}e3Ndhmj zBS;7acd_jzg5MAr|UQwaI`+=CKpj%gRrd=&|C5Zy%Z z$Mva4bU9|fD!61Z&y}=Y>jUEU%g#5-SR+{?U;kOpHRj`zw$UE!9m~j1#urusK8Qb5 z(Eq1ARk%z!&s=t`N9iFP2HtVbP7OKJlB;`|*wUC!Q>ZUXa&dhQiLH+fK30){6Z}|= zP^>CFFMmuCRC;WS5f_{y8#lXnRVu`ol>V%i{CqW28Skk0b`b061RJ3Ki(537YM`QN z*9xILR<@e90nRloLVJ4u3%%VgVR2+VUML3Mdi&HlW3{~nHSba_HODZ35>3hM@HqFf z^Le=_W9Qo(05eb4>N!Iu`Z_&lF-R66I|W>cyATBSoQ_EsGr(AqpSL*Wj4ceWNDh$TwEz47Z(dR}pjlQZ zN8F<&XLW;(jreE779l9Sdz+z-9eYs%I3Th^f5}b-2ZUpheOo_@?J&^(ogLVqcL>jp zib2XiMOtwsT%maO9_%HTlDoij$>y3pkkvS45Bc^I=+*dVg>`Qyt^5~=PtcSe=9}-y z70N>-C0O429)(EFua)V%1~-6C$H#lYICTvA92vT+SpEY`m=1=N>$Bs*$dOpi z;<4L{SQkQ)|Ay~9tx zzVE|#l_K+?_KM@|rpF>z{7X++Jd=CiyRg=rIr|ktvrjyK`vP*30|WT5mWq&+$sO$S zLLMNjAb3YXSQMcYhn&B2))lHz+BwAvBE1)zzirQx!m&u~cIfh@C;@@iOHhA+N-Vs8 z?%yMLq+VzQIBAc*@4!1hf~5AYNp;`95Zc3khN2W)>1-0R zD%d#17*!Je?Igk&!)1Sa@*_^{Ww4u%i5{E?KKfmymjHPI7?0im$9U`V)Bj!EWSF@} zWuPfJ5ppKJz2n=~|B9-MYt%P>K;46n8s}wk$Roj_E5aG#{De=dRGiZUkfScWoN$8o zOq~_R{7_)s&yj7eX-2!i4#=6(3iOVW(?#Cd#V1Elb%pI)F5{OamK z!s*8&?g1$j#9sbGsBbiw>xU5AB$O&mBrQWF$XtD>oWHdO86at%P9(lq&jbkP@tWP~ zU+xDV=vHYX1X-3KH1LCOLgw?qraeNrQ&854gYWT9;Czj)&!Kj_LMUq%BuuCnQ^rQN0mnB>e4WL`QBd8_AqSU_QDK#(DPYwW+{18$K z2zt=3PlG*hUy)UsBRc}9Xm(rg?eeN-Z#O&0C(v&Kl_wxFbU6s^1UL1FIto%5|Fw4C z*s9nXDWIGNc8prNKK~YD_2eavr<9xjQ@xGIfBT zDIgjK5Zta59gL=wN66*C42cP5S$Ot5?^9^ATn^ZqGvEVqoZWdJTbqzreiOB%4?Xuw z*bEjy`Kr4Px&3}@qNR5}ISrdBui}rMc|EE>wERM zuzi`ADrsK(^fAf!n8y?PxPPpBS<(RK`WR!?pwH+*wkh?fJIa$^WjG@$9F>&>04JFX z?$y8h+34=T5#9#CMX!pwnF)jIHXN);>?m?7JvPhovs4q5pQNx9z>)-e_)}i<@;1cO zR_pJoHVWuJQuZZDbbyy0E8`96;F&Fc*moCSS((Wj;M}dz(h#n*qB=m-?onhu^ZYEH zEybP)H@RPbPLR<=LYZ_dGBOaU0v;_-B@6WAD^Bs$z?7`y zAVp>q35iEWZVL){R$68p1~?yUC=;u}!GRf)JRYm>4mUtNH&fLiM7;eoJO)A^u43*W zLD;w}B+9Rp?MiGmio&NsLr@<-SgFWjFj50>!XZeV-RNt zB@Yq6<&D%<`;KHa$5i~zkS{VSY&)Xa8dG}$9Ld#!Ak_Plk2O50u+pe?1TI3D?6NO0 z>T|Je{?=x~phFOeLN#ok<+Xz~48)&VCyN^-N+}MXL1qaO(@C;R?gEP220L4vex5xM zHju2nXNScfuiZ? zbKedSpWhr1j-!{KYKo1g*CEl#@{j>wBvg^9Vf0Tt`cMVTE}Rw(loW8e6^tvS=!m7o zk1K`sERyHm=|t3+gJWyPf;sra1Y|czkTwH;Q0QZtzF#=vSSM%+6VLx+6Bn@apc{G&MPq9DZfN)Ut zYSjLXYtcS#HH&9DnFt8y*5k+rk$?PSttRMWl9(#;-X-jqvq|rf|Eax%Yc|ZB2d6-t&y2$()!>3K-XNJxUFZ|wH;c_T>Sd8^@Ha``!ZNBON2VOP zAh?}MvsK-^5;`#`(l{TgHmH%g_6_kVHy{{R1ovWbPobKUiNh7b56lUMNR)(fMerYN zqG83*tG>g;S{;2PCcI+k5(8qz0iKO@3q>_(nxOY@&m{RM5)z0UxXn+G(T04w4{KHe zV!TZ2%JWl1PCv4x!G(y0+N z;W~4|=C9icr*iG}>e0#7OVW=v@dj9d@E{X1L@`$%C6I%1XUY{hW!`UfulX+a zUmV^18S0>(5hzvNxldPnz>hTJ7mvA$zF2iZuyD7;bpKQX1*4c;QF%eo@S`Ml``@ni z-~HZ1kx$fRi>W>nN3%!YX5g|K4FS1jZ{JHp4=l_om`xG4j~$vJ)ust|RWa{uc^71m z=06N=_619b&%HmG54W4!;WJV_z2@6dRd{Dd?0-IRd@9=Rwpz= z;ku#l;WOR-=Y1_oF24ClS^5VTeSzHz>e99I_56SJXbOX0#RuC*7k5UZ^d+}{;pG({ z{MET#dtbg~Jga^kCRMG}>Vdy;8$Mp_{oI7(Btq!+F)nwO9?8aPuud&saDk1JtoBbVr zg&^`fpS-3EK9(+8EYFR+PKx$|@%pQ!)kH)u{YM)9PPv!!MNyI8&3b1t{VyIY>T`sHnS(8|m%|6PNaKNX9l`Yq zBS+w`*LJI{5WNdCw9eP&3Z> z-qDCTO7!v-+>}|Xd33mvFPcm)JCa$r>03~k;hD5}C!s9CPq^Yoq-Wh&r%AxsxpH5y)=9EvOjLFQU!Ab!_>1VZ*LueWuOEx-J{De2!C3208CnL_yuj7B5B*9; zCeC0j&F_L>v2DPeRAj+*Y&sl1=ibTcw>Zk=30OUsO3THoJI`TwPgN1U_ITcYC%c%U^F5 z-hcUM=yyv_N0h4UO)LOXeN%=rnnSvE)wz92Kar_k+4}H>>F3$XlHT;_eVm$J zYN8Esz4hizlr1N`>ttYjqxOr*E-#!EKi4o*XGytjHWXG;gJbPu*==L-gga!{{I%^3 zOn&#jHe2po(>bfTsE|V2z%ZY}A98FfNs~%l5<@fO8VwJJ>F()&?j4_1Z_tX8V!x($ z=I-*$QPCc*gyP>E0uF&mO&(Er8POv>OsPKE(>>%7#-{oo8JD)gO48%orqSg8$J2Mm zHI;mCuWe~chpYvV&|7d9r3)I0AW}qn5kUlLp(oU!m{1j@2uc7&QIsY-ZYDQ#@3b@LJkN86_OHF#lpTSzg*KJ7r~7_sp@GP zfg>B%TP^223&?5@d~-fz)7`ceCBqDV5R?+Sk+Ce)F*ebs89IDv#zwg6i8*`rRcGU) zmy-Xj?wKB>>QIr7JtaR6QiZ6LbWg2hRW1{(uP%HJjPe$KQA47inlG7(0}6 z%Lqzc(5tx*4j!BbPpMmtsqUd2=L@PEQRkxNl?_mlzAbiOG^{J_W#?hZ$@3TZ^OXEQ zBV9e`+N+oPmAOqCnd&dpCB(7XIvds}FCu+)Q50xbf_^tLen3o(mF^#V9>pN3G)&$9 zr0sYt55Gu%RC8D6(*{$OZo5EG`n2%^?6=XQ_^n?PT8frs3>E+Q1rNsiRPfHXq{4*x zwIy^uqveCag=0=Gev2wB?#UpzC?cxf|F@;C{BhpDZu&eIA#Y)TsVKP4Oe4J=(pA89 zV^3{F3suw7rxktCb(cevF z_P1xQZCv_m_9j^{{6@Qgr+A4<(zp8&=N$d>@Iy0nZG$*s|rOyG*PS6)er`015*cLYur!_>VGD5SDw?xwK!2avXLF?Nq9RK#KW`o@+75NRFylkA_i6r^l7p^ON(QIpbsz z9g&y^(?yPwKkCNQ1o${M$qy1r^{zVcKGH#LMfXiU?`dzFWy05%LA#3?HA8Mc1NpW| zc599}6$JWDAm4M+>A~o$mhP7CFx_Tp2qXtglH8U~gZkvLlj0Rnu(QW5O z^|dd^IVz4TAvs*6CdS}ArNK&+P2rI8?}1(EVBR-Q4Qo<@%a^5qbJ zJe-IvCE3|H;U;Md(ckmI)_IhA2Z8=Ggzp3Kv;qRH8N|2poptH2(Q6pfj?s2HD?LnE zDIPomcIu3Cz?I<2Ix_p!-P_yE-lMLJ`)XQF7J5?|5KgFVBkM-t|v57kj5(IP9C&MD z>Kx3S@jP$UeK$0{?ElHnYQOy9YZct;ZT|;b#`}`K_tu+BNf9LYP?@mLenGyq(UNz4 zpisk(!IX6L($6|KGH0c;Qerv9V}JE&j(Oh-6{>201N^q##`SecUbGWFnJ&gib57Fk zAq)106HTt1-`ixLb4nYx8SnT$(`l$refDRWaIUTRvl4@s)^=0vTtC|pz;V;bI%dnr zR@k2KmVw)fKLVC4=z~~RM~Ys&RAxY%Yo}0sP+LJSs9{~7diqGYjhJmgs=~oVTH=ql zx!oFrSNO5vUlXjmtzS>J`!&8DlkoKm5IVSRXPo9;bUDdt_!N=)XIdyBeVr|Zw@1ip z3mUQL0$f&ePF6C(>U~cin}Sn_!2##8JLSj=wuJ+Iy%X~L7KQrb{;+qvwQa#m1vBY# z8xwE=Y_LXkxJ3x?Hf2i`#@3Rq-7m3jww9guKJPEYxfAH~s~xeW@4LbYA~g^HT9wF> zfDxfb{K`CZsX6O4*YB_8+24+*&K1it$H z;{3^zNQ`aGC*{jYg-AQ6GG;j?&^BbG&+ILz#g^-3NyVU0Ur?<@11A9*7o;l~7k7Sc z_j0hDgy;B(tc@!thq4Eyp6pQf#)Qjc9 zy0(n6x9j6$a4EBeONF>RHz#~SIeSit)TZ@cvq>3=3OOJLHv)|KSkJVx#Jay>K}Ctk zS?H#Y+>%Fq)*Z7qr3|QcCXV=I?AaifKIO!Y<636*oCg+oOzftT=tPI>&iK%BVFBBM z9EInbFewAkXSgz>pc1KiFcnOVyGlwbs6w=c7!h13wg%%ev4hgP!anV6?E85XlcqBr zU6R#A(fmDYdi($VZ)?>}cGN2vE}i!?yl^w}nDbh**Wh(+y_4x9bGx@X!yHsi?h`D! zA6To*vOF%Ss=4L?r{DYned0xv?mFURqRfxJ8Yk`iP;6j9&PlUn?A3qrt;p%?zt|7Z zdh%66zH~QCOFMFeYeAubZM|&>}bHBA=Tb>90!`@>b+P!8i`k`4mNNc zpz%7Z%{?aseCZAvmp;74(y^i#s1*(c{xHI+k_#qrWN`0WgUTXv=0y?teUN?4LL18{XPj|R9(~rWf zrWHu!;DPozHV{7U|9c&NvZ^EQ9*Xd@8*D-zfBOimV2EOLt*04uvXLOJv)ipxdOqOm zIP@Yfo)Bu^gA3Ts--)p;!(}2UP^BdK*j04(Ln4P3RIjl*+qyRhjx_EeY6j~+n}+>} zn+6wkP~8vw1wIhP5BZ_9f?+wBjb|Ma^OObEI#S0ivQUFFJMCt>i22i$U83V(!}x}U ztTprt)bjOalFxGPjQTC2#Qg>IItnI?8BI|1>Wyz!)-sb=ME?;4LlR%8Pa5Wgb~xXr zr#!B5bQs1@F4(+5Gtj`c_O>en`>HJZ`AJF=X}Ge(`SD=Nom%G65tO|TEWOTgXb}H| zCZ@=8R)zB)Sw<08YPgJtulAx#l*tckL?*n5`t@8c!+~}yi!*hfD=SEZCW*TXHWnDy zK#a_Dlbl`6kWm9H!*@1?yI$h?g1T{?qw4^El9s*u8?CT@sbcA0vLVT*hPPe#eAYExD}@8t zZ7I_#x5qo_a2S`4Ec#avY@6grAI6KUCv!nvo*@E42!8xi#ZRVIwY2R)#Qf5$@mJ?R z+0ET22Ygsut7!6$k!Ft`Df@SUa@^$s*tfTTgwRv&kR69c@G6T&1k8g07hZ}aCillk znbjgv9+UZz_HhnTxKf!8KLC7c#9H8`rCoIpuJ3(;UkM^g*K=hwj`Gk<2<=Gu-$4@a zmVkc(FU{?a^(X9l|8+9U79;-b?fS?V^1{=h)POG{Z~Td`iCi#RAUm2^)5xXNG%VGu ziDgN@IrC4NhRey!2MJcyaSdF0z&%gX5x$LaeXV77Yf)GiBVIzjMRo3&g_chTcgag~ zPcN@|4FEyaXdmcMSO=;>nBAx<>+a`{-v2`u}Y^1-AOzRn+!InIzc|P0&%wA>Yf%p_-hM(39dTA)EGcvv89%C{qkd>e z*9z&&N;#SFJ>|y&5`)nPe)GKYCD-PdEq(oBaUIs}J+0#9^3G}t=1zJ@C{buI-^iry zd%qtygPQv2te0`Uda1Q2@^Q<6xi*Z=EI_BOD-6M1^Zk9ps`$tjv-$Uz1jXZ@8(fvP zc(Zl~_&%t3opupJbFc7vk0>J~H!no#%%5Epm)vBMSS2e2cXlzI9x`k3B}%`LhpH;t zkr*F3q(@qHwO-*}j0%odi~LRop4Rn^HoAedeV!&xYxKNqL!pt_IQ`JY-xZ5d>=>Pg z4Lql$&X*dBAz!dgyi2J3EkxlpjDD8XM77ES5n9oC9`R4{6Cd>KR`%{8Z5O^j<(+(g zc?rD2g%es97@n@8_#WCJnuYWg8zy&3Mio3v;n6x6 z&Rz-40IPlv9@lEM_*;2m@97>)krC4W4m25nE}JrW5sjlY1^w&UgL7Y2AnBJPOY7yuG7c-^gt}p4yO;NwA?P!5k-peXt{^8M}t+otUA|*R}r-_;$hr} zAiU+NJ4Zh2Jsx*`v(76W{zISUdVG!7atpY5`&RqV@9`@42=+JHJxknLm!S)bQtsT4 z=<{~~@F+_#Txu`Cf79EXaMhRxKR96>rBjEmJe~D5oc--sWb5DpOO?V{dpbLrt z53c>a!<2aGYK1^m{KJp$V~6CfR4qnvf-YDNqh6V;FuGgx^53tI$Nh{Of6qMf5M1s9IQ;%rx&W8MwD81G8E-81JO`+*X(<1qPH z03%x_MJd03!c6=TaDWqI--i_4>bW+}ObkIgL~G-9u$5wIIgV3hhU1Y4bHT;ha~smA3Pc zg66olU*VH-xyv;wWktMg0!=eD=rB$#ZN6r+Q%`@5-7r9({*@~nVz*B9dgRR>r~VEl-G66o6I zs&)7~`RLtM!TznllcU*!^$Cx|o`>e6k)R~pp+y_-LSKmAD96b4@}Jw;U#o3#Eb_~) zYqw`$7`wtD58d?`bv}oPu~V~&dId!yzqRqD^he|CA&~W7`&mN?=OmmDv|6j_kK(L6 zuf+BgAVDYUO@?eQB`kP(tq8hBKELqP=9xKzBx9DAZ-X%}Aj_Ebt~3QuTmCz^!~rFCB;t$OjT2zu`t zOu^q+FwL}lBRFa2)6C7aY$7<@qf3Fg%)PCx6r4|SB!9oiaxUcA9#4#mb|9R`chhNy zwPoB_mFb7mT#VY^9{ZRMe^WY;kMuP+&A<=ngxHy=FLtsI%8yEg5Sw*PrWbD&tns_; zv{gRVPc!fTrz#?t5Zbv(XnCliTr&w^rK-(v4t$dZoR#y6mF@g>g@-EDx{j=DDz$L| z+s-;_)YY{bLySAgI4K=tj$n{rRE_KEmXVA#CWsLtr4N`&Gz!r`(4e+Z@RbfBphZi_ z@4M>1!PZ{R7ZhzT+Jw6r0~~Ohae5bWTI%d}Rdq#n#WBS zaNwm}Zg*zqsW;(Hxb%MjwZN*r;`1Zy%|XE^n1=I#TqeK5PW-y9pLO=hT1g~qtG0=C z$xOfSM8j0O&0>k_7yJnq^oLdc$;g6Om)GR%yxm6JqK*w1<{Z{uVuzvr!5|5OK;@_h zGFCUI`R!1TkWN&A=yi2$q!Xu@^>&q(~kvA}9R|2+ZJ7_X!3KKcF6Tfh#?-=32S*#OP5EYQD>ehwyb zq&>a~M}Y#7WFs&BZy&K9X@!WHP$iKU5f#e7zbN_)9t8pGkg*Y)7>{J*53vt!LJ zIuCHclfxiZ%~knqxLAT1(h*~y`c&Pt!%o}y*Yiohc9hA-w)Zo^C|$-{cpb(C@4w9| zOM8IJnBD)8@$X8p2Jg{-NyK0I2~Z`Yh9Jz>+6DjE_jER}Vg=D6W71pTUMKf>7bkZ% zF=4S%U1XZ9d)U({Fo22t*&jz=0f_IaVlz-*+Cy9B&%Tyg$0o4#e9rd@{BW~g}R+|(iX8>98+K@iA~jeQPocsu4J z{c{79wx~+^VcW`9SJ%L6^(B@}21}V*x?VOh+LQB2pS3W~Fy7?OaKYx&0npD1Y}xgL zFz@6mE5!5mmgBIiKl~*C8LMne&=upIk+@_KqjNea?#2p+Rqj5*9kYRe!4i>Q>slag z{Oaw~>jVkGL?m@Hauh&g{FZZo@Ux6HG>Cy1r^}lF=Y}Hd#080q4+h?5kgVv7d!GbO zZghQSTWU_a`+eE=KsV)=Xq>OZc((q>r#z1f$BOQn<2I+Yi=-664kmlXm(?ZUaGU(5fm#Z>6xG?woYrWkmvB2K8(O1qAphx{25QredoR6Tp zsL&f+A+QC`?E+$`IQlWOcxyP{$!VXb-zp4+S~1q0&GdU)`PeORI2`;Xvy)p)_FKlQ zDa_Op#&>na&iMZ-02tvjM)zmO)pp3zpn328LIFl_@Est*mLp*r)%6_f7%Qi9y8hkK z*1F#C=5W$IvuEz`T#-)-l#z!|MShZ zu`xeGYl6iO>HV);MiPuTxWb_u<-bX020VZFeN+N;ljyU5P0uQ9Mw*rLG42bPe%MQ0 z2h+*(_FpWFLRF#hQ$2_otTpW)k}gOEJNc7LKPtOc6ad|#c~`EhT?8~@=JK&mn{^)p zyPg8tyQ*K6Ln>F%(G0zr6;%s)7w`v`jU({ha}qvz;vNUaoJ_`RCYFekqnuKeDOwNKSo;o zIj&oF$WVcyO@)I`~NBjl#a`v$ja*ggx;TQmrqBU zcIXQn^WM{;RGm*#8DZz7yEAgTmj1OUk( zcc1jUlAgPt5%8g$@2K!-e#dSK(U4mSG7*~|+3Vly9)9F#@=E`j0oKuA)a$~Yc8)#Y z^g{$)DT6Aw8}@AUZ^s>L+1$V?tm=P|j@8+Fo5Mh`@DB$^P}Qsk=;ntcX|9Y63yN_{ zAgET7b8G~%_i#4VBFS;qP1c6>Zcdf3CNv)7(0JH^Fvi8H@bIy>(W3KUad%L-Wx66W zD&B*gCj18s7Jlc9hCQ8t6QMt9z0v!C-7^=OJi4F-ok?So`hit(XF0TT$M27Um2=r{ zivY;sN>bP=Oy^V3{Uu;nc+M&dq0|b3O>I`C3&I7wuSetTZ`0k2NFL%LTkO@fq(M8U zmZzJ9-vc|&mLJ@Ok!sA%G2fp)!l(^9Fpb?!e5!jIm4(51C5A)-AFpRgIQV?rlY@04 zO*{*~+bulhAs!R6LBjLX#pcrtuSkmwkvj_YV>;c(n+9X26mtXX8r8V88i!xfQ;p;$ z%a5P?DN(o>qwxE32Sw5|8C%`cK8U0%>Q}OyWEuCbIaP~f<>L9NXnkK{(J-P|bd3J< zA7LZDohV_^eNP-bk8!tJ#3dIz+h*0HAY7$t%=d2};SXvr?AOVHD{3z?yR*u`J*gt4 zo!o>7#&KwxOe=|-cK3{rQyDHfisBZGkB ztXacm2lS0iDT1$Nnve5&)B*Mq-{jSr4Fm#;p+pS93Tfl1|8mfKMzJQuF!)K?&2FTL z=UOv>i;Fp6O#sgt+(9^n7-|w0WM>siSIZ@JS5-ss-v8qr!VEHU7p4albC=8ccAv)2 z8%=}ZFzg_diBKurx~PGD;-^pX3KhxWDM^M{fZk*-o?N~u4=c*x*ob205@2Kh;cyMw zAHv+gKURL}13UD_Y{A(*-QW|{Z+drJG69;Apds;tnsv~#AXN2l0H;@_4Mw_D?S~W7&ttm^dOa@teX$Ou5QVK95JBL zT3~Uy=2hn<fZgRz7s$;Or%j~xUu6+jTi?N94?+MsZ zCI?BE4-j3U0MRGmnGmD!GC?lkVe+j>1EVE3aTH$zc|e0~kgx!-v@q?A>ku$1mfUe1 zI3V1aeSpU=#JwCaxIGhl?FkpR8G?Ntn2+8t;M!r(G3$0Kl&@;LtujGP z%##*BASKs+0`CPF*0qa84y98{6c3nIWCOdubB|-oKq`Qs z8`>h~;D9Sghf9@aA&@38!JalVCd3yGk>B?IZgwgKoTmXy>#utD0}z5F(ys|~&Es;I za$^MY_1B-)MhJ_70uVs=L->gZdunnm)xd5l_EX)n4JFxU$$9CHxI2jHXtjl98$~l^ zP*<+BQ|U3NQlIO|71SfkewB10;Px!mn+INYD2F_4`$&gd1-~0?XiHjz??OOnOV85v zDMlF;OycJjU2M8ImJ zve$>r9*@(SYSsNE~6-wIsBQw60M;q87 zTx4O;N&s7bS{jjc493V#78!BG8Dq7N#mrj*U@ml;9dCs&^5inRhp;&ZE6CyE_We(& zP$#z!J@S!)u^Ta{(tdn8)kij%AnKqJrt_ zc1aoL`kIUTah(i&SfD<^yWURL8AkzOl)DIW#!V@hPjx3y01Cpu^S!g-Ef0^t6w<(y zJ<<(U{Z6tKm=mfyn!rtz?0YqyMzFwB5YuHp=_O13N18$}CORo`l_OnkyK+GRF!P?4 zwH8E9B}hRbf9NfzlCx49pe$SLwDU#wHvt1xr$DD5gDXx-Z_6o~tP=&wZ)rBZRQ9>u zfsf9XzqH>VFNi6~1^vlpWa|@B(gPN3(iITdyYnCX;e7xQk=tMB(bg^RLEv(KO1`ny z#R*^?$%OfTT_mR4|Ks?)Cs0CQ$^(`VgbzIbH0R2u{r5%EB*{VdI-Xdb5b?h|0SW6c zq>MNmQmabh>~rF?v@N*OfcV{j}k#0c{qVSwXSt_*`ErtkArTQ9^MI zLj|qYprP?n>70KD)*gBVs_wfyArH`gz{M@^@D1KoZy5VT_wEc4!qz*yal%`bt1k{^ z3tEO_a8V=cH}EdyfWQ`iq!2Nm1a1&>1O*+VCHsW5cVeJWalL~FD8qiKH_AlCV1P1! zFR58wF-_!ksDfs{cfoBT%X&Bm?VMZ81F%ZUjLRvKkmGUKVL0htWJ%tR6JDoWc*RCM z34mpg#HZ?z4AaJ{wy$_dem8NHB}=tJ#{RWqB+gLBt27&* zD47Bu@X>r<$$aB(%>n6CzSUN>$Jvt0H`=hk6Olh|Ui@J? zu+z?;@=4W1i*Tm;*s*~3;SJqzs&tf}UVnqXxhntX!nixNgRV`cn?p4Emh`}1g6Zo6 zbW>@D*8QV3g9RTzxyJ)9f%Lip7#(7)R=QX~b(_M6&HW18wfB_os#;DY4rAadr|HO= z6QnA@58`g7y)^{riwaN&J$j^kX> z1PkIZzrgAqB1h;j?{>2+SV0DJ%v=DXEa8S}=boD+t#$r&#Aa2sAe?Z7XnLEzuM687 zD#iLyHdVP22taxW;&#=mxJkeN?g}NFl4u?@lmLooPyFveVT7_vev~oQ8dCSiuhNPr zz3_;0khu3$-mU7=S`L@tc^pIfldqoXkRslf@~L?sHEcET{sNQxcO?ek4wYan&kxW| z8oUK8jfOmm{!|n9I!R?iOzT8+1^-m4tH`)<^7*&8uhDOzuvzY|2l{)0si3O|VSh9)No-)x6qg-EA$wJmoe2+X zj{Uq0SR0Xc$-p2zAtUG{X zLv`4kM9u*WnJ>+XkUo-+Y90UnRux{wJ=Lm;YwS)Mlh$7@FFfY#8h?`8t;r0Kt{k^D zd z`pLXmbtq;P&f$kv^#_j8wO%n|$MM4yWwcx`TV9~v+Hk233Mr z=uJP^Wzq}$qOdfEaaW6f93}4mzk(ICYrIzR5UPk111^Fl0MB6w@O?UJApnL3fBJbL zYaUd%4>Sum{8!s;KQjKU^8h0yI7*9i2E`W)G--}wLwMOm*`$3x620j?^hgj*0uH*f zECY2uVBhNOBS})6e+tMmP>%w@U9>{>xHS&M0BS_yHaoa z_5=b5zJa#j8DnAEPRn5m6&?yJ4*xFtOO>XoG%T=%SED>KsB8 zBy-J;l!Y!*G%OG7;{fm&U+zj)q=(FkB|aqF7+uhiM;Y5$=!&*J5FVk)+e8 zLW>kf%v=KbVIOUU1{hr^Zg-Dofq#omuP0L+HUcXE@LzPtq8q{`1kW}?J+&LuKG;rf z8a@klCg$1cl;HHY!Rf%p4`yix`RGeC?l2)zSo|5-Inup@!EUvE!=ShTu^tI?Xn293 zgDoeD%bxayhHjmqMa&@@e*&ijFVXlDn;l|3dN?C=li>X|A995_*HR=KhF!lo%g&>^ z17Y-SNY-g-y6Rl;^5>Wy`?OCsG)c1txeIdGiYHwYm(O62|Gk`?zMQEJ_*zlz#U-)G zY$>MyuL^ZQ&3)QAj<);BYZ?AyZT#+;sMCd_uLt8r*tKz?qUuM(PdA97&#v<#BEGXf zm3x|hUdHt`8#j+=f=~ReqM?Bw0a&9-Qm#=Xapc2c^y zQqhjw_(y$ufL}ik_;ty{L+#u)?!B-0_UeG2WM$bgdsiYI$m{9b%dcs+f2&qSJL0=V zv&;cIE2hS1_HLo#2k0XvE|!Hn^7F15o4lNnww9wNX~qe3wxor-lyJND^Ef6wd;Apy z4s)MBhQt7OY^CIerO+-}D0;IZ69edJUNu(EB-=2yjMKGQgAe6jEwqz&dSq)-)#0!X z&QKS)manBg19I8*k}8jDCmVeHt^^@|&!0UmVCqoi`h}jD;`0n@{J9Oi*UR1XtCNs_ z-e79XEkN+5r1R8_zn}dkuDEsKQ53Yh6jqIgv+paS-<-hiiK9f(>g&9esM8ywSpg7> zod;f+M=YT>{%5=1<`NKi0saCivC-pUyk~2ea`lXZF4EUP^k@rUE)Jbic8G#re-H8K ziLnAN0B=jGVcB|)cTcTMG5DyK0NL%G?fROpCyw*Hgk(=)&o@w2D9i{TJ|usjS(oTMX~_vrY{==m>`_0WmR*ZNcwE0> z7F?hCEMFIvU+&Lzi*f;iiqoaufuXGSchb;@^mf4^DZB1C-CH+!=9G_#xS{MutTsH zdq$L~kL8TfEep)2jGFuO6g^y5)=ZuHl-$PDP)UpT zg@fcW!41LnXosTnc+aP3qo0B&_JB}Z#C#3YS|dTz4Dd>`J={e&w1V25uA*4KxyL_0YADfm=Xzpnvdq*6inH%GtOX(znqi# zOt-jb;=?udMG)#HwLC73$)iM>`#dS?p^=+bfg*AZ$SDf8^3k)Kf(?<+zW}Fc6cB(N zpNjfO*QOWup!6MYVO?|AYMFng5s2GjHTfOtPdaa*qn7KcCg#$N3$Jp9W)5dG&i_&mlt zmv}0C=l~tuakE{C|47-YKCDSs1_(~XLcV?(p z*iXT@h_CG2nos*3%^79?J$PS$1IUWbLO_F%Ju)tL%qFh3$$XskdIG)W^U{2qN9N)s zMMtWy{WY8Tq8$j$m-+=Nmue&=rv3W~->6N6vff~Hm)A1jy895`%lwie7AE~LISmE+K4*o7^ z$1Q^menbT0!W`Zqq9E&fmY;IL%j_fFCQz{1o)OBZnZG4-1C+rIF5J4i&L0$wTnszHwK}_Y&}3j9 z9~EJ*(}Wvn9tuw8A~Y!`UI#kaX$aLF8NYko2}GE>%8W9Y8NZ7S9J+AZ!QZTa1ufn3 zTjy7ev=1WVDA#RVl?y7Or}hQ5ja$cKj)*^Y?w0{&F!}kL4-)j{Hm?ue{SG~hKiodJ z5l6gk1B2?~9KMyf0bajA;=1rpgzIaV_sp%@HGYQ(@t@8%CZK^3Ie-fZw{L)&XLD4U z@jN>ZT;BoPnh{3}$tW?Yl97p8furrlvL>|g!nv^Q0_|0=I!Zn7=lXn614w4 z-qTe)DCM+2hlAPNUx8fC*8QHMy3H)@#AY;hn z^(4ME%zluJ^S*9#55dUJe)+G-<8cra%wNzXm+D*xdU^mS0RZdqIJC6v?vimj*Av{c z^L{kqRIaO=ZGp+kACHz>TSl7h?FUiHc%AD;cQ>GjbNe*Ksb5kVDEHLnK^7^7#yTz~`q%F2x)HJ86eK`4a* zLN0pX+{0`OBA3WYl|*LtQZ1L~I70FTS5Z5nD<->w)V19$^=+YQ7R?a~u_BX>DrDRf zXLg>SGY&xC6Y#i)02}A zOV%{eUShxLAC!&?9lyiewH;Y#Rv#b@N7HdnOIo!d?zW9}ScA254Uqb3roW=dLZ~6^ zHE<-rMmf+t9^^mrs}69YrCLDSF$6f(J^<4>D59a#0MooWY6(g|46{hS^&lsB)L3{+g?48!L}KyEQ5);oRqnQK{jrQxR~Xn z@Ax^W!Y#)zAW*(&w;A~g5UMF)uX^5**baC*{ema`qs|TKf&PGyPId0J-l_Z0^pgOz zrqg8M@4e92ZvJ_>4!ljLNMbn`3+(xL1&?R>}V`LppVg#ybU#$?f5J! zk(3^&x2L_hpXGAd$bQcrn6kA-@VLy=$XySh>o+^k51<*Wz9?@ZmX6zz|8@4E(JtV4 zWzXJ;7#8(!`}4Y!Z`bwY=Zx2I~11;n+HJl)})o2)8#ZBPC#FOzWaS8jD#`^u%|E1DoQ*p|$3+VykDx?l7e zN@V%_F^HxGfqR~rSEXZKpX)XE?AE>&479MQQw zBGSq38D}~>;e(R75O+*S-8^Ft%fZQ-oi*GX1_|jMIlm#Y9dM`n z9A8H6%nn!r+)bpV+Rn>El9GPNn>nR_n<9IqGiv~{P<3d~{kiccU|+yw^*!-!qjzXb zGHRiGd~x4u^2$qh#bf|Fb*Gtp4!D)ZXC=1lAAw0onqAkW*`;!MtEIc%0_Kv#+V6S6m(eL>Rkz+C%xJ21mbB8cf={rSY6DKi?5xOE zWH4~XvV_@X3Q`4*JX;$LWKNve(@xtN z4MGoO@?td#T+D(_uY$=WRcdTTk(BXChdMfET=Gg#)dh9X`K3EokYYPjyo%ZM{fw8d zjMbUA5Y^5DAE5cKUTd;EX})XhmgdV3G>m*nYGOdc33f-Y_K+Gc|O#jB0O zT13y^y|CwD*ZAKBSJh~6T+QWOkrr&@m7)Ytb>H{f9Jp=je|ci>sOWmszP#2OE})eY-ow|O`{faD?^#uTZ?x&o}hN^Ggsji?NXFKoN zRRS*1tTq1$o;pB+8t(0lNhjtMPeX5ylLDl)d1nZmx~{uCOoV*7_(1U@Vy!;?6w24wWS$nz5}dG%|Rk*jh z(H;IEHx$5MfKx~MdL|cF^A2MJLCWv*S?ED2AT*TL0tmBKX+<~1(X+7m_#0LqNTvqT zh!4&Zs^z%;VXUm3V3AYXeYeSZcDZ$m$}JQfuX z-Uuo0+4ZdY;YULI)VE;8bWYO==7GkyLl`^u=}TWhT5$^Uf@f}OQ)Izr?pk7kl^$m9 zX?Vd)m7wpw7lVZzB4S40@a>qGbj;rOR&_i_z?bgp`Wim_79I0+eGS~sH*p9}$Mzij zzN;y3au@LY$A1Ra9aQ6rj+*}kGLSrTmA1Pn$NkZ7l!^jA06F5|-K*U?*S^{_?r&_Q z4`%?3>7pj#%aVtdABp`Dbf=1Jt#)#DJaVR&)&J8kn4y?}Tgk znamaH*b^b#bt}1o1SKeWoVw*yYN>>r2Gq@}DszwFylvP@NEIfY&Tc|I1~aqu72i<@ z6MS+2`AEAuOv|gDo#?1orbJoTZo>~N_16oFhj2ar;a29!hax`1DxrIWKt`-xw+Uv?a-No$kufR8M`Ne2ZAa{O&c{ZIz7zGJ{YK9ye+ zl6x9=(gSJ-TkLVm0PaQr3Y(J#$Du0E)UhY;kg{1ON%~%!eRyxEAdXQc)tU@8<4Ch2wQvA7V#CXA9yj*zO+>lDF~9sIwY-Lw+%5s zx@=`sB}h3|98{tlf=MQR*OM|y0%th@5&rCVH7@tEYiAt&6jlDaa{j_8ORR+>g9 zi(G>)gg-!i$4QH2zDRya0Rt6#69aHg;A%bVQL>qaz6=_4tM}zYZa`VQ{07R1Z+;ik z?Gzx@?EE_HZ zCphH)i4ky*T(*h~tXQ@xNjOn*Yt*`9H0esi*tZ`(3RP)g{R<|&)?0m+c-eBaYLJkq z-9m3VOyaQ9bkRYjWvS0@Rz3nk4}*f2B_d=fl@o-b z#jyumWni|9=TN*l4uj3yYbC)il?#j7f<#`CV@`PQ@_uE&(}GRklCnJ^zq`U@XO*nm zrdV{RHvM+0Ev^Uj@6~g*KEx7G0x3HUg!}6q(jD=kknELBNTP#U3piohWPfl27!J7t z7|gQXq0A9)T;B0a;RM}#F9@PuIi2vv;Dy3g`M%kdq?YuwgTd6UxIp5}a9XIK%dZ6* zY(iWm&qI=pk6#II8<2k7z^jx`-!I8~-~_r|Hc4TH4ug=NaR1tbdd{njgHlfu{Phbz zzX9osl~!cVt5Cw8&a|h3bZtiPb7*5XNT4j+i^ZE*r@FX*^)AcjBJ+A1WoXT$XdGz|dv9h$i_j%CLH zJ8x@M-N!jCe>lXT*-`0R+5eb%8JG*uOaNNa;d=kQB=CIIk!dQgUn)@lEz9z=b$z`d zHB-EYmuU=bJ3zMXaxSO<0|pWS5kZrmT+fM@l-zpL{g=1a0}{spXTDKYT!YYFST(K| zWRBWha1@~5zw^P_rhl}VFGI)4Quo+$u9uPBNzJkLYiO58x&t|9zWp{IN-lD!ZXj{! z(Rk}ryXrvBD9AFeUIa?DgQ`CF2)sSVwicPv04RP4Gz?u2TCe%Jq?dmjwKDCPjib~t z2ACekAp-OU``{5A5rxhS6rcnB0LYvDL{n_`LtaqBwRbmquLuu6LbK~}W&e_DK@K6b9xzAyOl)`)IeR_w!Zb7PXoL7Yl(2x>ejdxr zJ%Ln0-rNZAZULyy&(HMuJ5Zpwo^g1}Lq=VVkqxH%3^UcDkcT@Kl_devhffx-wwr>Z zG+d5=)Y(%_jXtf|7Iu(e=Z-O};>)mViGTy;gwd4r(VyTXANgN~t?xRzi-Bi}*3)Y7 za{pRmdQ`mbWYU618(P54kyfz)CA7z(%vwEOKm2j*5>8DE-pC<_t(AenI1+Rk?K$YU z!~ViPYU1xe`V+bJbnQ|z$2oey>2)X@#i%w;IWfYNKG0xN3mqFq!T2;_RFtN>~g&u#OV6&KYYuH%nJ1q(oq8T`#db2Y7XGDjsX;Na5a zjRmJ4(x*0lY3THVKpq22$*zhMGZA zf!Z97aAuU;bkiNRj;eOtTyl;i8>Wn$NV|j1K?`^{7M$=`_iV6lrh^vRn1L38*}BqY zNtgb#0TgD^gYUkXPA|q)SDZXC<8doeV3KUVO2ciTY{1BoVz$_UPbeYiuLJb_kYLw! z^qkx11qSJ4N*%qn=p>)Ui!zW6@W87|X%N4KQh!DQosB>2FB?k`dgr{kl)~TWxJtus zEust2um-XO*J9QY41<*V2t=uU`5dy1#x3Iz z=sUAf7VR9|7fsA3a^Y!d`nvgBK;2$1<%_=5)#%k4!~|)W#9y^sl})3c)0o1>csPl9 zVSa86GWu8|Uz+#pf_?n0_!hw%9FBvTxy-q`7j^=u5Bk7iCcr&?t`?HZ;Rj}^DFK05<)WUlH2GP4vf}qGS|80VJ)@i z<{*nCb^`Sv1m+!O%m2H04S)v2S%oFw6cg`8iTZ`C5j5kymRa#4x;YHo($XaXZm9l9 z1}?3 z(bG7Mo0kGH;&oa{3#c|U0BPH>`rE!KyfGRM8zXoo{gHM^yn*FRq+AFFv}z$H^b3BA zE~2Q@E-a1#s|Rp%NiC-W>1g8b1td(T@x{;4+9LnQMztwwN0q{fziThRym!5U#@({} z#0=a#e7vcVg)saa4 zKce0{u8H(}|6UbW$|_Y*5s+Sl;Hvbdp)5t3g&tWHX(F8jq*)RXL69P>GzC$RqVyJu z1`rS_f*>tG2)*}So-^_D`#yi@YZ#KrFf*CC?{l5&eR+>#N|(b6zA7F27MM60&>6VQ zP*&v%T@U8D>;H7%{5X_r_SWgtH@5Gd^;q-?TtpoS&l&feT2mW5L7HN&rPiEZM~R2 zkDOY`Vl{8KW#f~SdsOljbR(UN?%XqTnJsd(`Ro9-0IVU0kxM+=7>z6{z69fjrhA1P^IG_{TB*E!b`8 zP}0ulkjX=X2N{70bWz{Y=d88CztvvICs8gc!@t| zJJ;bpec9fynTGB}3qgsmp)#02R;Tw2GDAOS_FCC%1b@_-E?&;N%qd@wgn#61_!XQa zp$hlmS@NE-h~(yH{!Ze!**r$*8IQ9v{v4k+K3H>09pPAQdkge$(p<+?emXOQchUbb zbBrCbSfP~qcy{0{NLAe z$NcD*E0xT4L?)rxiJ33<4(PqX$6F9h_viiYls@%|IUB+<%Pl{%1QmQUufwb0cMISo z2EjmgV_R_PkHcG`M3JipKg?eWQFc?@&ZUyTL`+=6LWRZFPar@Rz+0-<60G4PV?G{g zUeDe0rYEaNzDGRGiB2k#A9>(6wM8|LmiWEaKZ}!V6zBL)ujfko&?g{`txngfZwN#i z{l%;loZ21WIBx4V*!9r?nBB!z;|1%u% z=aI8f5)_>1{SL>sspqh|Ia3Wiw^(sNrnT1bcy`L0j;LX)(jT#x&N!PA+AZD=a1c`tf?B81N0 zLRJ}esNqTaotkUfqapb?iykGy^}s}!o(Il?r+JosN<3{z;iUI2{G zz2jRx!&XC%_5y}BQR(mABSz#QU*yd?122E#^o1B7^@a#|Se#cOIKjb+u*?_>3G}tl zRv}m;pSId`ZDTYf+}omF5kB685B^}JHEHUI=15p)J+iU*EqK1P4AGA`K3ss4VcO1{ zeXg-yH(uk5b@n08ufr4KJ4+vh?6O^J(^}#A)R=~$H51LEHoKr|8))vMObAWR@D}|x z5aR47fJx@`G)#Gi1EHtl@{UE3wlAZ)iu` z7&dGY3jRw^l2IafCp(m+A8!NIdRhaFd-h1@t((SbVV5uCw6gooLg7)g zLwk3aULU)_>LCcNKB;d)ljVQ;4%bp0zie_?+`ra-akh_L=bcUph|&Ae2mJ(~F71?k zLdO1hxF1fS0;ekKE1;*n5VHJ9wB=|rHfjm(T&7X3C*-7Dscdubu&-gR|IhI3uecY} z#HgPG&^^L1TGe(_I_7JW#JX_IHhQ#*B@PHyTEo7?KH?RMaQ|lh5j&wRu*e2*Lb3I<}Nl{+d) zpb|fKbD|Xb*uZ_Y-QI$_NphFITM$R17$`h`oE$egr1y08j=~1Gjej&?+5^*>>Jbi} z@C%E1?1%YyZHAw1O{dm`zpv+EpwsfS++Ok`^GofRM}x;=yOA9_ICDp53w9`l4hEZt zth5()2PQKE{vgooxZn!!bbGOk)~%F$caxMPeR`-eTgw{#R$8N@Y46uTy%Vc&$LzY{ zpYh_VwPhqST=Fc4Ynxy)-^o7}!0^24#S`hQAF!gSd>M`@x~*FBD7>5I2GAH{61Dx` zZv_^RBd+1YV6&I%8F@s$VH2)o-9!oTt7xc+Y>+75nWQ$+egWij(DcB;LYESmr4*GR<_Wn&$!Tegw^KQO3q$*%jXkYUB9KnsX?wk*X zGO> zSK|Y$yQ-vZ2I2M__03`ljK8EGT}|P|H%U>_wtG!Wt6&(0!u`x=$6hAU5NV~`ezXHH zk5nD6&<@95sSM0{kHoi4(8@V~>;o2{WvF51PV+9CM?lKMn-e{8JZY79d+S(wY5rev zFQ@eyR-uz!<43)~RZ>g$P4shVjxS)TiMiBKeo>ASoXz8yjG;K5zpC(b*7SC9BDG*C zKK)0fP^4rKxP_HmFf{U;i19HVXL6^jbo*I7h%a<*dw=<%TVMc) zj=^BOMU1vOu8Pdy(*@^Dplpr8^1W6m-jWtqPGdH7ubAFrQWKhP}$3)fFBrW0MIA%N`0GELH*K3 zU!kO<$5$Z`{cq>BC17`6*#wEy zYA&t=WLbcDXLy)L)MN*-BnO?XRaqzlbF65?whCel{*n^quC!z49(@FGMMvriVGIJL>r|tF7Sa_jtx9!IEV}6(5 zlIQ=5Oj5)9DC3i4)5ZGNbVVR`2S%RUk3jlCvjrb)fpxllglmA#r4~le-gFUzGZ>*W zU#Rm(!B(6p753|nr>aX*D*%Vd#b5$e;~nnW>{$u8QB@=ElJuH+2$mF)CDEmS;9;i& z2oI{xONYYw5`-qG6XLU4rZo&Je3rojYpeVrs;EWBY@8fu+bzofhMjT3_OKU-gyw00 zOEKVF6+t>ud0WHrMsns+39!oK9;}K!T@2Ew&vF2?w#6Ot0zrIUeyiv1e14iweNKoz zSTD1zqhC~4d8YVAd#C7>lJOj?bv7X-uj~#7&A*d$9B{AXTMh>aO3C0__-`L_>&7gq zo*hosfWO{dzyUW-{SxYTL60P6^BSU;RoC`Bi$Hn&x(;n@Y-^D$@p9%G3HUz!2`u|j zlRa60y7c6Ui|-p6>zo)Asz*-x)mwh}f3P4Yndeo+_774cS?O**$?y;l~Ne{43xF1pWvc-gkhR*VUt}o>9wT@OPTq zPdc-u%BQ?A@YwLwA)ORG6^m%%9GjZUVT16*!f(l&2PEQE4PskFz;aBgvQ2VlYmsmC zEraV-BhTU@gZ&P2zefmW9_`LL06Z?tV$gqItp-cBb&XR^Lj7|vg<&4~+zXcz@9EwM z_=-d66?wx&^13e=B6kQ6qt@=9vh5JCm&Ae`J!gPl54Tn^VHE|i*Yky=RLdIfLb)pr z1Na9Ud9&Mty@RUgy*VgpL&Gr5ir60YD!g@7l9r+v84faLsRkP1nFf08zCGm1h&BVS4eLEZfg2N@| zCkDg5%28v;&j0Y(^9SLcw?(u#cY1Q_%2P-BoeB1wSb3`d5O~x%QxT1@#ddpx-Z;^H z!K2tkk;yobwb4%LjvSMH;tzc_-Xb*v4OxNnjZ;*~6?ZM81gVT>G@t#&uAYNGC9f<| zHTE28UvgYk=nJVZ|8Jz;9m?~U44==E6;)^a6*aG{0sZ+re{7Yy8+u?{YrE%JzZd7%aHcbqL7fT1yV+jA^_>j*j~ zj0nKu^Z-QMlLQ+?(KPm-p+}$z@3a||a^#W2^uliCeUH-*(0{+We}=0F5JDy#u=Rq~ z1aqGuC>h6GdKaJ5){LI8YvL{dh3J^x$bs@7&SVG9C|SXOn>pw0Z0s%wv>+=Kv8Gq~ zvKtO*eCT2PA?Y;(6^&!Eg1XJvpDvuoy7*F9KApt4e*KaUtsNeJvW|P-h3A**#-WMp zf+EqStO+`#?{;ZPJ#0&o-<`jvluKhB&rh~}d3FV?zDN9~J~A9ha9?oM%8YjpbJD6v zFlM#ayARHlh`tTAUaDwt!dJn37dfVqgdekZvvJ0n+ z+*?eu{0D`;lybPzFoGWQppu3?#g^bUt9_5B_~QHqix6IOvG|8|7z&c|hW;3UQQ&d0 zXQ4?KEyLKpM(vDnoP8DwviSS?tgVwF_L#hDkKsqek%-AlEd?piZNm)#=Nel{N=PBP zpP_O9W9rN;aW}vcclQu~1B2!GDAUxC%6+N#_&aTyaQS&c3)Uxy&yDEVev9;aF~*PF z!niUEuz2&O6OtxX36YaEAQjXD43qJ%M7^xgX53J~Hm_kiD(#_ZAk=y7VOcNuK| zR+2j_z$u_*0Om)+AWbr9f;0)rweN!u!Ggh|qm`OZhi?(QSh1yMN>;yNkcU=2AD(r~ z(=A0<$l9)_D8ZTCrED!5ajiOO5m4m+Z{*PhH>UG_x6&_j@xO$-U_gne!1d*iY0s~u z#LLy+3vp-71kUZYrYKlnH>-iAX^W||R)ENhPNOx>k#HO1(9XQq`*y#`Ww6lM z&^E~#zn4>0CLs00i0fi~UAR9AZ88tHQSLsp4cFPM&=;M^NqlOt)k~BVXJZ+c=F-ax zZEKGRo}#r;J^-Tf)uZ}8c^hT)=DVc~K^LKof8~pNWu1W^ie$-^IPIU!8hJq;TW*H7 z!Z)L0S-AdB=wUnD?0%UIBN>Q7+x+i4Ey&T6ry!|n7JwHp&R&v&4V=EYT?$3|ZEnr( znOmY%PTIR^K^>&6MS%+Mys=Vxa}0|om+hB2ws~+Ne-x@3r~c!v@Wc`NwX1PZE$Tt;thg9Bh7=Ye%iE9;%RLj}g0SQT$qN-v> zYs(+Me%l|V*VtQMfy3>_)(z9y!eRKm=FP3)f2ko?b1*riVUxrvtDH8(EIE?j$v7o} zchU6Px)le1SCom8V=-fir90lW$f}sJnFtNY>L&bNXH$oq2rkFbC8=#WSTk2x7(USl zt)|f79UEt2G9HPTz#@ws;}TVeTt>jP8OQ1I=9{0`K`4A ziq3U84OQ!Mm%&fTByOuIVP(8rRca$Jz0n2y{e)@Px7vC_Z;vy06x9&27Cv|0|0!{C z9%kJK1+Y1>MJANHyMg#uIT^RX1A1ekdzTgIePqUfGcO+x@K5UQSKRB}AU zwTP~m(R;he4`gNCqTbE#H_ZB<$roCjuq4#wh=phIWLv?4yk<$Scscya=?JSSw7u6K|A~>uc^?*Ntd8TS>8gLhrfg4xgEDO7T9f>*Fbqpylkv zU|d0DAR?-|y8CCZBKAjF=Nh-y1^05N>@|eWI+33RZZ5I`om4J!p^3P*a+KXSR4@tg zEN_g`nuhd3L$Y3cgD>^wC>Pf&{9ol3{+5V^_+yF1X$)9}kA{A*|GG!Usjrd8IU^-R5{J9S4S{_?InS$q7*WmBe5@P;3+ zcQ8%7hLMs4Jh!XvR>GMjrur$9rapu|&4VifNHt4ef>KyG(IO86l(oWjk<++3%9qYP z`#(TMBcsY#D{+xd4d1!1-Ml#19Iov`@|SD+5A?ZaMKGO0MTPq6XB&f@UJkMpzOQU*J{2P)|0JmkZ5=70pYNBDHJ(bCtMO@pL1Su8D~pf0p&> zP@j7C-B<_hF7C`FyLxsxN)ESyhKq@fTuLsiArAl-BCoPcrb`8sJZ^zKnqcp}4md{p zV?5blFzq-h#YV2JQSPdWRhWAE39|TE_C7NkOqUlQlOJDk$;OTWJB_w{K zv>g57p`P2Ho#+CE?_Q;!AXR!AoD4Fu1cC9~U|iaob1l8i0E-;xy8T9DvP>xnZsSC) zbGveud4mk-kI-P@*_#CSZ=vb^$7^^GSNR*oDgU}Od`$3e)|cP33r5S?3~~=IkwX>+ zW`BjTEFMi)kW)gHF^obehPF-2^e+Xd%(@!Bt{I5CnAFPg57VlEdqndvGCm+kIXh?u19Jkx38MKv8QF!sGIPoxENt){ zpE;GM)=LO*ZJ6b5x#xmCgJl;8tX^ktt#Dg9>KIsHM`TbLbW`-M+22U*+1Gl*;8@*5 ztXt66-fliL0az?`4sx5boZh>H+^za>OIw~>8_2Y)K{00XsN>y&;c|wT`%N&7RB!K} z3F2+Te{+RF1^;Y9T{rygw}XYxGaS*7Q;IHU*dCbi85dFZQ*YWwT*Z>>F6g&%UgOOk z^CEcPnth=mMR?4o(J?OD5q#N673MZ@@DaLRNJvDfW`}<1^6hnCj|-Dv$*%qesM*}9 zYe;|JnLk}PvG5}t5b=k-#WZQ#HFilhSeUoKLG;L{@grZtVOd%aYy zmwg43(qZ@ic{>mpiJOimzL-WpjCSEKrg_p$aG_zaf;=^g3fls8hfW##riNi6#Krm< z$23H2o8Srd#n~>BTg>N48Mqz8gXMRAVNR^NngjmV+noe8wFl`5X#>o_HjO5hy-(8S^E z$?*$dz5R#1>Td1(2P|#>OV3~^tz-aq-iW}#+3@7Tw_j&DJrT-rXC3CmluHq^BbJBz zAy}Ya#&#lsXosxXs>85zxGAjV!A zl9@*|#`UIHP_Sm^y>M>9KW}V$zyGL0$x&*N0^OPWZ}av2p+pVTFvlEuvgZNk*mfLf z(Rzs%WMgxj(wRyonE@%v9Qrvlt_!`fru|Ec?<8X;=E9#;TE>DHy%r2rXn5Z8f-q|QPo%-2m)f;69`cvct{**a4<=v|`*FSb$a^PrEb5l>q0ahIlx~i5QE04!+R^KFo)?+h&3y##m@S z(!WM&IdW>!MrH+I&2Z6OpZNd9L^HAq4M0ib`+Z>HXAXSytegF)6NU9Q-tl!Y-$%h96%pR)Zsl4*#_s!x|@pHWL;rF|H zCPA`^+E2LkPmq2iOGMPxrme9iP!!9Xgn=4o#6e4cD{e6U6e?3AEXq>&|p@fK=&hxsr{9yE~D*p)7)EZDuAIAEc zu`0vvYr6z@l0jYtVc;r1e^rYPlCKr8#6oMq32>8N$o=k1@2Zlm09awf(nfb`$|hKj z8GOy*8N9Iy%=}rjyJf$(*^V;4gtvN=IAQR69~tM=GmCNC#ud&v!R7}O#Q3h zG9>q3=b$9R!V>0T>zdqX(6xhw|vaflmV+82OT9iLRLRo33T@hCe;S; z8B@PP{=)Ts=)Tr4h=8bqBpH}1lvrJAtBlYLhB5i<=_o@zEc^utQFVLw*>rs@HkAlF zNe(IL!o+JnL-p>1ruUrbg_YfT=L(nI(ic8=+#eEGUVz8Y6?CGK)a7K-Aw#-M_QsED zE-84N@T{J6%!0Q8v{s8b_=|>fzc$%}KMQCY1JF<-n=E!GUAO@@8$#zh{CURl$Q8pB zyy&sMq%Jfpq$k}|CLDpzok1I-o=tH2jn-@36vv!d4qcz&m8lS`&BZ11e%IG0ZeM{R z&sX<9gW>}g(1RVE0qW@oGzAI6rYAsrCMLYGz7TmG+HZF9e|j-~P&O_xh^g$zTn6p7 z(Afu8%xY7_X{Mi+GxJGUyLk?PM8fD>@=7x47@VkzO?uz-(QmK=A(>bUC1nE7!2FW7 zpa}E1N0Rdhr&`Ynj#>ShV1CVfeOhe_2v(Ph6@M5T0Kb~;mpFh(R9x^0T~PncC%J)w z{-f8R$q#_m@O8P8ul`@U5sCffLg6KEMrLKHnk3Q&_!HA2lCVmIz9ekv0tY9qm-X8< zv;L5&wYos)Gk^O~v_&jAb|1y>m3}-&kDd%(*})yaE-Y>+RkaPH?z)2wl1XYVpA*Lr zO3cP!NW;8JBp+Sn@a-yH*Uo$~ABK``=(+U#I%t#P%Vl7CQ(hixK3tC9K>#-KD=B)Za3+qGC7$7Woo8KkkFCe74&@^;DagYclT#Hn-E3rj2dfk*eFBjlC;lFaT>zK4n zaNO^8hv(R^K0WT=;r9gPfkA)%XI$uk`pSy^oPaD^EmnvTawt55toJbfj@%4l^DonZp1228+WeMA;LK zVo`Umz)CoM%DFdvz$eNwk4j5w8ZHt3K7(E|Qbcornz^6JF&i(i& z4PtciCN^f8Eegwz#c8RRL(jikfu|2#w9bZEkv^NlT@7<4;IsIqCRSJ;2{Llo&3DzTf$0u1ib zCX0Sy$+@EAV2{acM*Uqa>sRtYq<;JMK(Cc z@eH=wUCJiHE=C4UgQp^Ou5y43)NW7IGd&N|WotvgaZj!I5l~(2pSFN(8?+gSgnPOk zlsl+~8%&JWmZ`FdIstFVH^`?T`s)vevH560u-(2DFK=ZB3AF8b)|e}jS9=}QnCn+% zepL@=ZfcIZcOrmYiT4qS0l-dfILQzJLXr68+6^STh_#0T<(tPlOUpo^T5Ek$>J*sV zulE-wPK|4Xr6=}@+8hf(Cx?hj3(!^CE^fy=N@Qu8U2M+J#;~-7FPTI!V z$b;{}^{495I}7rNF;YPlN(0mB$mP0?m$ysdlYK9BJOzOg{8d@{{hDg7BtGce0*xmI z=$S@!M_1RMAfZ2PVZ#Ur8r0mQfRcg!#|!v>TY*Q(R@OIv574<+Sr_+Yp}F7%hZ>k4=jJA1?e8V$^Rzz^gYPHq&1A`4G3*5k)wZ9(F`r zIUt@tzT3Y&|IaDbS3m!jrN5|V2(fV0Th#om&C+V;-Xbp3?mn%J#8MT%`|f$W{w#qX zb?XuDZ_}5E+}-2szsRlQleCg*c9aEjN~8LhX}soCuYNds+1wk78@o@h3$pH1GJu9H zad2r+%c`+-bAUISe5c);N)P~H1fo6iLwwo(Geq(SIlcWZ*5b=n4cXUEN!AN*AOvo0zS(4I`S#BwZFlmnzbvGioK>vzUN5L5 z3fav>?LRhurZhJmu+R5=f<0vXO1`WTLqZaL2!fHOhD5P&iZ*?T&h4qko@{+}TbMc- zovmR&vV(XUqizNTpZpe82G^v8YHlB8GK6pHN8y{-)~|NY;7JN8LHZXjY;Kx??EM$x zGSq1@Rkj8XMx98I_)p0korupi;8cS(0LnK(aHToc zGyjY{Jlv~uVyYfBzdOW5l=%tE_;7jie~=eDWPC!113V5H(cZN>4wEo~#zGGa+hK3_ zsN2u)vRNpmFsOCG89Oz(bI%a?__cl|2l%0qou+CQtrLs|UT_F5m7%va2N>m@*?NW~ zcTv5ZXt#di?tkog)^E^{M1Qt5mX8Yw`Jk7R03#lc-$b;=-jv73%a!=Wg8JiMXE~%r zpFWISZfqRlh1L#OgpFMsFdEwBiN!iZGuF-vFsPxNcQ(&l1 zYCBEqlF_*AnK-gB8;>U$m~a6;37!&chl{-OFDWrdB}uO8lQc!AQ={E}G(MvU(Rt-N z$ub;B8aV-`^V$U05O=mr$ZOg0K)*|pjM67bi_($yfSd{8hZWSVk0H2zrzs(THR~s} z^@^N*26Su&O?UK0yyTWX>14GJj|LLr3!(zrf70>X(pu^4pd<*|3f7wiaK&CPYV4&5 z%`AWx9U!vD@v`6@+*)3xrDPb9XyLr+mMyW!)f08RR0l$}LPNn~9h#W;_(=i0037p6 zyNy~5f-SU3rg)^3Q8O}bQr;W0rz`2nAC?Sr{TkVdD0^Y^VBJ!d$L21^G-R9s@ixp^ z#v)qU$hz%6gr`OLms^x-exE-~akY#8n^oHkQBAASn?;uYJSt*bh zwXqk5C!B*{*xLlJ3x81I_C#~I8rXI`J*t)xQQ+NS4(`sk0T<5qIY0O2ysBXNArV>_ z;e39YwfS*lTL$E9t%#(Y^=5E%o_z_jDh&h}0kmSC6ci|eyGxz$&1O5SGuH|C36HP$ z2PJowJ_vGTDhM_<%eO07h9^SVqJJH3Bb5v!O>hHrh{9ue+{iwrvuA4fcl=`!tDvoS zv9l7BdXoD&kK(tV3eNpJdD*l0jRLIsk!;t5ffZ1r`fJrC4ibGTnba#?5h5w!sSu7O$%&W~a#=5=6O3HB*fz z@U&!M5zO<&=uSbu&HL$V)~bqN+c<(_Rr+D_LGx<6%`4{O_M?LXyM)=!jEfi zNGy;kH;2qx`!ze-_vt*tJ-6aq86Zm|jxl*t`99Vz#KfKB$=RhKs9ZIdD+ykHN8jQF zd8TQ9XAp{JSjGSXO=FDP6?Q2A1Nkl;dwa|E7Lw+??o;emKe5GRVAw1gl zo?CZZSyA_^^~xpo<3a`Kye`{WN^+xskc!hW9c`@_*zveLj+tp224-)bZ8-#7R> z?e)((1=2h&D_XL!bI}#mS&R#07dY7#949C1Tta<-GMPQA6HR4@%&w3Eb(gxq4dHMDwLs4Q+Xo)mD z>_IZ!l+T(#(*leC?Ho^5z(s$eWn~GB-Wu0LvS(ov1^DJ!+a zIlA(mb^1dn1P@j22l+PbdP;blKHz^j9aGrAd5SFaC}paTeKK6DvisH04Wvz$s&LcX z*s>Huu>XX0#vMc*l+#_J$h^L3xaPstHOk|sB7Ab3CrqgL$LV4RotrQ2{=GOGt zSxKrGLO_svF1X(QF)f_$G+_G#EwQJ*aDBVKCZX)7c?ctQ;uHF#H4=Jx)%@H|8gxyY zBP%B%J;Z=uT#+9M^o2AO6L>$ zIrzG@8Dfa_r+~iJUnKAx+G>avQ8x+9xLFD_>vRq5_Hlw|k!L~Hxk2PFq?87Xlk7~- zwq>3BdAw)^Zm%C!l2~5-T*OT8Jf%jc#dQAaIFrEn;p;5F`CyU#povYv*<*PhyHrg1 zi_f;a`e^dTlv0|-^9=(a_nBR9D5jpBnsd7BdmIE!p_{aos1WPjE`L*q6)a(&!TV9Mg=3^P4^bBqFf@Q%*`Ly`0hgXpT*KM{I*lCi~zpuZtdO`mRNt>UFgSY zNB?I!GH{&iTjWsAhzpdFg0CFNwmNrK-Hyjr2$&(q#-{P?6ve6jJ{+X8TTM<$PRCU% zERJFbo5*wj7?Tl*uC%XOR6mz6;9;JW2wbfy7T{(Tw>hFiPE2-KI{0xr$1Ej8!v$3JkvT6nS_gi`I|6({UhEIW-DqTwhnRMw-=0h@nv zu!JJCXm`?!eQU$rVEsk{50EdETq1c)hGZ#W+!lRyj-KpWr70I&u=#H6Ev4oSeRv)h zY?U`V05;$bx&j9N{uec>Yk_hC`%fKVAf(%Spj}^{YDe&bms2t(>T}=$GQ$ELG$6U( z()VB&DdR7=7uzFi6P0kMSf56J(fIPJv$-YPg(M`0Pd%D40eUTzD!US7Qz8;N>tQ#6 zKo)aJsXv>RrF!;K!i(zWa4#1iDTg{FAO#+NFF3OU?uk_Z7`Cp5Ce3;IxREt~K>_B# zbqx)y*=8TaY=HhJu{W3NQ_djVZxlcO`cIgv@^RE1jdU(3EMu_m&(^<(=1|M01kEJ9 z{*wp^qufqpF6gyhxUK`(QzP@ZKD>_0Q*&;{e!EUzb`XW0!cz>^1b#v$%1&a>Xj2Sp zs4u3Wh5A_jmdmnCaQg}-ku*}JMsa6V==w2{U!T`3=MI6*K(pBS_|>B9bX{eMqL#8_hQcHT>!+Q-5TE`-^TE9gzgx*yA1 z_}qMpDx&OGqtJjP?Z&v(TrO!QjX>n?oN)(u$QHg#L4*09IrnOO%Z`3ohCfUt@_Hug zz%v&^Tb}q4Oh`t`l3LTgpEkgfg#X>!JK+yC+A=AX5J!Nn)MU9 z=VCQLC`Kx9V4`QM12B8dpiv}S7a2=QrFA*5M&c6Rk$;?~p%{YxqX*J%jdfqFuqLlr zTR(wDuYLRoSK1w{dtxg5YK7$vteles@l;C76q$oq=PGdb4Wa z9ZcMHVON4flZQI&cHdtDP1dL>g><4o+C-)rsIeUO;w&Wltlia^n+1!1jR;B)XrK9tZFP=!JEj7ciD3 z7D~sQYg{XhC=`ui++Ctx3HoTk)(eKR7}~AoKu*&vS_ao-0<>>(lwQQCwoJO<11U$dtYOoKgqL$Cyy&S)EJ??h>R|;83)0Zd+aT*^ z@?DCwe)=3t&C-AJ2Oaq~Xp?@P*~ULuI7R)$;4W)&X$|QRb8Sb>u}8dUhIu_wr{w+eF!Y%~ z-mVB{N{$>+BU;Vv>sqdQHbm7DEo+QF>jM!je7pN7`{ZMbfH#S}6A{6y6cB4Mf*b2U z?al(c7xe7i#oRp~dYdXD!hC)ReDWn}S=Dvsbs?O|;@FPrJ=tS}3HF*R|F!IFOX%2MerLR|EiDAwng0x*T zH3z2F+%R8yGBSxg5*rR|2vIKOf= zDRdn>w4O{$?X|K03n5VBW+MPMh<0Y4P6mtZq1pM|a6kAo$szzU)22OQ#lcCRl=0oX zCIZZ~`xb<*8-Q(ArLCTpn5(Yx0>!Mv1T<|Gx1EJt&!k|tA2n=Lh^7UtPZ_M6z7I}$ znPn&erQ6|ga8V1S`$Eh!3>}C2QZDDvFr&6d9`|1GdreYgzTRB3H1&U4n;ZQCu)sB5 zN%}!1td@l9Ts#Wujv>5$0zZ>DuOjx-8_i%v-3^?`3|kcknHTf5V;ndCj-{<5ygiAe zxIb6PaqzytKY@9;Xr23uK3i83jg^fr8Pbh+OwEgDFOQYN4`<(`v$V0Vt`}}#84pyR z4RL+s{R6PTAx>BeJ|)5f)f-pM#zR!G7Ey?$vP+Q`f{QxeC=LIns6a8*AS>qFP9mK| zFn8aob>6qtcO0a^`oaM(#sL4RT)^bYOZr-HDH2qXC&j~eFF=hA+48XXtO9yzhP3Fj zZ;mggIKCor?0{-I_9+QXHn?5_g1?7d$J6Jslz-C?zrH5lUEdL4UH4kCt54s?PBfE5 zW992;^QVtKzn0NQc3&P?)o0lx=z0qrO6q!R!0&}a>|WKf#GmV!wD_b_CBmyDhtr}G zjUk6JK8gMV32gVEjk8AXivgH`f6eL6#Y4)6m4=Q|PFfPW-QapH(p`;|r8O_U?`ZK( z28n4M1^Pox&sU^jnLPIIDw8loC|oz3CZrpcbQriLqshs=5er4^I`g$XUpqW{#3koC zAssR;f{+Kh_&aX7b6 zj8NLCN5RO6?NIfXCr2Ud%=&Z+;4%?@bMJi%7C3?d{giD9EpE~;N1G)MYq;v-;U}m!-R= zOAP^BAD%=9iyB~(#mduvUkf$iIDJpQwcwl=ogI(Hpdz+cN|pOAQohjDp*sSgh&@Z}RG*}aa&ddjR8fnFia!BmzQK@Ar5(#N&0^z+= zbAWkD)0P=2>&V{}KE0lTK~YN$XMw#sHAgsc2SQ`{zi{a;IGV44QIy{v6I+0S z%I?ds@n1;!Eb!;>W|0xIbW=WLnL=gWFcZP5Z+1oo9fOy}9c}_^?wxnjzbop9NTW1U zJ1NYuh87AW%OHJq!{dYvUs}TG&92kZ0EdP?00=iNL5OP3f@mA*>)lNfGsrvcR%N^0 zB-u$fnS%qiX=zf}c@3x+NVp^7^U!@GVU7K~0vV{3Kd8t)%nlwyJ4}A}`Z+hCJgqq+unF?5_57|L99=5uJ6yYmN z=szp7DHxKFG?Np24phZlRo^EkO~D7<%<$%V)_LdXJlj>@p2BPM#gyvITSIrX9sBbNdH)(3G9``kV$GFoP{d;V7Ysdr;x#V_+ zDKkF26ij>N%IiC%kR?9heeYF2c3VNp%H{xFnUB0u^7DREihb=mFli_;8xhdODEw{w z5Jkfm$w&QviyeH=fo0pbg*YPzDWyKU#iCry>8;BUXQKx$FSZ{oa^UsWcz|pggvpEO zO@ys_UPrMTMAViShXbx%6?z6?C_Hrfuj_Z~2Oy_(aSL)vUGg8}9Qk%i?**t{S2Mj( zb&RbC!6$1W@4J$^GX?gk4a_qQ{@Ys!k@@+f(oX@PoI2Eg)v_W7BEaA)0u|f$T3?23 z_wLJ+*m3eM?l?bDuB|Z*jX+k#-2pB0cA?{Y88Pvo`$byQJq711R5OmvLeA@tW}4eI z^IAkiLmKJRu|RblWe|WGq{Wwdt=%`bkyP0BdTAGgPnTcw8X6YbQ(K|EZDUB!8N@S? zQek?O0@RT&z3dC@<@ZvZF1av6L*!oXDXW3Y1ALP%U`NK4O_1!yr13A7`hUzUKq0!4 z&s)wQpsr;1xNr<)(!#XMtw>UC?+Z{H?}0=P;PUh=> z&9XsA;ULId(PHIr`PHbtaVPAKnQ8F0otv762!O>g_LxB4brAJ|tY~;Uz1kAo#=I<< zG|5<5{`&d3($^s6*Gb0wyV(I5C^|?GXo!IC9I&R17k)LY{d-4HBp|SeHS)SpdbPa- z$cjs}=G!ARKOibGL}+8VYv)HY#6@(z7yA0OP@E@jXh~z{0-q_hwa>@8DDq^#>Q69;ERlf@W(k-<#?70IC7^bkq;!R|3{ zd%&MkK z1P#`0KSV>{N3)DIddv&qebF|7AT)qbK2Zt5P6lur!69WnvEXo{(q;VGmODFKY)O%u zJjH5!1Y<)JS5cdva(;t}?16{P%98O`hT0L)i6wjHS|eQLW40Ji@Y1hm^jJS8Wgwt| z%rG6oeI@hsB)nCSZ4IbMZ>xg*Co*@Ri-m2Cb>{6;)Y-Il+L>g2}ezGkgqBy*0yTANEXeR*uYAzm{vaAYC)EKf} zXP-4h_loKjMz<|9Y~IU1p~N8ink7|KVSF3D-8u~)qfgf%67FkgD&IO20qszr2ARK1 zgcz10J~(w~Aaa18k7pym5m9sfOY{PyA^$8t5X!~&r9#hV_f(PW4^@Z82pPEk#_k2R zUI$&Gut#anskmH~;d!zHb_;j*W7@eXq|bHjNXCol5D{$9Yv_`P@T(s>K5MtPp~Abj z4LAI&KQva68%#qQ^jJ^c-tWT;Df^+Vl3BV$vmQqq%~kh3&7Ehs1Y}Z2jw}yGm9*Yc$?0_x}pqA}I|9u}?%(et-g>7Ev^!W42^#j%8C-=5IHgsEIx; zwg>k+T92`ufX5S&1jG*vc1)5olTDz5nmP3M3&Q|IFwDLl(ZK>`#WM?Jrp!;QV*JW& zm7_~X0_Xkj=U4h<-nqWr!?q=oRH7iPu(7)EdUaxODI{!>^ z#!qWIInvX9darnAJ#tT!!zk|@Q$$xP19K>VLGp3^-P3Y z9emxsDH8UyC$k5kHV?=#btbx3V2jx+3yhk3jzvTMEMFfu*01;WkQO9&Jib!8_x>eZ zZxQn=;0a2Gg{N;LX30W~fsM{IGVvGjwv&gwiaWj|+XUY;otM^fyp%vI`qF&Fi;umz zTn7~el>^=Tp=N`?3}fw~KyEPE0!nkDP7*7|{_bPgE27qh29o2O^urfwp~Cus6nE)u zH1tofuG%pbf}q}Wa2DiuLl zJ{aKOOZ7~qLQ{M6QF+muc2t)%7bTAA)-Y|#d7bkoCxoQlsX=}%zoiMjM37r)u2=m= z=fO)hQA{mVgxzvMo?QCoIx4n@lm8`?fgFmyCY0yRO}x{^CTs{8gfvur;jF?h1vVRfyUZy$HfKR8jH|@wn&RDy3J)z}!cGb_s*k zffiomT4fDgyV#GOh-cW|3OvITVWBTaz#CjYFrRfITAsJu?1L5lI*Ojmv^9Dwz?n6$ zCy8Ayr;lBsK!p`-5ztsM>2aCPlD511OVNV)$BqbcogT$x8zLrMm*@I=lpF}$`RL&% z>q_WGaWZkGrf%G_f|RwvPNR&);=*@fCGCOW0l>Eg81IFU7}yeAO|%6 zc#GjeSGyoc_|d^iGgr{~kx~K|da_;tAShQE@+$9Y#6f39M`Gw`2W;`th0;*XVPpZ; zyzA0L@{KFa6mQa;61GvWW@7G9InfMng`Y!pEpt*znG6z9^xr}ckHT-Du*KdbcdI@4 z?H{+>7{>*^uU82b*#{XiE@LF+P$YM*)3O-JA`~r#>^y@vE^n@kz8;f(2ZeTy+yDPs zx)OM%|Nrl7(HG5;a*VR&jPEzqls4q1azr{@m2XM1uh3#MLw%idMLJxKauw2nW{%2L zp+tz8%rVC17#lYJZ{Oel@!0nHJU++!{W{+7*X#LueLnBkoc_XQvyOFnigHm+$n5wr zj_<+E>z|H%YrXgC(NFo%bPv(1O1jsFYH+!(yYMjs=tA%rMulmvNL^lcyB8Vr0bN*w zF6=~yjju{c0W>)G`iYVAiW+7={#kq&Q{4>6TKBE?T3I%n8;@!llf} z%GP|TnU7BMzbP4Y*MlT_Ze2W>uW;Daf|Tz<%AfhD&!0EGGI~mj|M$h_jD8c%_hk+h zz8xC+;iv=UCz#R?>TMPUXsAIriWM-nnq6P!UNPE*F_5)as>8aoy(}K~ z$3LNyeC^vSi*HM-D}=Xf|u;OC^xsQ)1W^E+!u8rC!a! zz|+Vh{;ej@NT;m7%E-`>%erfIl)>5=h9y-~ZCX8*Zfp@3!K0lmx-Kk6Y+q7=TyNwk zJ-GYg2lU4lWe@7h3M+j(%5QOiL|RK3oRung(FMgxLcjS#kG?LYyQ^2$qXmg?s%>^$ z%wl`|Ib)XktML%|sCXXLW{+22qK7lvJqsr};oTPsc9FZ{tP;lSX8c*wHp14i4E1^w zKU;Xs;l*LzsU{mumlCM(w#Z>`t#cKhLx6r%ZcdXJ|IWty*XX?k?3H)zuNbYx7#Jpy zF`5IjD(QSuMw(7t(Y^)g%j?Bdj=S)@#AS*epw|yY?g({{GKl_A5zGv6=X*6@?T^ndzcnu{y&k!**2K?MqSJl)mZYUu;e!Sj`5x_T zH!sg-=YEq+N||AWZwb)gw1VhA?*DpQIQEw$m8;B1|NFkxV#vJ|BYECSYx!kBi9UG$ z5On$JRge3t07*;XIs5iU+r!FFS637~E0<RJ%^ zak;>Kec-~-^EY+T#v@r@=YqBRe-v9^p+;-A?YSg=ZFsC{Vpr#lGpA@xaOB|* znUjk_*}AhBwVEQQAo#=riSeK)5zGIkEbSJOWcSY6c_?!?(z)|M*<}7peB~IXY}?P( zDQh9a3JjHBS2+u!T&iW6b>py`9y0CofzyH@hh$a$#IC8UNTnGWHvs1L_Jx{+h&Kub zyzUo8l)(Km)+V+Q>RRl79{4by|Gd%TN+8o(h|YS`Spbx+3zZB#lQd#(j%+EDk>E~l zl!yh5l7Z9Gg+`sQ1{5R(9W#9&ofP!lnxoPoT0!3f$SkfgEgnAf4pO?mCit~dLtO@O zadr+SaYHT?n`GY5@@nQlieFGLJmg2mluR$bf?A)&H*&U~lNny!Y+L`sCK9WPy_QI7 zLRuK^(N5z8Y1KgJDrLi}I=o$v7Q1f>yh)p3Wh~_Wc>Z&LYIHm%@s(;kpLS^?wi9U~ zw<`yqbhf_qK4x_MqChnot94FZ-gyouzD{6NY2FX5zAZj6LY@x#Uvrm)q;>H@XmJA) z!Ic@0NJ_4^?jFhfhMb>Ww|N1-vqCdm_8}DvBPqT1zhyFUNk5)lRP!5g<0Gp$2Q~)V zpF@=vWUTOK@sAn@Ep? zHN_;NCkOfkE7_qw9+8?XplyF}SCHskQ{F$P*-!brEPIQppUU>_rJVl3F8EFf;L55{ zSvy&>0Ro$;Gzc^w8`iBJicKvTPTdJM?I?D>)K+ayW)~JY1)w9JE_iKJRKG` zXKdz7Yao_xezMV2F8q@dT)niO0QL`rIbb1|0Qc=JWk!nImsE2t2`%13S{3%ZpFOlKl5a+t6uuhvP>i(pacty)YEc;{?6=HFkMcee3n8g>u*QzabMN zg{)bJa8n&#MRHxN%Vu~ln*&*7m1^BBO1xXknq|wP>um?t+_W^CalN$^n?n=}EYHM} zV*7SD>>(D?MhgqXLheNZg=pkHpfy`>9$MT22maGoT&>A?@`Wkc|0b(C-as>pqBkeI zzs`0WttdfayfX2lC3n9f zkH}tl&oXDp8Uja@hITQ>hSjJ`aDmBlAt$jNUYXW1E8f?}Cb5r&Qo!%$bZ|g5>Eja( zYd;Upkj3FG6J)+O4AMBPq<~HPYzA4Uey-eGzuKLtrkRC<|M2o+iUAUD>mDm=#{#DbVQoc&*oQ)xSku!P>8*Q^HD0rt^7dY|n3!|n}JE0O)QHksz8O*GJ&gbocSShA)@2~tl*g~SV!CIEca)xR#y?MY!K4E%cI;b z$vF?0@q|7q-~W+#f+9PuP-8n`!GYZPDn3;y&}xzOG$X@4m=h2RiJybkv95AvdLSlj zD2W{(5YDWf7fo4j4Ynj$JDP@?b4Bh^O$YdMFTREoKfuzDa!y+{#x-9|HF-9K5o@1; zS}Zw#MKw96mOP8Ao)f(g@ky6v35f+nSwd$;EdNIz@BldrEqh(?!FCBMK3zJOY{%Oz zk1mQRQ;ou@*GWf!k61BG$iR?tx4(l-E70cR33#1Jm~V+~&O_5sS3YQmtf3K*0yu;g zOUmU2nwpS%5?^K5?FEy@mKs zcP3crq7}{L()vJ^c(|Wyjz7K-Y}AsE?-RhJ8zBR;Pw^4N&Jm8bSD!$vP56V$D?JFb{7mo{pqJAV^CA~De_4(G@JjM6cH`8L>o znzEd-ko!i{BF{XnjwCW*E(cPXwV3*=X#r0dBX6&fwhjfR#+St%V~eKX=)i)#NP0-n zX@V6{kO*Yk%kvOIw%M2t`)Ot* z@xDf|BJZ1-`R;JAf*?jSDsg} zxCNmapQlvh6--e>zAYK|aQ56>?w#&YI4P{~3+x8)32p4UQkoeV)0iL7qHVHTdhAY2 ze7-}ewhj+WDp-k4e!=%^67y%=7bURhLeu@ui`o=s{$CJRalVTD1P^6Q(Evh+#K9CAe+;|`& zh1U9#7kqiaO$OB*2WpmUMuI^vv4m0@JN+l!`2AFAZ$!*$UKw87gk5?B7t^`YWpRnl zR9n=P?Iv*49Zxt|jiJI!mLxEdjP1YGQ!V3)Z!tj7WmDZ?dM-%9bzfHvVOG}iw$)of z0|~$cggjVwyjCgkjb}IA>T&zczI)W=ZoDVK3DmwF&D*d$-ap*zgP_c^+D3_D3Kb4Y zp#{a$9Ct$GUdz6v(`lo?uDm$YhH4H5`p9swSdy?rY5C{5oOQ~TG_yF10q&?C+WyES z0H?Q*H~R8Fpm~YqHy{nP<8@rg%&2P6*p*&d5FT9vBAoG)MPE2JRpZOt^H5zQ>(4tp zxvmNg=H`{{-#m)GAXVz}j8oNTmvhbsr|=R(>a)8Rya5Vr%T={secPLAqer^(&{uayU8pW!2-JH3NP zR$SW~%mXXq%d(HLB~x&v1KyhNvQJD)9>KM^3?so%xB4>6gM0!&%MMngk@&=G=H$HO zWn74nR=)Q!OI-ATcknJj;$>V*^Q^w?hPT5@WhR@qEjYLx{;Xq%8mOW7|807Vw>p+C zi?u~wF-tQ(W{3x!yYyC?9K=n#v9>yc{%}0X7Xy^rx5t{4MobSdx2XBod$iUgblOo@ zAV#BxDsshW!d{{161d7flb;LQv*e0zFpsIUyYG?nvLV!gCw91DEO42Y;BQVu_m+RQgx)<}PWaB{^l?^~9IK$1lI> z=RAJ}hx>kNdSXL%Y5WcwCrd9$e!yFMP!yw${+V(NXNz5G7)m90fgYfH*P$^8pLA6t z$$=esexf{nn#+-##OWFUx{>R@uPJ<5NemUx4n4R#8-E#B>gc2S&Ld|Q*na>qbL&HI z^MJkI3Li`2va4q$Cqc-cX53Hsi48*2XA=YYv_k-Y z%X_h1OY6<`jNZQ6!CfG={O;s|uZLWHlX#{7Qx7%Y`p}$ZG1GdZM-?+HnXWsfr@Tg! zqfU<#K#c9_+9qf8XNSJ)=(9f}qR|_5paNYC07Z&I!<{W)E?6ay?^tswp_)r#TSf0H zv74BGTJ>kf1nCcY zm#*m##20n@+>`*hdd)_(ht{*^3LO$znLq8eaBW zFK{9^y-5~{Z&v%Z!yk*oFAea z3o8mX7pd&zI#i&1o3X~udq*Z${9hyqB1$Ys#L)sc4= zSTKIqSekl6?YO9sVffD2Bc}$1fL-aokkBc>9VkA>TNbrXsL!wG;UoU~!8PC%rBAzMQ=TS-CeZ9IZl$Pa+Tk7-E{TmEJR z)AnFAGz3{8@y3M71eCd=hKr)c_va0m-A8Vr?x!3&x4P;7U(yFuC`$z)gY9D%!4Q|H zXEQ0ff3;~(i%=vIe`SI7D75H%Q$F>IeLLK`5j1XjfGbMo+bP^Po4W*Tjh689QMVT` z%|tn+7I1b8=$et)w-PaLbxSYFiLJ#S;X8kiB!;2)nWGfxFwFuv zH7&sfwQ5;yArP7UM3SYe^|nZzHI%sqeL&8yZBJC)sQ)OCH{yuxZpLT1UDaAM46U9) z%TtRW`0+S6nOyx_ylAna$VSy}LhEve*5xtF!Ff@_s`I@FqWxCr=BlFh-vr%XnvZId z-2xG9%5hcz_an&usI5-|Dw7P;jFMA3HzfCG1H~%%LPDeL>m?AbNeux8o%S>-Q8`Y(#nlAW^V0bi5{<~l-Cbc_j{%P5Y2m)_4 zL~Xn@upRFECH3!yOKbGfrac_h=8TL73p=!B7{VOgBVyOIN7$p8v51qQ8(E z8~zfGC&bY1^3@e>NYhUAMxdl>wA+~!Jduc2glYKZ${|`IC099Wf<;o-UPR_@jnQnm zEGmQ#xF54btpL_vWq>s4-SDEikBt{sr}Sja2?xZ(iG?XX8pPwf7s}m!FNppe^no~c zQgC}V^BqQT0#<_MGEY=2f_~^h=E=`a*b&OczYyh9q`;t4gu8XuJ6ax!&9s5w$@cE5 z?WbYeH4Q;;QOa4ZiV>QYifS@FG4suXee$4VISMtn({?b~6YU5L&H z8^gB($0L3!S@%hXViO3BO#Flx$e3%@=Y>&l9f-zM3G_d~ z4P|pG_L$q>8@+Tin;kz*A@o>eLL*Uyo@?jOq}m-{bYbnMQSb}yWR7B!@;9b6EnF1q zy)Vp2uW*MyH=nxseajS@@;m=^!}*(O_B*|Q3@P>C*$uT0<$ z37D*dlVSn&R)@WNh+GP#$p7H&_1mrILQuTip|)0fHG>XwSit#-G1MRShD3&61@l z#18=Y6-Yku3iS>Z1qy;XkUvG0uNm&Ww(o~Q@U~DFX`ihoE4PI8qZ~^aw*hH^e+^w) zb|I!gj|pGvb*c?Co0A@M#3ujKjr6k}1GDm?|G3C|HC@eS1|@a585UF}^-PHU2R798 z3U+K~%2P2eOBb4sWtTiok_|L0c$`%ITZ~X=)##adQaSB2!eN3OSW9#R0Jq4>@1u2_ z>(;@DS^2^Fb#4_%)-bdG17GN<8mL_v?7m(X(J--MM=ewSnz^#|xa1pdQ1;^h-;$`H zPBRa8_O7%(Yu)Rj=e^v{DuZ3rbx}*NUi7a2lDxC=Rn$Im$&-uV$;a`B3yvWHcVcu5U8LwH=h{;`4H=GPzZ#;tq08q6Fmcn2 z(`QFag6#6Q2RXti)^X~}&L6Bv7*Pf#3g6={TojY@RD8W_z6sG~VR&q=jtDVy3C6%Q zFcKMhdcC}}RYh=j0q0kPV|!6C`%gbt#U2Wyi961xtks|Y7W%R#h zCs%XbkdZMuXoe=p2ns@doZcFL?%BGai=Q00+^gH89Y5CQ;N4wm{Oh-Iz|0x#)A_z} zPJLP0cSg?~=14upV$ZF4$1KpY#=TCg@rBVj38O2?OSq`6X`K6g<>OU{Giu0l(duXh zm%&>F2%yYvdils@Tt>hGYhTJfw9@f>-wZ6`3T_0LyiX&=m&X(YiyN=L)@)Oaelt9a zLVrM@KM+o*y|_o0u={D^CvdAF#3Z2^2D4|buS#8rz#3t@1zK|!7i=)XrDQ>H1PBqw YCa>F>6>cv1Y%VqGHq1J=ny88V9~6eQzyJUM literal 0 HcmV?d00001 From a9a810a2b2a35c0c693300efcd365d5862fcbaf2 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 28 Jan 2021 13:22:20 +0200 Subject: [PATCH 290/351] Add block type to MineJSON (#1464) --- .../consensus/model/testapi/test_consensus.go | 16 +++++++++++- .../reachability_stretch_test.go | 2 +- domain/consensus/test_consensus.go | 26 ++++++++++++++++--- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index ba2bfd1c4..a51991455 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -8,6 +8,20 @@ import ( "io" ) +// MineJSONBlockType indicates which type of blocks MineJSON mines +type MineJSONBlockType int + +const ( + // MineJSONBlockTypeUTXOValidBlock indicates for MineJSON to mine valid blocks. + MineJSONBlockTypeUTXOValidBlock MineJSONBlockType = iota + + // MineJSONBlockTypeUTXOInvalidBlock indicates for MineJSON to mine UTXO invalid blocks. + MineJSONBlockTypeUTXOInvalidBlock + + // MineJSONBlockTypeUTXOInvalidHeader indicates for MineJSON to mine UTXO invalid headers. + MineJSONBlockTypeUTXOInvalidHeader +) + // TestConsensus wraps the Consensus interface with some methods that are needed by tests only type TestConsensus interface { externalapi.Consensus @@ -33,7 +47,7 @@ type TestConsensus interface { AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) - MineJSON(r io.Reader) (tips []*externalapi.DomainHash, err error) + MineJSON(r io.Reader, blockType MineJSONBlockType) (tips []*externalapi.DomainHash, err error) DiscardAllStores() AcceptanceDataStore() model.AcceptanceDataStore diff --git a/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go b/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go index 48592bcf3..fa5ff2067 100644 --- a/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go +++ b/domain/consensus/processes/reachabilitymanager/reachability_stretch_test.go @@ -54,7 +54,7 @@ func buildJsonDAG(t *testing.T, tc testapi.TestConsensus, attackJson bool) (tips } defer gzipReader.Close() - tips, err = tc.MineJSON(gzipReader) + tips, err = tc.MineJSON(gzipReader, testapi.MineJSONBlockTypeUTXOInvalidHeader) if err != nil { t.Fatal(err) } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index 48f93166c..c0879e630 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -106,7 +106,7 @@ func (tc *testConsensus) AddUTXOInvalidBlock(parentHashes []*externalapi.DomainH return consensushashing.BlockHash(block), blockInsertionResult, nil } -func (tc *testConsensus) MineJSON(r io.Reader) (tips []*externalapi.DomainHash, err error) { +func (tc *testConsensus) MineJSON(r io.Reader, blockType testapi.MineJSONBlockType) (tips []*externalapi.DomainHash, err error) { // jsonBlock is a json representation of a block in mine format type jsonBlock struct { ID string `json:"id"` @@ -145,10 +145,28 @@ func (tc *testConsensus) MineJSON(r io.Reader) (tips []*externalapi.DomainHash, } delete(tipSet, *parentHashes[i]) } - blockHash, _, err := tc.AddUTXOInvalidHeader(parentHashes) - if err != nil { - return nil, err + + var blockHash *externalapi.DomainHash + switch blockType { + case testapi.MineJSONBlockTypeUTXOValidBlock: + blockHash, _, err = tc.AddBlock(parentHashes, nil, nil) + if err != nil { + return nil, err + } + case testapi.MineJSONBlockTypeUTXOInvalidBlock: + blockHash, _, err = tc.AddUTXOInvalidBlock(parentHashes) + if err != nil { + return nil, err + } + case testapi.MineJSONBlockTypeUTXOInvalidHeader: + blockHash, _, err = tc.AddUTXOInvalidHeader(parentHashes) + if err != nil { + return nil, err + } + default: + return nil, errors.Errorf("unknwon block type %v", blockType) } + parentsMap[block.ID] = blockHash tipSet[*blockHash] = blockHash } From 13ffa5093cfce232827e5d612312f011a3b5ceba Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 28 Jan 2021 13:33:37 +0200 Subject: [PATCH 291/351] Increase the waiting for error timeout (#1465) --- app/protocol/flows/testing/handle_relay_invs_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 3ebb29199..0a84c484f 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -1411,8 +1411,8 @@ func TestHandleRelayInvs(t *testing.T) { select { case err := <-errChan: checkFlowError(t, err, test.expectsProtocolError, test.expectsBan, test.expectsErrToContain) - case <-time.After(time.Second): - t.Fatalf("waiting for error timed out after %s", time.Second) + case <-time.After(10 * time.Second): + t.Fatalf("waiting for error timed out after %s", 10*time.Second) } } From 7c1495ba65bbd7eb624e2e03521602635fc96aeb Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 28 Jan 2021 19:43:04 +0200 Subject: [PATCH 292/351] Force stop gRPC servers after a short timeout (#1463) * Force stop gRPC servers after a short timeout. * Use spawn instead of go. --- .../netadapter/server/grpcserver/grpc_server.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go index 3a5dd8737..9a303fe24 100644 --- a/infrastructure/network/netadapter/server/grpcserver/grpc_server.go +++ b/infrastructure/network/netadapter/server/grpcserver/grpc_server.go @@ -9,6 +9,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/peer" "net" + "time" ) type gRPCServer struct { @@ -61,7 +62,20 @@ func (s *gRPCServer) listenOn(listenAddr string) error { } func (s *gRPCServer) Stop() error { - s.server.GracefulStop() + const stopTimeout = 2 * time.Second + + stopChan := make(chan interface{}) + spawn("gRPCServer.Stop", func() { + s.server.GracefulStop() + close(stopChan) + }) + + select { + case <-stopChan: + case <-time.After(stopTimeout): + log.Warnf("Could not gracefully stop %s: timed out after %s", s.name, stopTimeout) + s.server.Stop() + } return nil } From 65e149b2bbae52d8ce9480dad45d91d82398b1ca Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Fri, 29 Jan 2021 09:10:21 +0200 Subject: [PATCH 293/351] In kaspaminer, don't crash on submitBlock timeout (#1462) * In kaspaminer, don't crash on submitBlock timeout. * Make timeout messages have a log level of Warn. * Wait for a second after receiving a reject for IBD. Co-authored-by: Elichai Turkel --- cmd/kaspaminer/mineloop.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 718724d15..594f9811e 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -117,8 +117,14 @@ func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error rejectReason, err := client.SubmitBlock(block) if err != nil { + if nativeerrors.Is(err, router.ErrTimeout) { + log.Warnf("Got timeout while submitting block %s to %s: %s", blockHash, client.Address(), err) + return nil + } if rejectReason == appmessage.RejectReasonIsInIBD { - log.Warnf("Block %s was rejected because the node is in IBD", blockHash) + const waitTime = 1 * time.Second + log.Warnf("Block %s was rejected because the node is in IBD. Waiting for %s", blockHash, waitTime) + time.Sleep(waitTime) return nil } return errors.Errorf("Error submitting block %s to %s: %s", blockHash, client.Address(), err) @@ -152,7 +158,7 @@ func templatesLoop(client *minerClient, miningAddr util.Address, getBlockTemplate := func() { template, err := client.GetBlockTemplate(miningAddr.String()) if nativeerrors.Is(err, router.ErrTimeout) { - log.Infof("Got timeout while requesting block template from %s", client.Address()) + log.Warnf("Got timeout while requesting block template from %s: %s", client.Address(), err) return } else if err != nil { errChan <- errors.Errorf("Error getting block template from %s: %s", client.Address(), err) From 669a9ab4c31367cf4eb18bfbc680ea2619c86aec Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 1 Feb 2021 10:51:18 +0200 Subject: [PATCH 294/351] Ban by IP (#1471) * Ban by IP * Fix panic * Fix error format * Remove failed addresses Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/protocol/flowcontext/errors.go | 2 +- .../flows/handshake/receiveversion.go | 2 +- .../flows/testing/handle_relay_invs_test.go | 4 +- app/protocol/protocol.go | 6 +- domain/consensus/finality_test.go | 4 +- .../blockvalidator/block_header_in_context.go | 17 +++++ .../network/addressmanager/addressmanager.go | 63 ++++++++++--------- .../addressmanager/addressrandomize.go | 2 +- .../addressmanager/localaddressmanager.go | 4 +- .../network/connmanager/connmanager.go | 25 +++++++- 10 files changed, 85 insertions(+), 44 deletions(-) diff --git a/app/protocol/flowcontext/errors.go b/app/protocol/flowcontext/errors.go index 0b1deafc1..8445fdae0 100644 --- a/app/protocol/flowcontext/errors.go +++ b/app/protocol/flowcontext/errors.go @@ -22,7 +22,7 @@ func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32, panic(err) } - log.Errorf("error from %s: %+v", flowName, err) + log.Errorf("error from %s: %s", flowName, err) } if atomic.AddUint32(isStopping, 1) == 1 { diff --git a/app/protocol/flows/handshake/receiveversion.go b/app/protocol/flows/handshake/receiveversion.go index fc2c5a87b..7cd3eb70b 100644 --- a/app/protocol/flows/handshake/receiveversion.go +++ b/app/protocol/flows/handshake/receiveversion.go @@ -60,7 +60,7 @@ func (flow *receiveVersionFlow) start() (*appmessage.NetAddress, error) { } if !allowSelfConnections && flow.NetAdapter().ID().IsEqual(msgVersion.ID) { - return nil, protocolerrors.New(true, "connected to self") + return nil, protocolerrors.New(false, "connected to self") } // Disconnect and ban peers from a different network diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 0a84c484f..7e506e6bd 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -1421,7 +1421,7 @@ func TestHandleRelayInvs(t *testing.T) { if !test.expectsIBDToFinish { t.Fatalf("IBD unexpecetedly finished") } - case <-time.After(time.Second): + case <-time.After(10 * time.Second): if test.expectsIBDToFinish { t.Fatalf("IBD didn't finished after %d", time.Second) } @@ -1436,7 +1436,7 @@ func TestHandleRelayInvs(t *testing.T) { if !errors.Is(err, router.ErrRouteClosed) { t.Fatalf("unexpected error %+v", err) } - case <-time.After(time.Second): + case <-time.After(10 * time.Second): t.Fatalf("waiting for flow to finish timed out after %s", time.Second) } } diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 2678aff5d..605586db1 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -78,11 +78,7 @@ func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection if !m.context.Config().DisableBanning && protocolErr.ShouldBan { log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause) - err := m.context.ConnectionManager().Ban(netConnection) - if err != nil && !errors.Is(err, addressmanager.ErrAddressNotFound) { - panic(err) - } - + m.context.ConnectionManager().Ban(netConnection) err = outgoingRoute.Enqueue(appmessage.NewMsgReject(protocolErr.Error())) if err != nil && !errors.Is(err, routerpkg.ErrRouteClosed) { panic(err) diff --git a/domain/consensus/finality_test.go b/domain/consensus/finality_test.go index ff1547e59..80a8fc3c0 100644 --- a/domain/consensus/finality_test.go +++ b/domain/consensus/finality_test.go @@ -232,12 +232,12 @@ func TestBoundedMergeDepth(t *testing.T) { } factory := NewFactory() - consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, false, "BoundedMergeTestBuild") + consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, false, "TestBoundedMergeTestBuild") if err != nil { t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) } - consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, false, "BoundedMergeTestReal") + consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, false, "TestBoundedMergeTestReal") if err != nil { t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err) } diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index 3ce16882f..ca595693c 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -1,6 +1,8 @@ package blockvalidator import ( + "fmt" + "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" @@ -29,6 +31,21 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa if err != nil { return err } + + var logErr error + log.Debug(logger.NewLogClosure(func() string { + var ghostdagData *model.BlockGHOSTDAGData + ghostdagData, logErr = v.ghostdagDataStore.Get(v.databaseContext, blockHash) + if err != nil { + return "" + } + + return fmt.Sprintf("block %s blue score is %d", blockHash, ghostdagData.BlueScore()) + })) + + if logErr != nil { + return logErr + } } err = v.validateMedianTime(header) diff --git a/infrastructure/network/addressmanager/addressmanager.go b/infrastructure/network/addressmanager/addressmanager.go index 4371cc20c..adfe8f887 100644 --- a/infrastructure/network/addressmanager/addressmanager.go +++ b/infrastructure/network/addressmanager/addressmanager.go @@ -12,16 +12,22 @@ import ( "github.com/pkg/errors" ) -// AddressRandomizer is the interface for the randomizer needed for the AddressManager. -type AddressRandomizer interface { +// addressRandomizer is the interface for the randomizer needed for the AddressManager. +type addressRandomizer interface { RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress } -// AddressKey represents a pair of IP and port, the IP is always in V6 representation -type AddressKey struct { +// addressKey represents a pair of IP and port, the IP is always in V6 representation +type addressKey struct { port uint16 - address [net.IPv6len]byte + address ipv6 +} + +type ipv6 [net.IPv6len]byte + +func (i ipv6) equal(other ipv6) bool { + return i == other } // ErrAddressNotFound is an error returned from some functions when a @@ -29,16 +35,16 @@ type AddressKey struct { var ErrAddressNotFound = errors.New("address not found") // NetAddressKey returns a key of the ip address to use it in maps. -func netAddressKey(netAddress *appmessage.NetAddress) AddressKey { - key := AddressKey{port: netAddress.Port} +func netAddressKey(netAddress *appmessage.NetAddress) addressKey { + key := addressKey{port: netAddress.Port} // all IPv4 can be represented as IPv6. copy(key.address[:], netAddress.IP.To16()) return key } // netAddressKeys returns a key of the ip address to use it in maps. -func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[AddressKey]bool { - result := make(map[AddressKey]bool, len(netAddresses)) +func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[addressKey]bool { + result := make(map[addressKey]bool, len(netAddresses)) for _, netAddress := range netAddresses { key := netAddressKey(netAddress) result[key] = true @@ -50,12 +56,12 @@ func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[AddressKey]bool // AddressManager provides a concurrency safe address manager for caching potential // peers on the Kaspa network. type AddressManager struct { - addresses map[AddressKey]*appmessage.NetAddress - bannedAddresses map[AddressKey]*appmessage.NetAddress + addresses map[addressKey]*appmessage.NetAddress + bannedAddresses map[ipv6]*appmessage.NetAddress localAddresses *localAddressManager mutex sync.Mutex cfg *Config - random AddressRandomizer + random addressRandomizer } // New returns a new Kaspa address manager. @@ -66,8 +72,8 @@ func New(cfg *Config) (*AddressManager, error) { } return &AddressManager{ - addresses: map[AddressKey]*appmessage.NetAddress{}, - bannedAddresses: map[AddressKey]*appmessage.NetAddress{}, + addresses: map[addressKey]*appmessage.NetAddress{}, + bannedAddresses: map[ipv6]*appmessage.NetAddress{}, localAddresses: localAddresses, random: NewAddressRandomize(), cfg: cfg, @@ -111,7 +117,6 @@ func (am *AddressManager) RemoveAddress(address *appmessage.NetAddress) { key := netAddressKey(address) delete(am.addresses, key) - delete(am.bannedAddresses, key) } // Addresses returns all addresses @@ -175,21 +180,23 @@ func (am *AddressManager) BestLocalAddress(remoteAddress *appmessage.NetAddress) } // Ban marks the given address as banned -func (am *AddressManager) Ban(address *appmessage.NetAddress) error { +func (am *AddressManager) Ban(addressToBan *appmessage.NetAddress) { am.mutex.Lock() defer am.mutex.Unlock() - key := netAddressKey(address) - addressToBan, ok := am.addresses[key] - if !ok { - return errors.Wrapf(ErrAddressNotFound, "address %s "+ - "is not registered with the address manager", address.TCPAddress()) + keyToBan := netAddressKey(addressToBan) + keysToDelete := make([]addressKey, 0) + for _, address := range am.addresses { + key := netAddressKey(address) + if key.address.equal(keyToBan.address) { + keysToDelete = append(keysToDelete, key) + } + } + for _, key := range keysToDelete { + delete(am.addresses, key) } - delete(am.addresses, key) - am.bannedAddresses[key] = addressToBan - return nil - + am.bannedAddresses[keyToBan.address] = addressToBan } // Unban unmarks the given address as banned @@ -198,13 +205,13 @@ func (am *AddressManager) Unban(address *appmessage.NetAddress) error { defer am.mutex.Unlock() key := netAddressKey(address) - bannedAddress, ok := am.bannedAddresses[key] + bannedAddress, ok := am.bannedAddresses[key.address] if !ok { return errors.Wrapf(ErrAddressNotFound, "address %s "+ "is not registered with the address manager as banned", address.TCPAddress()) } - delete(am.bannedAddresses, key) + delete(am.bannedAddresses, key.address) am.addresses[key] = bannedAddress return nil } @@ -215,7 +222,7 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) defer am.mutex.Unlock() key := netAddressKey(address) - if _, ok := am.bannedAddresses[key]; !ok { + if _, ok := am.bannedAddresses[key.address]; !ok { if _, ok = am.addresses[key]; !ok { return false, errors.Wrapf(ErrAddressNotFound, "address %s "+ "is not registered with the address manager", address.TCPAddress()) diff --git a/infrastructure/network/addressmanager/addressrandomize.go b/infrastructure/network/addressmanager/addressrandomize.go index 03e17d26b..d27f9847f 100644 --- a/infrastructure/network/addressmanager/addressrandomize.go +++ b/infrastructure/network/addressmanager/addressrandomize.go @@ -7,7 +7,7 @@ import ( "github.com/kaspanet/kaspad/app/appmessage" ) -// AddressRandomize implement AddressRandomizer interface +// AddressRandomize implement addressRandomizer interface type AddressRandomize struct { random *rand.Rand } diff --git a/infrastructure/network/addressmanager/localaddressmanager.go b/infrastructure/network/addressmanager/localaddressmanager.go index d9274a432..8a06f64bc 100644 --- a/infrastructure/network/addressmanager/localaddressmanager.go +++ b/infrastructure/network/addressmanager/localaddressmanager.go @@ -38,7 +38,7 @@ type localAddress struct { } type localAddressManager struct { - localAddresses map[AddressKey]*localAddress + localAddresses map[addressKey]*localAddress lookupFunc func(string) ([]net.IP, error) cfg *Config mutex sync.Mutex @@ -46,7 +46,7 @@ type localAddressManager struct { func newLocalAddressManager(cfg *Config) (*localAddressManager, error) { localAddressManager := localAddressManager{ - localAddresses: map[AddressKey]*localAddress{}, + localAddresses: map[addressKey]*localAddress{}, cfg: cfg, lookupFunc: cfg.Lookup, } diff --git a/infrastructure/network/connmanager/connmanager.go b/infrastructure/network/connmanager/connmanager.go index eb3ec4f9d..8a5392049 100644 --- a/infrastructure/network/connmanager/connmanager.go +++ b/infrastructure/network/connmanager/connmanager.go @@ -126,12 +126,21 @@ func (c *ConnectionManager) ConnectionCount() int { } // Ban marks the given netConnection as banned -func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) error { - return c.addressManager.Ban(netConnection.NetAddress()) +func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) { + if c.isPermanent(netConnection.Address()) { + log.Infof("Cannot ban %s because it's a permanent connection", netConnection.Address()) + return + } + + c.addressManager.Ban(netConnection.NetAddress()) } // IsBanned returns whether the given netConnection is banned func (c *ConnectionManager) IsBanned(netConnection *netadapter.NetConnection) (bool, error) { + if c.isPermanent(netConnection.Address()) { + return false, nil + } + return c.addressManager.IsBanned(netConnection.NetAddress()) } @@ -159,3 +168,15 @@ func (c *ConnectionManager) connectionExists(addressString string) bool { return false } + +func (c *ConnectionManager) isPermanent(addressString string) bool { + if conn, ok := c.activeRequested[addressString]; ok { + return conn.isPermanent + } + + if conn, ok := c.pendingRequested[addressString]; ok { + return conn.isPermanent + } + + return false +} From 331042edf122bd83dcaf1a111073ff4d152fe958 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 1 Feb 2021 14:26:45 +0200 Subject: [PATCH 295/351] Add defaultTargetBlocksPerSecond (#1473) * Add defaultTargetBlocksPerSecond * Use different default per network --- cmd/kaspaminer/config.go | 24 +++++++++++++++--------- cmd/kaspaminer/main.go | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cmd/kaspaminer/config.go b/cmd/kaspaminer/config.go index 68423b5ac..f78860feb 100644 --- a/cmd/kaspaminer/config.go +++ b/cmd/kaspaminer/config.go @@ -17,8 +17,9 @@ import ( ) const ( - defaultLogFilename = "kaspaminer.log" - defaultErrLogFilename = "kaspaminer_err.log" + defaultLogFilename = "kaspaminer.log" + defaultErrLogFilename = "kaspaminer_err.log" + defaultTargetBlockRateRatio = 2.0 ) var ( @@ -30,13 +31,13 @@ var ( ) type configFlags struct { - ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` - RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` - MiningAddr string `long:"miningaddr" description:"Address to mine to"` - NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."` - MineWhenNotSynced bool `long:"mine-when-not-synced" description:"Mine even if the node is not synced with the rest of the network."` - Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` - TargetBlocksPerSecond float64 `long:"target-blocks-per-second" description:"Sets a maximum block rate. This flag is for debugging purposes."` + ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` + RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"` + MiningAddr string `long:"miningaddr" description:"Address to mine to"` + NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."` + MineWhenNotSynced bool `long:"mine-when-not-synced" description:"Mine even if the node is not synced with the rest of the network."` + Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` + TargetBlocksPerSecond *float64 `long:"target-blocks-per-second" description:"Sets a maximum block rate. 0 means no limit (The default one is 2 * target network block rate)"` config.NetworkFlags } @@ -64,6 +65,11 @@ func parseConfig() (*configFlags, error) { return nil, err } + if cfg.TargetBlocksPerSecond == nil { + targetBlocksPerSecond := defaultTargetBlockRateRatio / cfg.NetParams().TargetTimePerBlock.Seconds() + cfg.TargetBlocksPerSecond = &targetBlocksPerSecond + } + if cfg.Profile != "" { profilePort, err := strconv.Atoi(cfg.Profile) if err != nil || profilePort < 1024 || profilePort > 65535 { diff --git a/cmd/kaspaminer/main.go b/cmd/kaspaminer/main.go index 27729b511..593451eee 100644 --- a/cmd/kaspaminer/main.go +++ b/cmd/kaspaminer/main.go @@ -48,7 +48,7 @@ func main() { doneChan := make(chan struct{}) spawn("mineLoop", func() { - err = mineLoop(client, cfg.NumberOfBlocks, cfg.TargetBlocksPerSecond, cfg.MineWhenNotSynced, miningAddr) + err = mineLoop(client, cfg.NumberOfBlocks, *cfg.TargetBlocksPerSecond, cfg.MineWhenNotSynced, miningAddr) if err != nil { panic(errors.Wrap(err, "error in mine loop")) } From d281dabdb4cafd515d47c50d6007c10fc1fc5526 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 1 Feb 2021 14:35:11 +0200 Subject: [PATCH 296/351] Bump Go version to 1.15 (#1477) --- .github/workflows/go.yml | 4 ++-- README.md | 2 +- cmd/kaspactl/README.md | 2 +- cmd/kaspactl/docker/Dockerfile | 2 +- cmd/kaspaminer/README.md | 2 +- cmd/kaspaminer/docker/Dockerfile | 2 +- cmd/wallet/README.md | 2 +- docker/Dockerfile | 2 +- go.mod | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index d23baf0e7..57398f5b5 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -34,7 +34,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: 1.14 + go-version: 1.15 # Source: https://github.com/actions/cache/blob/main/examples.md#go---modules @@ -60,7 +60,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: 1.14 + go-version: 1.15 - name: Create coverage file # Because of https://github.com/golang/go/issues/27333 this seem to "fail" even though nothing is wrong, so ignore the failure diff --git a/README.md b/README.md index 56a74d2e6..36beb180a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Kaspa is an attempt at a proof-of-work cryptocurrency with instant confirmations ## Requirements -Go 1.14 or later. +Go 1.15 or later. ## Installation diff --git a/cmd/kaspactl/README.md b/cmd/kaspactl/README.md index e747c30c7..01f1e2c2b 100644 --- a/cmd/kaspactl/README.md +++ b/cmd/kaspactl/README.md @@ -4,7 +4,7 @@ kaspactl is an RPC client for kaspad ## Requirements -Go 1.14 or later. +Go 1.15 or later. ## Installation diff --git a/cmd/kaspactl/docker/Dockerfile b/cmd/kaspactl/docker/Dockerfile index 319623966..2dae764d4 100644 --- a/cmd/kaspactl/docker/Dockerfile +++ b/cmd/kaspactl/docker/Dockerfile @@ -1,5 +1,5 @@ # -- multistage docker build: stage #1: build stage -FROM golang:1.14-alpine AS build +FROM golang:1.15-alpine AS build RUN mkdir -p /go/src/github.com/kaspanet/kaspad diff --git a/cmd/kaspaminer/README.md b/cmd/kaspaminer/README.md index 53e2041d4..acdd51b5c 100644 --- a/cmd/kaspaminer/README.md +++ b/cmd/kaspaminer/README.md @@ -4,7 +4,7 @@ Kaspaminer is a CPU-based miner for kaspad ## Requirements -Go 1.14 or later. +Go 1.15 or later. ## Installation diff --git a/cmd/kaspaminer/docker/Dockerfile b/cmd/kaspaminer/docker/Dockerfile index bc904fb51..3a7758ae2 100644 --- a/cmd/kaspaminer/docker/Dockerfile +++ b/cmd/kaspaminer/docker/Dockerfile @@ -1,5 +1,5 @@ # -- multistage docker build: stage #1: build stage -FROM golang:1.14-alpine AS build +FROM golang:1.15-alpine AS build RUN mkdir -p /go/src/github.com/kaspanet/kaspad diff --git a/cmd/wallet/README.md b/cmd/wallet/README.md index c71fe930c..36cd5f580 100644 --- a/cmd/wallet/README.md +++ b/cmd/wallet/README.md @@ -10,7 +10,7 @@ It is capable of generating wallet key-pairs, printing a wallet's current balanc ## Requirements -Go 1.14 or later. +Go 1.15 or later. ## Installation diff --git a/docker/Dockerfile b/docker/Dockerfile index 7a152738b..b4b16315a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ # -- multistage docker build: stage #1: build stage -FROM golang:1.14-alpine AS build +FROM golang:1.15-alpine AS build RUN mkdir -p /go/src/github.com/kaspanet/kaspad diff --git a/go.mod b/go.mod index 50ef525b8..6c95f6940 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/kaspanet/kaspad -go 1.14 +go 1.15 require ( github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd From 280fa3de46e5c8375bbbaf30d2e1b7524b3b5f37 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 1 Feb 2021 14:52:17 +0200 Subject: [PATCH 297/351] Prevent infinite ticker leaks in kaspaminer (#1476) * Prevent infinite tickers leaks in kaspaminer * Reset ticker in ConnectionManager instead of allocating a new one Co-authored-by: Ori Newman --- cmd/kaspaminer/mineloop.go | 5 ++++- infrastructure/network/connmanager/connmanager.go | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 594f9811e..d07da2f19 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -167,6 +167,8 @@ func templatesLoop(client *minerClient, miningAddr util.Address, newTemplateChan <- template } getBlockTemplate() + const tickerTime = 500 * time.Millisecond + ticker := time.NewTicker(tickerTime) for { select { case <-stopChan: @@ -174,7 +176,8 @@ func templatesLoop(client *minerClient, miningAddr util.Address, return case <-client.blockAddedNotificationChan: getBlockTemplate() - case <-time.Tick(500 * time.Millisecond): + ticker.Reset(tickerTime) + case <-ticker.C: getBlockTemplate() } } diff --git a/infrastructure/network/connmanager/connmanager.go b/infrastructure/network/connmanager/connmanager.go index 8a5392049..33dbe1bed 100644 --- a/infrastructure/network/connmanager/connmanager.go +++ b/infrastructure/network/connmanager/connmanager.go @@ -147,8 +147,7 @@ func (c *ConnectionManager) IsBanned(netConnection *netadapter.NetConnection) (b func (c *ConnectionManager) waitTillNextIteration() { select { case <-c.resetLoopChan: - c.loopTicker.Stop() - c.loopTicker = time.NewTicker(connectionsLoopInterval) + c.loopTicker.Reset(connectionsLoopInterval) case <-c.loopTicker.C: } } From 12c438d389b5d7f979d3b38f0299423d5fe8724e Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 1 Feb 2021 15:03:31 +0200 Subject: [PATCH 298/351] Fix data races in ConnectionManager and flow tests (#1474) * Reuse the ticker in ConnectionManager.waitTillNextIteration * Fix a data race in ConnectionManager by locking the mutex * Add a mutex to fakeRelayInvsContext in block relay flow test Co-authored-by: Ori Newman --- .../flows/testing/handle_relay_invs_test.go | 149 ++++++++++++------ .../network/connmanager/connmanager.go | 18 +-- 2 files changed, 105 insertions(+), 62 deletions(-) diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 7e506e6bd..9708db895 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -18,6 +18,7 @@ import ( "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" + "sync" "testing" "time" ) @@ -105,6 +106,7 @@ type fakeRelayInvsContext struct { validateAndInsertImportedPruningPointResponse error getBlockInfoResponse *externalapi.BlockInfo validateAndInsertBlockResponse error + rwLock sync.RWMutex } func (f *fakeRelayInvsContext) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { @@ -128,6 +130,8 @@ func (f *fakeRelayInvsContext) GetBlockHeader(blockHash *externalapi.DomainHash) } func (f *fakeRelayInvsContext) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error) { + f.rwLock.RLock() + defer f.rwLock.RUnlock() if f.getBlockInfoResponse != nil { return f.getBlockInfoResponse, nil } @@ -167,6 +171,8 @@ func (f *fakeRelayInvsContext) AppendImportedPruningPointUTXOs(outpointAndUTXOEn } func (f *fakeRelayInvsContext) ValidateAndInsertImportedPruningPoint(newPruningPoint *externalapi.DomainBlock) error { + f.rwLock.RLock() + defer f.rwLock.RUnlock() return f.validateAndInsertImportedPruningPointResponse } @@ -179,12 +185,16 @@ func (f *fakeRelayInvsContext) CreateBlockLocator(lowHash, highHash *externalapi } func (f *fakeRelayInvsContext) CreateHeadersSelectedChainBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error) { + f.rwLock.RLock() + defer f.rwLock.RUnlock() return externalapi.BlockLocator{ f.params.GenesisHash, }, nil } func (f *fakeRelayInvsContext) CreateFullHeadersSelectedChainBlockLocator() (externalapi.BlockLocator, error) { + f.rwLock.RLock() + defer f.rwLock.RUnlock() return externalapi.BlockLocator{ f.params.GenesisHash, }, nil @@ -203,6 +213,8 @@ func (f *fakeRelayInvsContext) GetVirtualInfo() (*externalapi.VirtualInfo, error } func (f *fakeRelayInvsContext) IsValidPruningPoint(blockHash *externalapi.DomainHash) (bool, error) { + f.rwLock.RLock() + defer f.rwLock.RUnlock() return f.isValidPruningPointResponse, nil } @@ -231,6 +243,8 @@ func (f *fakeRelayInvsContext) Domain() domain.Domain { } func (f *fakeRelayInvsContext) Config() *config.Config { + f.rwLock.RLock() + defer f.rwLock.RUnlock() return &config.Config{ Flags: &config.Flags{ NetworkFlags: config.NetworkFlags{ @@ -269,13 +283,59 @@ func (f *fakeRelayInvsContext) IsIBDRunning() bool { } func (f *fakeRelayInvsContext) TrySetIBDRunning(ibdPeer *peerpkg.Peer) bool { + f.rwLock.RLock() + defer f.rwLock.RUnlock() return f.trySetIBDRunningResponse } func (f *fakeRelayInvsContext) UnsetIBDRunning() { + f.rwLock.RLock() + defer f.rwLock.RUnlock() close(f.finishedIBD) } +func (f *fakeRelayInvsContext) SetValidateAndInsertBlockResponse(err error) { + f.rwLock.Lock() + defer f.rwLock.Unlock() + f.validateAndInsertBlockResponse = err +} + +func (f *fakeRelayInvsContext) SetValidateAndInsertImportedPruningPointResponse(err error) { + f.rwLock.Lock() + defer f.rwLock.Unlock() + f.validateAndInsertImportedPruningPointResponse = err +} + +func (f *fakeRelayInvsContext) SetGetBlockInfoResponse(info externalapi.BlockInfo) { + f.rwLock.Lock() + defer f.rwLock.Unlock() + f.getBlockInfoResponse = &info +} + +func (f *fakeRelayInvsContext) SetTrySetIBDRunningResponse(b bool) { + f.rwLock.Lock() + defer f.rwLock.Unlock() + f.trySetIBDRunningResponse = b +} + +func (f *fakeRelayInvsContext) SetIsValidPruningPointResponse(b bool) { + f.rwLock.Lock() + defer f.rwLock.Unlock() + f.isValidPruningPointResponse = b +} + +func (f *fakeRelayInvsContext) GetGenesisHeader() externalapi.BlockHeader { + f.rwLock.RLock() + defer f.rwLock.RUnlock() + return f.params.GenesisBlock.Header +} + +func (f *fakeRelayInvsContext) GetFinishedIBDChan() chan struct{} { + f.rwLock.RLock() + defer f.rwLock.RUnlock() + return f.finishedIBD +} + func TestHandleRelayInvs(t *testing.T) { triggerIBD := func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(consensushashing.BlockHash(orphanBlock))) @@ -289,10 +349,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestRelayBlocks) - context.validateAndInsertBlockResponse = ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes()) - defer func() { - context.validateAndInsertBlockResponse = nil - }() + context.SetValidateAndInsertBlockResponse(ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes())) err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) if err != nil { @@ -342,10 +399,10 @@ func TestHandleRelayInvs(t *testing.T) { name: "sending a known invalid inv", funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusInvalid, - } + }) err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(knownInvalidBlockHash)) if err != nil { @@ -402,7 +459,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestRelayBlocks) - context.validateAndInsertBlockResponse = ruleerrors.ErrBadMerkleRoot + context.SetValidateAndInsertBlockResponse(ruleerrors.ErrBadMerkleRoot) err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(invalidBlock)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -426,7 +483,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestRelayBlocks) - context.validateAndInsertBlockResponse = ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes()) + context.SetValidateAndInsertBlockResponse(ruleerrors.NewErrMissingParents(orphanBlock.Header.ParentHashes())) err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(orphanBlock)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -452,7 +509,7 @@ func TestHandleRelayInvs(t *testing.T) { { name: "starting IBD when peer is already in IBD", funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { - context.trySetIBDRunningResponse = false + context.SetTrySetIBDRunningResponse(false) triggerIBD(t, incomingRoute, outgoingRoute, context) checkNoActivity(t, outgoingRoute) @@ -558,15 +615,15 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue( appmessage.NewBlockHeadersMessage( []*appmessage.MsgBlockHeader{ - appmessage.DomainBlockHeaderToBlockHeader(context.params.GenesisBlock.Header)}, + appmessage.DomainBlockHeaderToBlockHeader(context.GetGenesisHeader())}, ), ) if err != nil { @@ -581,10 +638,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) // Finish the IBD by sending DoneHeaders and send incompatible pruning point err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) @@ -598,7 +655,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) - context.isValidPruningPointResponse = false + context.SetIsValidPruningPointResponse(false) err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -630,11 +687,11 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) - context.validateAndInsertBlockResponse = ruleerrors.ErrDuplicateBlock + context.SetValidateAndInsertBlockResponse(ruleerrors.ErrDuplicateBlock) err = incomingRoute.Enqueue( appmessage.NewBlockHeadersMessage( []*appmessage.MsgBlockHeader{ - appmessage.DomainBlockHeaderToBlockHeader(context.params.GenesisBlock.Header)}, + appmessage.DomainBlockHeaderToBlockHeader(context.GetGenesisHeader())}, ), ) if err != nil { @@ -649,10 +706,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) // Finish the IBD by sending DoneHeaders and send incompatible pruning point err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) @@ -666,7 +723,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) - context.isValidPruningPointResponse = false + context.SetIsValidPruningPointResponse(false) err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -698,7 +755,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestHeaders) - context.validateAndInsertBlockResponse = ruleerrors.ErrBadMerkleRoot + context.SetValidateAndInsertBlockResponse(ruleerrors.ErrBadMerkleRoot) err = incomingRoute.Enqueue( appmessage.NewBlockHeadersMessage( []*appmessage.MsgBlockHeader{ @@ -738,10 +795,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -790,10 +847,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -806,7 +863,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestPruningPointHashMessage) - context.isValidPruningPointResponse = false + context.SetIsValidPruningPointResponse(false) err = incomingRoute.Enqueue(appmessage.NewPruningPointHashMessage(invalidPruningPointHash)) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -840,10 +897,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -905,10 +962,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -968,10 +1025,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -1037,10 +1094,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -1064,7 +1121,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) - context.validateAndInsertImportedPruningPointResponse = ruleerrors.ErrBadMerkleRoot + context.SetValidateAndInsertImportedPruningPointResponse(ruleerrors.ErrBadMerkleRoot) err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(invalidPruningPointBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -1104,10 +1161,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -1131,7 +1188,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestPruningPointUTXOSetAndBlock) - context.validateAndInsertImportedPruningPointResponse = ruleerrors.ErrSuggestedPruningViolatesFinality + context.SetValidateAndInsertImportedPruningPointResponse(ruleerrors.ErrSuggestedPruningViolatesFinality) err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(validPruningPointBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -1168,10 +1225,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -1247,10 +1304,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -1324,10 +1381,10 @@ func TestHandleRelayInvs(t *testing.T) { // This is done so it'll think it added the high hash to the DAG and proceed with fetching // the pruning point UTXO set. - context.getBlockInfoResponse = &externalapi.BlockInfo{ + context.SetGetBlockInfoResponse(externalapi.BlockInfo{ Exists: true, BlockStatus: externalapi.StatusHeaderOnly, - } + }) err = incomingRoute.Enqueue(appmessage.NewMsgDoneHeaders()) if err != nil { @@ -1367,7 +1424,7 @@ func TestHandleRelayInvs(t *testing.T) { } _ = msg.(*appmessage.MsgRequestIBDBlocks) - context.validateAndInsertBlockResponse = ruleerrors.ErrBadMerkleRoot + context.SetValidateAndInsertImportedPruningPointResponse(ruleerrors.ErrBadMerkleRoot) err = incomingRoute.Enqueue(appmessage.NewMsgIBDBlock(appmessage.DomainBlockToMsgBlock(invalidBlock))) if err != nil { t.Fatalf("Enqueue: %+v", err) @@ -1417,7 +1474,7 @@ func TestHandleRelayInvs(t *testing.T) { } select { - case <-context.finishedIBD: + case <-context.GetFinishedIBDChan(): if !test.expectsIBDToFinish { t.Fatalf("IBD unexpecetedly finished") } diff --git a/infrastructure/network/connmanager/connmanager.go b/infrastructure/network/connmanager/connmanager.go index 33dbe1bed..fc1afb5e6 100644 --- a/infrastructure/network/connmanager/connmanager.go +++ b/infrastructure/network/connmanager/connmanager.go @@ -152,23 +152,9 @@ func (c *ConnectionManager) waitTillNextIteration() { } } -func (c *ConnectionManager) connectionExists(addressString string) bool { - if _, ok := c.activeRequested[addressString]; ok { - return true - } - - if _, ok := c.activeOutgoing[addressString]; ok { - return true - } - - if _, ok := c.activeIncoming[addressString]; ok { - return true - } - - return false -} - func (c *ConnectionManager) isPermanent(addressString string) bool { + c.connectionRequestsLock.Lock() + defer c.connectionRequestsLock.Unlock() if conn, ok := c.activeRequested[addressString]; ok { return conn.isPermanent } From d5a3a96bde6785089c1b2735b1be972468804966 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 1 Feb 2021 15:15:37 +0200 Subject: [PATCH 299/351] Use hard-coded sample config instead of assumed path (#1466) * Use hard-coded sample config instead of assumed path * Fix bad path to sample-kaspad.conf in TestCreateDefaultConfigFile Co-authored-by: Elichai Turkel --- infrastructure/config/config.go | 44 +--- infrastructure/config/config_test.go | 2 +- .../config/sample-kaspad.conf | 70 +----- infrastructure/config/sample_config.go | 238 ++++++++++++++++++ 4 files changed, 247 insertions(+), 107 deletions(-) rename sample-kaspad.conf => infrastructure/config/sample-kaspad.conf (76%) create mode 100644 infrastructure/config/sample_config.go diff --git a/infrastructure/config/config.go b/infrastructure/config/config.go index 243c76ae2..09dc35925 100644 --- a/infrastructure/config/config.go +++ b/infrastructure/config/config.go @@ -5,9 +5,7 @@ package config import ( - "bufio" "fmt" - "io" "net" "os" "path/filepath" @@ -16,18 +14,15 @@ import ( "strings" "time" - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - - "github.com/kaspanet/kaspad/domain/dagconfig" - - "github.com/pkg/errors" - "github.com/btcsuite/go-socks/socks" "github.com/jessevdk/go-flags" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/network" "github.com/kaspanet/kaspad/version" + "github.com/pkg/errors" ) const ( @@ -244,9 +239,7 @@ func LoadConfig() (*Config, error) { cfg := &Config{ Flags: cfgFlags, } - if !preCfg.Simnet || preCfg.ConfigFile != - defaultConfigFile { - + if !preCfg.Simnet || preCfg.ConfigFile != defaultConfigFile { if _, err := os.Stat(preCfg.ConfigFile); os.IsNotExist(err) { err := createDefaultConfigFile(preCfg.ConfigFile) if err != nil { @@ -593,13 +586,6 @@ func createDefaultConfigFile(destinationPath string) error { return err } - // We assume sample config file path is same as binary - path, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - return err - } - sampleConfigPath := filepath.Join(path, sampleConfigFilename) - dest, err := os.OpenFile(destinationPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { @@ -607,25 +593,7 @@ func createDefaultConfigFile(destinationPath string) error { } defer dest.Close() - src, err := os.Open(sampleConfigPath) - if err != nil { - return err - } - defer src.Close() + _, err = dest.WriteString(sampleConfig) - // We copy every line from the sample config file to the destination - reader := bufio.NewReader(src) - for err != io.EOF { - var line string - line, err = reader.ReadString('\n') - if err != nil && err != io.EOF { - return err - } - - if _, err := dest.WriteString(line); err != nil { - return err - } - } - - return nil + return err } diff --git a/infrastructure/config/config_test.go b/infrastructure/config/config_test.go index 3928e008b..fd205b351 100644 --- a/infrastructure/config/config_test.go +++ b/infrastructure/config/config_test.go @@ -18,7 +18,7 @@ func TestCreateDefaultConfigFile(t *testing.T) { if !ok { t.Fatalf("Failed finding config file path") } - sampleConfigFile := filepath.Join(filepath.Dir(path), "..", "..", "sample-kaspad.conf") + sampleConfigFile := filepath.Join(filepath.Dir(path), "sample-kaspad.conf") // Setup a temporary directory tmpDir, err := ioutil.TempDir("", "kaspad") diff --git a/sample-kaspad.conf b/infrastructure/config/sample-kaspad.conf similarity index 76% rename from sample-kaspad.conf rename to infrastructure/config/sample-kaspad.conf index 708a4324e..b0116484f 100644 --- a/sample-kaspad.conf +++ b/infrastructure/config/sample-kaspad.conf @@ -30,7 +30,7 @@ ; Use Universal Plug and Play (UPnP) to automatically open the listen port ; and obtain the external IP address from supported devices. NOTE: This option -; will have no effect if exernal IP addresses are specified. +; will have no effect if external IP addresses are specified. ; upnp=1 ; Specify the external IP addresses your node is listening on. One address per @@ -83,7 +83,7 @@ ; connect=[fe80::2]:16111 ; Maximum number of inbound and outbound peers. -; maxpeers=125 +; maxinpeers=125 ; Disable banning of misbehaving peers. ; nobanning=1 @@ -142,9 +142,6 @@ ; Disable peer bloom filtering. See BIP0111. ; nopeerbloomfilters=1 -; Add additional checkpoints. Format: ':' -; addcheckpoint=: - ; Add comments to the user agent that is advertised to peers. ; Must not include characters '/', ':', '(' and ')'. ; uacomment= @@ -198,13 +195,6 @@ ; Set the minimum transaction fee to be considered a non-zero fee, ; minrelaytxfee=0.00001 -; Rate-limit free transactions to the value 15 * 1000 bytes per -; minute. -; limitfreerelay=15 - -; Require high priority for relaying free or low-fee transactions. -; norelaypriority=0 - ; Limit orphan transaction pool to 100 transactions. ; maxorphantx=100 @@ -218,22 +208,6 @@ ; rejectnonstd=1 -; ------------------------------------------------------------------------------ -; Optional Indexes -; ------------------------------------------------------------------------------ - -; Build and maintain a full hash-based transaction index which makes all -; transactions available via the getrawtransaction RPC. -; txindex=1 - -; Build and maintain a full address-based transaction index which makes the -; searchrawtransactions RPC available. -; addrindex=1 - -; Delete the entire address index on start up, then exit. -; dropaddrindex=0 - - ; ------------------------------------------------------------------------------ ; Signature Verification Cache ; ------------------------------------------------------------------------------ @@ -242,38 +216,6 @@ ; sigcachemaxsize=50000 -; ------------------------------------------------------------------------------ -; Coin Generation (Mining) Settings - The following options control the -; generation of block templates used by external mining applications through RPC -; calls. -; ------------------------------------------------------------------------------ - -; Add addresses to pay mined blocks to in the block templates generated -; for the getblocktemplate RPC. One address per line. -; miningaddr=kaspa:yourkaspaaddress -; miningaddr=kaspa:yourkaspaaddress2 -; miningaddr=kaspa:yourkaspaaddress3 - -; Specify the minimum block size in bytes to create. By default, only -; transactions which have enough fees or a high enough priority will be included -; in generated block templates. Specifying a minimum block size will instead -; attempt to fill generated block templates up with transactions until it is at -; least the specified number of bytes. -; blockminsize=0 - -; Specify the maximum block size in bytes to create. This value will be limited -; to the consensus limit if it is larger than that value. -; blockmaxsize=750000 - -; Specify the size in bytes of the high-priority/low-fee area when creating a -; block. Transactions which consist of large amounts, old inputs, and small -; sizes have the highest priority. One consequence of this is that as low-fee -; or free transactions age, they raise in priority thereby making them more -; likely to be included in this section of a new block. This value is limited -; by the blackmaxsize option and will be limited as needed. -; blockprioritysize=50000 - - ; ------------------------------------------------------------------------------ ; Debug ; ------------------------------------------------------------------------------ @@ -290,11 +232,3 @@ ; accessed at http://localhost:/debug/pprof once running. ; profile=6061 -; ------------------------------------------------------------------------------ -; Subnetworks -; ------------------------------------------------------------------------------ - -; If subnetwork > 0, than node will request and process only payloads from -; specified subnetwork. And if subnetwork is 0, than payloads of all subnetworks -; are processed. -; subnetwork=0 \ No newline at end of file diff --git a/infrastructure/config/sample_config.go b/infrastructure/config/sample_config.go new file mode 100644 index 000000000..a3c0b0ff6 --- /dev/null +++ b/infrastructure/config/sample_config.go @@ -0,0 +1,238 @@ +package config + +// This should be identical to the content of sample-kaspad.conf +// TODO: Replace with go:embed once go1.16 lands +var sampleConfig = `[Application Options] + +; ------------------------------------------------------------------------------ +; Data settings +; ------------------------------------------------------------------------------ + +; The directory to store data such as the block DAG and peer addresses. The +; block DAG takes several GB, so this location must have a lot of free space. +; The default is ~/.kaspad/data on POSIX OSes, $LOCALAPPDATA/Kaspad/data on Windows, +; ~/Library/Application Support/Kaspad/data on Mac OS, and $home/kaspad/data on +; Plan9. Environment variables are expanded so they may be used. NOTE: Windows +; environment variables are typically %VARIABLE%, but they must be accessed with +; $VARIABLE here. Also, ~ is expanded to $LOCALAPPDATA on Windows. +; datadir=~/.kaspad/data + + +; ------------------------------------------------------------------------------ +; Network settings +; ------------------------------------------------------------------------------ + +; Use testnet. +; testnet=1 + +; Connect via a SOCKS5 proxy. NOTE: Specifying a proxy will disable listening +; for incoming connections unless listen addresses are provided via the 'listen' +; option. +; proxy=127.0.0.1:9050 +; proxyuser= +; proxypass= + +; Use Universal Plug and Play (UPnP) to automatically open the listen port +; and obtain the external IP address from supported devices. NOTE: This option +; will have no effect if external IP addresses are specified. +; upnp=1 + +; Specify the external IP addresses your node is listening on. One address per +; line. kaspad will not contact 3rd-party sites to obtain external ip addresses. +; This means if you are behind NAT, your node will not be able to advertise a +; reachable address unless you specify it here or enable the 'upnp' option (and +; have a supported device). +; externalip=1.2.3.4 +; externalip=2002::1234 + +; ****************************************************************************** +; Summary of 'addpeer' versus 'connect'. +; +; Only one of the following two options, 'addpeer' and 'connect', may be +; specified. Both allow you to specify peers that you want to stay connected +; with, but the behavior is slightly different. By default, kaspad will query DNS +; to find peers to connect to, so unless you have a specific reason such as +; those described below, you probably won't need to modify anything here. +; +; 'addpeer' does not prevent connections to other peers discovered from +; the peers you are connected to and also lets the remote peers know you are +; available so they can notify other peers they can to connect to you. This +; option might be useful if you are having problems finding a node for some +; reason (perhaps due to a firewall). +; +; 'connect', on the other hand, will ONLY connect to the specified peers and +; no others. It also disables listening (unless you explicitly set listen +; addresses via the 'listen' option) and DNS seeding, so you will not be +; advertised as an available peer to the peers you connect to and won't accept +; connections from any other peers. So, the 'connect' option effectively allows +; you to only connect to "trusted" peers. +; ****************************************************************************** + +; Add persistent peers to connect to as desired. One peer per line. +; You may specify each IP address with or without a port. The default port will +; be added automatically if one is not specified here. +; addpeer=192.168.1.1 +; addpeer=10.0.0.2:16111 +; addpeer=fe80::1 +; addpeer=[fe80::2]:16111 + +; Add persistent peers that you ONLY want to connect to as desired. One peer +; per line. You may specify each IP address with or without a port. The +; default port will be added automatically if one is not specified here. +; NOTE: Specifying this option has other side effects as described above in +; the 'addpeer' versus 'connect' summary section. +; connect=192.168.1.1 +; connect=10.0.0.2:16111 +; connect=fe80::1 +; connect=[fe80::2]:16111 + +; Maximum number of inbound and outbound peers. +; maxinpeers=125 + +; Disable banning of misbehaving peers. +; nobanning=1 + +; Maximum allowed ban score before disconnecting and banning misbehaving peers. +; banthreshold=100 + +; How long to ban misbehaving peers. Valid time units are {s, m, h}. +; Minimum 1s. +; banduration=24h +; banduration=11h30m15s + +; Add whitelisted IP networks and IPs. Connected peers whose IP matches a +; whitelist will not have their ban score increased. +; whitelist=127.0.0.1 +; whitelist=::1 +; whitelist=192.168.0.0/24 +; whitelist=fd00::/16 + +; Disable DNS seeding for peers. By default, when kaspad starts, it will use +; DNS to query for available peers to connect with. +; nodnsseed=1 + +; Specify the interfaces to listen on. One listen address per line. +; NOTE: The default port is modified by some options such as 'testnet', so it is +; recommended to not specify a port and allow a proper default to be chosen +; unless you have a specific reason to do otherwise. +; All interfaces on default port (this is the default): +; listen= +; All ipv4 interfaces on default port: +; listen=0.0.0.0 +; All ipv6 interfaces on default port: +; listen=:: +; All interfaces on port 16111: +; listen=:16111 +; All ipv4 interfaces on port 16111: +; listen=0.0.0.0:16111 +; All ipv6 interfaces on port 16111: +; listen=[::]:16111 +; Only ipv4 localhost on port 8333: +; listen=127.0.0.1:8333 +; Only ipv6 localhost on port 8333: +; listen=[::1]:8333 +; Only ipv4 localhost on non-standard port 8336: +; listen=127.0.0.1:8336 +; All interfaces on non-standard port 8336: +; listen=:8336 +; All ipv4 interfaces on non-standard port 8336: +; listen=0.0.0.0:8336 +; All ipv6 interfaces on non-standard port 8336: +; listen=[::]:8336 + +; Disable listening for incoming connections. This will override all listeners. +; nolisten=1 + +; Disable peer bloom filtering. See BIP0111. +; nopeerbloomfilters=1 + +; Add comments to the user agent that is advertised to peers. +; Must not include characters '/', ':', '(' and ')'. +; uacomment= + +; ------------------------------------------------------------------------------ +; RPC server options - The following options control the built-in RPC server +; which is used to control and query information from a running kaspad process. +; ------------------------------------------------------------------------------ + +; Specify the interfaces for the RPC server listen on. One listen address per +; line. NOTE: The default port is modified by some options such as 'testnet', +; so it is recommended to not specify a port and allow a proper default to be +; chosen unless you have a specific reason to do otherwise. By default, the +; RPC server will only listen on localhost for IPv4 and IPv6. +; All interfaces on default port: +; rpclisten= +; All ipv4 interfaces on default port: +; rpclisten=0.0.0.0 +; All ipv6 interfaces on default port: +; rpclisten=:: +; All interfaces on port 16110: +; rpclisten=:16110 +; All ipv4 interfaces on port 16110: +; rpclisten=0.0.0.0:16110 +; All ipv6 interfaces on port 16110: +; rpclisten=[::]:16110 +; Only ipv4 localhost on port 16110: +; rpclisten=127.0.0.1:16110 +; Only ipv6 localhost on port 16110: +; rpclisten=[::1]:16110 +; Only ipv4 localhost on non-standard port 8337: +; rpclisten=127.0.0.1:8337 +; All interfaces on non-standard port 8337: +; rpclisten=:8337 +; All ipv4 interfaces on non-standard port 8337: +; rpclisten=0.0.0.0:8337 +; All ipv6 interfaces on non-standard port 8337: +; rpclisten=[::]:8337 + +; Specify the maximum number of concurrent RPC clients for standard connections. +; rpcmaxclients=10 + +; Use the following setting to disable the RPC server. +; norpc=1 + + +; ------------------------------------------------------------------------------ +; Mempool Settings - The following options +; ------------------------------------------------------------------------------ + +; Set the minimum transaction fee to be considered a non-zero fee, +; minrelaytxfee=0.00001 + +; Limit orphan transaction pool to 100 transactions. +; maxorphantx=100 + +; Do not accept transactions from remote peers. +; blocksonly=1 + +; Relay non-standard transactions regardless of default network settings. +; relaynonstd=1 + +; Reject non-standard transactions regardless of default network settings. +; rejectnonstd=1 + + +; ------------------------------------------------------------------------------ +; Signature Verification Cache +; ------------------------------------------------------------------------------ + +; Limit the signature cache to a max of 50000 entries. +; sigcachemaxsize=50000 + + +; ------------------------------------------------------------------------------ +; Debug +; ------------------------------------------------------------------------------ + +; Debug logging level. +; Valid levels are {trace, debug, info, warn, error, critical} +; You may also specify =,=,... to set +; log level for individual subsystems. Use kaspad --debuglevel=show to list +; available subsystems. +; debuglevel=info + +; The port used to listen for HTTP profile requests. The profile server will +; be disabled if this option is not specified. The profile information can be +; accessed at http://localhost:/debug/pprof once running. +; profile=6061 +` From 2871a6a5277486e96ab92d0cd386f83ee9663413 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 1 Feb 2021 15:38:40 +0200 Subject: [PATCH 300/351] Update to version 0.8.7 --- version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version/version.go b/version/version.go index f1c6319d3..76b989a2b 100644 --- a/version/version.go +++ b/version/version.go @@ -10,8 +10,8 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 - appMinor uint = 9 - appPatch uint = 0 + appMinor uint = 8 + appPatch uint = 7 ) // appBuild is defined as a variable so it can be overridden during the build From a3913dbf80b31751117e417b6a1f738e7ea165fe Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 1 Feb 2021 15:39:39 +0200 Subject: [PATCH 301/351] Update to version 0.9.0 --- version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version/version.go b/version/version.go index 76b989a2b..f1c6319d3 100644 --- a/version/version.go +++ b/version/version.go @@ -10,8 +10,8 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs const ( appMajor uint = 0 - appMinor uint = 8 - appPatch uint = 7 + appMinor uint = 9 + appPatch uint = 0 ) // appBuild is defined as a variable so it can be overridden during the build From b636ae234e5140fc58e79b2e97f615e97f69f722 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 1 Feb 2021 17:34:43 +0200 Subject: [PATCH 302/351] Add ban and unban RPC commands (#1478) * Add ban and unban RPC commands * Fix names * Fix commands strings * Update RPC documentation * Rename functions * Simplify return * Use IP strings in app messages * Add parse IP error * Fix wrong condition --- app/appmessage/message.go | 8 + app/appmessage/rpc_ban.go | 39 + app/appmessage/rpc_unban.go | 39 + app/protocol/protocol.go | 7 +- app/rpc/rpc.go | 2 + app/rpc/rpchandlers/ban.go | 28 + app/rpc/rpchandlers/unban.go | 27 + cmd/kaspactl/commands.go | 3 + .../network/connmanager/connmanager.go | 96 ++- .../grpcserver/protowire/messages.pb.go | 136 ++- .../grpcserver/protowire/messages.proto | 4 + .../server/grpcserver/protowire/rpc.md | 777 +++++++++++++++--- .../server/grpcserver/protowire/rpc.pb.go | 287 ++++++- .../server/grpcserver/protowire/rpc.proto | 18 + .../server/grpcserver/protowire/rpc_ban.go | 37 + .../server/grpcserver/protowire/rpc_unban.go | 37 + .../server/grpcserver/protowire/wire.go | 28 + 17 files changed, 1401 insertions(+), 172 deletions(-) create mode 100644 app/appmessage/rpc_ban.go create mode 100644 app/appmessage/rpc_unban.go create mode 100644 app/rpc/rpchandlers/ban.go create mode 100644 app/rpc/rpchandlers/unban.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_ban.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_unban.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 9f609f30a..15ad2a5c9 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -123,6 +123,10 @@ const ( CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage CmdVirtualSelectedParentBlueScoreChangedNotificationMessage + CmdBanRequestMessage + CmdBanResponseMessage + CmdUnbanRequestMessage + CmdUnbanResponseMessage ) // ProtocolMessageCommandToString maps all MessageCommands to their string representation @@ -220,6 +224,10 @@ var RPCMessageCommandToString = map[MessageCommand]string{ CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: "NotifyVirtualSelectedParentBlueScoreChangedRequest", CmdNotifyVirtualSelectedParentBlueScoreChangedResponseMessage: "NotifyVirtualSelectedParentBlueScoreChangedResponse", CmdVirtualSelectedParentBlueScoreChangedNotificationMessage: "VirtualSelectedParentBlueScoreChangedNotification", + CmdBanRequestMessage: "BanRequest", + CmdBanResponseMessage: "BanResponse", + CmdUnbanRequestMessage: "UnbanRequest", + CmdUnbanResponseMessage: "UnbanResponse", } // Message is an interface that describes a kaspa message. A type that diff --git a/app/appmessage/rpc_ban.go b/app/appmessage/rpc_ban.go new file mode 100644 index 000000000..bf6d89af8 --- /dev/null +++ b/app/appmessage/rpc_ban.go @@ -0,0 +1,39 @@ +package appmessage + +// BanRequestMessage is an appmessage corresponding to +// its respective RPC message +type BanRequestMessage struct { + baseMessage + + IP string +} + +// Command returns the protocol command string for the message +func (msg *BanRequestMessage) Command() MessageCommand { + return CmdBanRequestMessage +} + +// NewBanRequestMessage returns an instance of the message +func NewBanRequestMessage(ip string) *BanRequestMessage { + return &BanRequestMessage{ + IP: ip, + } +} + +// BanResponseMessage is an appmessage corresponding to +// its respective RPC message +type BanResponseMessage struct { + baseMessage + + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *BanResponseMessage) Command() MessageCommand { + return CmdBanResponseMessage +} + +// NewBanResponseMessage returns a instance of the message +func NewBanResponseMessage() *BanResponseMessage { + return &BanResponseMessage{} +} diff --git a/app/appmessage/rpc_unban.go b/app/appmessage/rpc_unban.go new file mode 100644 index 000000000..f2e558375 --- /dev/null +++ b/app/appmessage/rpc_unban.go @@ -0,0 +1,39 @@ +package appmessage + +// UnbanRequestMessage is an appmessage corresponding to +// its respective RPC message +type UnbanRequestMessage struct { + baseMessage + + IP string +} + +// Command returns the protocol command string for the message +func (msg *UnbanRequestMessage) Command() MessageCommand { + return CmdUnbanRequestMessage +} + +// NewUnbanRequestMessage returns an instance of the message +func NewUnbanRequestMessage(ip string) *UnbanRequestMessage { + return &UnbanRequestMessage{ + IP: ip, + } +} + +// UnbanResponseMessage is an appmessage corresponding to +// its respective RPC message +type UnbanResponseMessage struct { + baseMessage + + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *UnbanResponseMessage) Command() MessageCommand { + return CmdUnbanResponseMessage +} + +// NewUnbanResponseMessage returns a instance of the message +func NewUnbanResponseMessage() *UnbanResponseMessage { + return &UnbanResponseMessage{} +} diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 605586db1..87875d93e 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -2,6 +2,7 @@ package protocol import ( "github.com/kaspanet/kaspad/app/protocol/flows/rejects" + "github.com/kaspanet/kaspad/infrastructure/network/connmanager" "sync/atomic" "github.com/kaspanet/kaspad/app/appmessage" @@ -78,7 +79,11 @@ func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection if !m.context.Config().DisableBanning && protocolErr.ShouldBan { log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause) - m.context.ConnectionManager().Ban(netConnection) + err := m.context.ConnectionManager().Ban(netConnection) + if !errors.Is(err, connmanager.ErrCannotBanPermanent) { + panic(err) + } + err = outgoingRoute.Enqueue(appmessage.NewMsgReject(protocolErr.Error())) if err != nil && !errors.Is(err, routerpkg.ErrRouteClosed) { panic(err) diff --git a/app/rpc/rpc.go b/app/rpc/rpc.go index bcc34b53e..b978ec943 100644 --- a/app/rpc/rpc.go +++ b/app/rpc/rpc.go @@ -38,6 +38,8 @@ var handlers = map[appmessage.MessageCommand]handler{ appmessage.CmdGetUTXOsByAddressesRequestMessage: rpchandlers.HandleGetUTXOsByAddresses, appmessage.CmdGetVirtualSelectedParentBlueScoreRequestMessage: rpchandlers.HandleGetVirtualSelectedParentBlueScore, appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualSelectedParentBlueScoreChanged, + appmessage.CmdBanRequestMessage: rpchandlers.HandleBan, + appmessage.CmdUnbanRequestMessage: rpchandlers.HandleUnban, } func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) { diff --git a/app/rpc/rpchandlers/ban.go b/app/rpc/rpchandlers/ban.go new file mode 100644 index 000000000..88e35fcc5 --- /dev/null +++ b/app/rpc/rpchandlers/ban.go @@ -0,0 +1,28 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "net" +) + +// HandleBan handles the respectively named RPC command +func HandleBan(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { + banRequest := request.(*appmessage.BanRequestMessage) + ip := net.ParseIP(banRequest.IP) + if ip == nil { + errorMessage := &appmessage.BanResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not parse IP %s", banRequest.IP) + return errorMessage, nil + } + + err := context.ConnectionManager.BanByIP(ip) + if err != nil { + errorMessage := &appmessage.BanResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not ban IP: %s", err) + return errorMessage, nil + } + response := appmessage.NewBanResponseMessage() + return response, nil +} diff --git a/app/rpc/rpchandlers/unban.go b/app/rpc/rpchandlers/unban.go new file mode 100644 index 000000000..56df65ca8 --- /dev/null +++ b/app/rpc/rpchandlers/unban.go @@ -0,0 +1,27 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "net" +) + +// HandleUnban handles the respectively named RPC command +func HandleUnban(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { + unbanRequest := request.(*appmessage.UnbanRequestMessage) + ip := net.ParseIP(unbanRequest.IP) + if ip == nil { + errorMessage := &appmessage.UnbanResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not parse IP %s", unbanRequest.IP) + return errorMessage, nil + } + err := context.AddressManager.Unban(appmessage.NewNetAddressIPPort(ip, 0, 0)) + if err != nil { + errorMessage := &appmessage.UnbanResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Could not unban IP: %s", err) + return errorMessage, nil + } + response := appmessage.NewUnbanResponseMessage() + return response, nil +} diff --git a/cmd/kaspactl/commands.go b/cmd/kaspactl/commands.go index db3e2a5a9..24c54ed23 100644 --- a/cmd/kaspactl/commands.go +++ b/cmd/kaspactl/commands.go @@ -32,6 +32,9 @@ var commandTypes = []reflect.Type{ reflect.TypeOf(protowire.KaspadMessage_SubmitTransactionRequest{}), reflect.TypeOf(protowire.KaspadMessage_GetUtxosByAddressesRequest{}), + + reflect.TypeOf(protowire.KaspadMessage_BanRequest{}), + reflect.TypeOf(protowire.KaspadMessage_UnbanRequest{}), } type commandDescription struct { diff --git a/infrastructure/network/connmanager/connmanager.go b/infrastructure/network/connmanager/connmanager.go index fc1afb5e6..7b3a91e81 100644 --- a/infrastructure/network/connmanager/connmanager.go +++ b/infrastructure/network/connmanager/connmanager.go @@ -1,6 +1,9 @@ package connmanager import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/pkg/errors" + "net" "sync" "sync/atomic" "time" @@ -35,7 +38,7 @@ type ConnectionManager struct { maxIncoming int stop uint32 - connectionRequestsLock sync.Mutex + connectionRequestsLock sync.RWMutex resetLoopChan chan struct{} loopTicker *time.Ticker @@ -125,14 +128,39 @@ func (c *ConnectionManager) ConnectionCount() int { return c.netAdapter.P2PConnectionCount() } +// ErrCannotBanPermanent is the error returned when trying to ban a permanent peer. +var ErrCannotBanPermanent = errors.New("ErrCannotBanPermanent") + // Ban marks the given netConnection as banned -func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) { +func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) error { if c.isPermanent(netConnection.Address()) { - log.Infof("Cannot ban %s because it's a permanent connection", netConnection.Address()) - return + return errors.Wrapf(ErrCannotBanPermanent, "Cannot ban %s because it's a permanent connection", netConnection.Address()) } c.addressManager.Ban(netConnection.NetAddress()) + return nil +} + +// BanByIP bans the given IP and disconnects from all the connection with that IP. +func (c *ConnectionManager) BanByIP(ip net.IP) error { + ipHasPermanentConnection, err := c.ipHasPermanentConnection(ip) + if err != nil { + return err + } + + if ipHasPermanentConnection { + return errors.Wrapf(ErrCannotBanPermanent, "Cannot ban %s because it's a permanent connection", ip) + } + + connections := c.netAdapter.P2PConnections() + for _, conn := range connections { + if conn.NetAddress().IP.Equal(ip) { + conn.Disconnect() + } + } + + c.addressManager.Ban(appmessage.NewNetAddressIPPort(ip, 0, 0)) + return nil } // IsBanned returns whether the given netConnection is banned @@ -153,8 +181,9 @@ func (c *ConnectionManager) waitTillNextIteration() { } func (c *ConnectionManager) isPermanent(addressString string) bool { - c.connectionRequestsLock.Lock() - defer c.connectionRequestsLock.Unlock() + c.connectionRequestsLock.RLock() + defer c.connectionRequestsLock.RUnlock() + if conn, ok := c.activeRequested[addressString]; ok { return conn.isPermanent } @@ -165,3 +194,58 @@ func (c *ConnectionManager) isPermanent(addressString string) bool { return false } + +func (c *ConnectionManager) ipHasPermanentConnection(ip net.IP) (bool, error) { + c.connectionRequestsLock.RLock() + defer c.connectionRequestsLock.RUnlock() + + for addr, conn := range c.activeRequested { + if !conn.isPermanent { + continue + } + + ips, err := c.extractAddressIPs(addr) + if err != nil { + return false, err + } + + for _, extractedIP := range ips { + if extractedIP.Equal(ip) { + return true, nil + } + } + } + + for addr, conn := range c.pendingRequested { + if !conn.isPermanent { + continue + } + + ips, err := c.extractAddressIPs(addr) + if err != nil { + return false, err + } + + for _, extractedIP := range ips { + if extractedIP.Equal(ip) { + return true, nil + } + } + } + + return false, nil +} + +func (c *ConnectionManager) extractAddressIPs(address string) ([]net.IP, error) { + host, _, err := net.SplitHostPort(address) + if err != nil { + return nil, err + } + + ip := net.ParseIP(host) + if ip == nil { + return c.cfg.Lookup(host) + } + + return []net.IP{ip}, nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 0811df1bb..1437fdadc 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -120,6 +120,10 @@ type KaspadMessage struct { // *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest // *KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse // *KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification + // *KaspadMessage_BanRequest + // *KaspadMessage_BanResponse + // *KaspadMessage_UnbanRequest + // *KaspadMessage_UnbanResponse Payload isKaspadMessage_Payload `protobuf_oneof:"payload"` } @@ -785,6 +789,34 @@ func (x *KaspadMessage) GetVirtualSelectedParentBlueScoreChangedNotification() * return nil } +func (x *KaspadMessage) GetBanRequest() *BanRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_BanRequest); ok { + return x.BanRequest + } + return nil +} + +func (x *KaspadMessage) GetBanResponse() *BanResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_BanResponse); ok { + return x.BanResponse + } + return nil +} + +func (x *KaspadMessage) GetUnbanRequest() *UnbanRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_UnbanRequest); ok { + return x.UnbanRequest + } + return nil +} + +func (x *KaspadMessage) GetUnbanResponse() *UnbanResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_UnbanResponse); ok { + return x.UnbanResponse + } + return nil +} + type isKaspadMessage_Payload interface { isKaspadMessage_Payload() } @@ -1145,6 +1177,22 @@ type KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification struct { VirtualSelectedParentBlueScoreChangedNotification *VirtualSelectedParentBlueScoreChangedNotificationMessage `protobuf:"bytes,1058,opt,name=virtualSelectedParentBlueScoreChangedNotification,proto3,oneof"` } +type KaspadMessage_BanRequest struct { + BanRequest *BanRequestMessage `protobuf:"bytes,1059,opt,name=banRequest,proto3,oneof"` +} + +type KaspadMessage_BanResponse struct { + BanResponse *BanResponseMessage `protobuf:"bytes,1060,opt,name=banResponse,proto3,oneof"` +} + +type KaspadMessage_UnbanRequest struct { + UnbanRequest *UnbanRequestMessage `protobuf:"bytes,1061,opt,name=unbanRequest,proto3,oneof"` +} + +type KaspadMessage_UnbanResponse struct { + UnbanResponse *UnbanResponseMessage `protobuf:"bytes,1062,opt,name=unbanResponse,proto3,oneof"` +} + func (*KaspadMessage_Addresses) isKaspadMessage_Payload() {} func (*KaspadMessage_Block) isKaspadMessage_Payload() {} @@ -1323,13 +1371,21 @@ func (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse) isKasp func (*KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification) isKaspadMessage_Payload() {} +func (*KaspadMessage_BanRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_BanResponse) isKaspadMessage_Payload() {} + +func (*KaspadMessage_UnbanRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_UnbanResponse) isKaspadMessage_Payload() {} + var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xa4, 0x48, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x6f, 0x22, 0xba, 0x4a, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, @@ -1906,21 +1962,39 @@ var file_messages_proto_rawDesc = []byte{ 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, - 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, + 0x0a, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa3, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, + 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x0a, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, + 0x0a, 0x0b, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa4, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xa5, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x75, 0x6e, 0x62, + 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x0d, 0x75, 0x6e, 0x62, + 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa6, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, + 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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 ( @@ -2026,6 +2100,10 @@ var file_messages_proto_goTypes = []interface{}{ (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 86: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 87: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 88: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*BanRequestMessage)(nil), // 89: protowire.BanRequestMessage + (*BanResponseMessage)(nil), // 90: protowire.BanResponseMessage + (*UnbanRequestMessage)(nil), // 91: protowire.UnbanRequestMessage + (*UnbanResponseMessage)(nil), // 92: protowire.UnbanResponseMessage } var file_messages_proto_depIdxs = []int32{ 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -2117,15 +2195,19 @@ var file_messages_proto_depIdxs = []int32{ 86, // 86: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage 87, // 87: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage 88, // 88: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 0, // 89: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 90: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 91: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 92: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 91, // [91:93] is the sub-list for method output_type - 89, // [89:91] is the sub-list for method input_type - 89, // [89:89] is the sub-list for extension type_name - 89, // [89:89] is the sub-list for extension extendee - 0, // [0:89] is the sub-list for field type_name + 89, // 89: protowire.KaspadMessage.banRequest:type_name -> protowire.BanRequestMessage + 90, // 90: protowire.KaspadMessage.banResponse:type_name -> protowire.BanResponseMessage + 91, // 91: protowire.KaspadMessage.unbanRequest:type_name -> protowire.UnbanRequestMessage + 92, // 92: protowire.KaspadMessage.unbanResponse:type_name -> protowire.UnbanResponseMessage + 0, // 93: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 94: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 95: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 96: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 95, // [95:97] is the sub-list for method output_type + 93, // [93:95] is the sub-list for method input_type + 93, // [93:93] is the sub-list for extension type_name + 93, // [93:93] is the sub-list for extension extendee + 0, // [0:93] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2239,6 +2321,10 @@ func file_messages_proto_init() { (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedRequest)(nil), (*KaspadMessage_NotifyVirtualSelectedParentBlueScoreChangedResponse)(nil), (*KaspadMessage_VirtualSelectedParentBlueScoreChangedNotification)(nil), + (*KaspadMessage_BanRequest)(nil), + (*KaspadMessage_BanResponse)(nil), + (*KaspadMessage_UnbanRequest)(nil), + (*KaspadMessage_UnbanResponse)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 50631bac9..349e55b7f 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -98,6 +98,10 @@ message KaspadMessage { NotifyVirtualSelectedParentBlueScoreChangedRequestMessage notifyVirtualSelectedParentBlueScoreChangedRequest = 1056; NotifyVirtualSelectedParentBlueScoreChangedResponseMessage notifyVirtualSelectedParentBlueScoreChangedResponse = 1057; VirtualSelectedParentBlueScoreChangedNotificationMessage virtualSelectedParentBlueScoreChangedNotification = 1058; + BanRequestMessage banRequest = 1059; + BanResponseMessage banResponse = 1060; + UnbanRequestMessage unbanRequest = 1061; + UnbanResponseMessage unbanResponse = 1062; } } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md index afafc28a7..0aafcb3d7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -4,84 +4,90 @@ ## Table of Contents - [rpc.proto](#rpc.proto) - - [RPCError](#protowire.RPCError) - - [GetCurrentNetworkRequestMessage](#protowire.GetCurrentNetworkRequestMessage) - - [GetCurrentNetworkResponseMessage](#protowire.GetCurrentNetworkResponseMessage) - - [SubmitBlockRequestMessage](#protowire.SubmitBlockRequestMessage) - - [SubmitBlockResponseMessage](#protowire.SubmitBlockResponseMessage) - - [GetBlockTemplateRequestMessage](#protowire.GetBlockTemplateRequestMessage) - - [GetBlockTemplateResponseMessage](#protowire.GetBlockTemplateResponseMessage) - - [NotifyBlockAddedRequestMessage](#protowire.NotifyBlockAddedRequestMessage) - - [NotifyBlockAddedResponseMessage](#protowire.NotifyBlockAddedResponseMessage) - - [BlockAddedNotificationMessage](#protowire.BlockAddedNotificationMessage) - - [GetPeerAddressesRequestMessage](#protowire.GetPeerAddressesRequestMessage) - - [GetPeerAddressesResponseMessage](#protowire.GetPeerAddressesResponseMessage) - - [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) - - [GetSelectedTipHashRequestMessage](#protowire.GetSelectedTipHashRequestMessage) - - [GetSelectedTipHashResponseMessage](#protowire.GetSelectedTipHashResponseMessage) - - [GetMempoolEntryRequestMessage](#protowire.GetMempoolEntryRequestMessage) - - [GetMempoolEntryResponseMessage](#protowire.GetMempoolEntryResponseMessage) - - [GetMempoolEntriesRequestMessage](#protowire.GetMempoolEntriesRequestMessage) - - [GetMempoolEntriesResponseMessage](#protowire.GetMempoolEntriesResponseMessage) - - [MempoolEntry](#protowire.MempoolEntry) - - [GetConnectedPeerInfoRequestMessage](#protowire.GetConnectedPeerInfoRequestMessage) - - [GetConnectedPeerInfoResponseMessage](#protowire.GetConnectedPeerInfoResponseMessage) - - [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage) - - [AddPeerRequestMessage](#protowire.AddPeerRequestMessage) - - [AddPeerResponseMessage](#protowire.AddPeerResponseMessage) - - [SubmitTransactionRequestMessage](#protowire.SubmitTransactionRequestMessage) - - [SubmitTransactionResponseMessage](#protowire.SubmitTransactionResponseMessage) - - [NotifyVirtualSelectedParentChainChangedRequestMessage](#protowire.NotifyVirtualSelectedParentChainChangedRequestMessage) - - [NotifyVirtualSelectedParentChainChangedResponseMessage](#protowire.NotifyVirtualSelectedParentChainChangedResponseMessage) - - [VirtualSelectedParentChainChangedNotificationMessage](#protowire.VirtualSelectedParentChainChangedNotificationMessage) - - [ChainBlock](#protowire.ChainBlock) - - [AcceptedBlock](#protowire.AcceptedBlock) - - [GetBlockRequestMessage](#protowire.GetBlockRequestMessage) - - [GetBlockResponseMessage](#protowire.GetBlockResponseMessage) - - [BlockVerboseData](#protowire.BlockVerboseData) - - [TransactionVerboseData](#protowire.TransactionVerboseData) - - [TransactionVerboseInput](#protowire.TransactionVerboseInput) - - [ScriptSig](#protowire.ScriptSig) - - [TransactionVerboseOutput](#protowire.TransactionVerboseOutput) - - [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult) - - [GetSubnetworkRequestMessage](#protowire.GetSubnetworkRequestMessage) - - [GetSubnetworkResponseMessage](#protowire.GetSubnetworkResponseMessage) - - [GetVirtualSelectedParentChainFromBlockRequestMessage](#protowire.GetVirtualSelectedParentChainFromBlockRequestMessage) - - [GetVirtualSelectedParentChainFromBlockResponseMessage](#protowire.GetVirtualSelectedParentChainFromBlockResponseMessage) - - [GetBlocksRequestMessage](#protowire.GetBlocksRequestMessage) - - [GetBlocksResponseMessage](#protowire.GetBlocksResponseMessage) - - [GetBlockCountRequestMessage](#protowire.GetBlockCountRequestMessage) - - [GetBlockCountResponseMessage](#protowire.GetBlockCountResponseMessage) - - [GetBlockDagInfoRequestMessage](#protowire.GetBlockDagInfoRequestMessage) - - [GetBlockDagInfoResponseMessage](#protowire.GetBlockDagInfoResponseMessage) - - [ResolveFinalityConflictRequestMessage](#protowire.ResolveFinalityConflictRequestMessage) - - [ResolveFinalityConflictResponseMessage](#protowire.ResolveFinalityConflictResponseMessage) - - [NotifyFinalityConflictsRequestMessage](#protowire.NotifyFinalityConflictsRequestMessage) - - [NotifyFinalityConflictsResponseMessage](#protowire.NotifyFinalityConflictsResponseMessage) - - [FinalityConflictNotificationMessage](#protowire.FinalityConflictNotificationMessage) - - [FinalityConflictResolvedNotificationMessage](#protowire.FinalityConflictResolvedNotificationMessage) - - [ShutDownRequestMessage](#protowire.ShutDownRequestMessage) - - [ShutDownResponseMessage](#protowire.ShutDownResponseMessage) - - [GetHeadersRequestMessage](#protowire.GetHeadersRequestMessage) - - [GetHeadersResponseMessage](#protowire.GetHeadersResponseMessage) - - [NotifyUtxosChangedRequestMessage](#protowire.NotifyUtxosChangedRequestMessage) - - [NotifyUtxosChangedResponseMessage](#protowire.NotifyUtxosChangedResponseMessage) - - [UtxosChangedNotificationMessage](#protowire.UtxosChangedNotificationMessage) - - [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) - - [RpcTransaction](#protowire.RpcTransaction) - - [RpcTransactionInput](#protowire.RpcTransactionInput) - - [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) - - [RpcTransactionOutput](#protowire.RpcTransactionOutput) - - [RpcOutpoint](#protowire.RpcOutpoint) - - [RpcUtxoEntry](#protowire.RpcUtxoEntry) - - [GetUtxosByAddressesRequestMessage](#protowire.GetUtxosByAddressesRequestMessage) - - [GetUtxosByAddressesResponseMessage](#protowire.GetUtxosByAddressesResponseMessage) - - [GetVirtualSelectedParentBlueScoreRequestMessage](#protowire.GetVirtualSelectedParentBlueScoreRequestMessage) - - [GetVirtualSelectedParentBlueScoreResponseMessage](#protowire.GetVirtualSelectedParentBlueScoreResponseMessage) - - [NotifyVirtualSelectedParentBlueScoreChangedRequestMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) - - [NotifyVirtualSelectedParentBlueScoreChangedResponseMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) - - [VirtualSelectedParentBlueScoreChangedNotificationMessage](#protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage) - + - [RPCError](#protowire.RPCError) + - [GetCurrentNetworkRequestMessage](#protowire.GetCurrentNetworkRequestMessage) + - [GetCurrentNetworkResponseMessage](#protowire.GetCurrentNetworkResponseMessage) + - [SubmitBlockRequestMessage](#protowire.SubmitBlockRequestMessage) + - [SubmitBlockResponseMessage](#protowire.SubmitBlockResponseMessage) + - [GetBlockTemplateRequestMessage](#protowire.GetBlockTemplateRequestMessage) + - [GetBlockTemplateResponseMessage](#protowire.GetBlockTemplateResponseMessage) + - [NotifyBlockAddedRequestMessage](#protowire.NotifyBlockAddedRequestMessage) + - [NotifyBlockAddedResponseMessage](#protowire.NotifyBlockAddedResponseMessage) + - [BlockAddedNotificationMessage](#protowire.BlockAddedNotificationMessage) + - [GetPeerAddressesRequestMessage](#protowire.GetPeerAddressesRequestMessage) + - [GetPeerAddressesResponseMessage](#protowire.GetPeerAddressesResponseMessage) + - [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) + - [GetSelectedTipHashRequestMessage](#protowire.GetSelectedTipHashRequestMessage) + - [GetSelectedTipHashResponseMessage](#protowire.GetSelectedTipHashResponseMessage) + - [GetMempoolEntryRequestMessage](#protowire.GetMempoolEntryRequestMessage) + - [GetMempoolEntryResponseMessage](#protowire.GetMempoolEntryResponseMessage) + - [GetMempoolEntriesRequestMessage](#protowire.GetMempoolEntriesRequestMessage) + - [GetMempoolEntriesResponseMessage](#protowire.GetMempoolEntriesResponseMessage) + - [MempoolEntry](#protowire.MempoolEntry) + - [GetConnectedPeerInfoRequestMessage](#protowire.GetConnectedPeerInfoRequestMessage) + - [GetConnectedPeerInfoResponseMessage](#protowire.GetConnectedPeerInfoResponseMessage) + - [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage) + - [AddPeerRequestMessage](#protowire.AddPeerRequestMessage) + - [AddPeerResponseMessage](#protowire.AddPeerResponseMessage) + - [SubmitTransactionRequestMessage](#protowire.SubmitTransactionRequestMessage) + - [SubmitTransactionResponseMessage](#protowire.SubmitTransactionResponseMessage) + - [NotifyVirtualSelectedParentChainChangedRequestMessage](#protowire.NotifyVirtualSelectedParentChainChangedRequestMessage) + - [NotifyVirtualSelectedParentChainChangedResponseMessage](#protowire.NotifyVirtualSelectedParentChainChangedResponseMessage) + - [VirtualSelectedParentChainChangedNotificationMessage](#protowire.VirtualSelectedParentChainChangedNotificationMessage) + - [ChainBlock](#protowire.ChainBlock) + - [AcceptedBlock](#protowire.AcceptedBlock) + - [GetBlockRequestMessage](#protowire.GetBlockRequestMessage) + - [GetBlockResponseMessage](#protowire.GetBlockResponseMessage) + - [BlockVerboseData](#protowire.BlockVerboseData) + - [TransactionVerboseData](#protowire.TransactionVerboseData) + - [TransactionVerboseInput](#protowire.TransactionVerboseInput) + - [ScriptSig](#protowire.ScriptSig) + - [TransactionVerboseOutput](#protowire.TransactionVerboseOutput) + - [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult) + - [GetSubnetworkRequestMessage](#protowire.GetSubnetworkRequestMessage) + - [GetSubnetworkResponseMessage](#protowire.GetSubnetworkResponseMessage) + - [GetVirtualSelectedParentChainFromBlockRequestMessage](#protowire.GetVirtualSelectedParentChainFromBlockRequestMessage) + - [GetVirtualSelectedParentChainFromBlockResponseMessage](#protowire.GetVirtualSelectedParentChainFromBlockResponseMessage) + - [GetBlocksRequestMessage](#protowire.GetBlocksRequestMessage) + - [GetBlocksResponseMessage](#protowire.GetBlocksResponseMessage) + - [GetBlockCountRequestMessage](#protowire.GetBlockCountRequestMessage) + - [GetBlockCountResponseMessage](#protowire.GetBlockCountResponseMessage) + - [GetBlockDagInfoRequestMessage](#protowire.GetBlockDagInfoRequestMessage) + - [GetBlockDagInfoResponseMessage](#protowire.GetBlockDagInfoResponseMessage) + - [ResolveFinalityConflictRequestMessage](#protowire.ResolveFinalityConflictRequestMessage) + - [ResolveFinalityConflictResponseMessage](#protowire.ResolveFinalityConflictResponseMessage) + - [NotifyFinalityConflictsRequestMessage](#protowire.NotifyFinalityConflictsRequestMessage) + - [NotifyFinalityConflictsResponseMessage](#protowire.NotifyFinalityConflictsResponseMessage) + - [FinalityConflictNotificationMessage](#protowire.FinalityConflictNotificationMessage) + - [FinalityConflictResolvedNotificationMessage](#protowire.FinalityConflictResolvedNotificationMessage) + - [ShutDownRequestMessage](#protowire.ShutDownRequestMessage) + - [ShutDownResponseMessage](#protowire.ShutDownResponseMessage) + - [GetHeadersRequestMessage](#protowire.GetHeadersRequestMessage) + - [GetHeadersResponseMessage](#protowire.GetHeadersResponseMessage) + - [NotifyUtxosChangedRequestMessage](#protowire.NotifyUtxosChangedRequestMessage) + - [NotifyUtxosChangedResponseMessage](#protowire.NotifyUtxosChangedResponseMessage) + - [UtxosChangedNotificationMessage](#protowire.UtxosChangedNotificationMessage) + - [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) + - [RpcTransaction](#protowire.RpcTransaction) + - [RpcTransactionInput](#protowire.RpcTransactionInput) + - [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) + - [RpcTransactionOutput](#protowire.RpcTransactionOutput) + - [RpcOutpoint](#protowire.RpcOutpoint) + - [RpcUtxoEntry](#protowire.RpcUtxoEntry) + - [GetUtxosByAddressesRequestMessage](#protowire.GetUtxosByAddressesRequestMessage) + - [GetUtxosByAddressesResponseMessage](#protowire.GetUtxosByAddressesResponseMessage) + - [GetVirtualSelectedParentBlueScoreRequestMessage](#protowire.GetVirtualSelectedParentBlueScoreRequestMessage) + - [GetVirtualSelectedParentBlueScoreResponseMessage](#protowire.GetVirtualSelectedParentBlueScoreResponseMessage) + - [NotifyVirtualSelectedParentBlueScoreChangedRequestMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) + - [NotifyVirtualSelectedParentBlueScoreChangedResponseMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) + - [VirtualSelectedParentBlueScoreChangedNotificationMessage](#protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage) + - [BanRequestMessage](#protowire.BanRequestMessage) + - [BanResponseMessage](#protowire.BanResponseMessage) + - [UnbanRequestMessage](#protowire.UnbanRequestMessage) + - [UnbanResponseMessage](#protowire.UnbanResponseMessage) + + - [SubmitBlockResponseMessage.RejectReason](#protowire.SubmitBlockResponseMessage.RejectReason) + - [Scalar Value Types](#scalar-value-types) @@ -94,8 +100,8 @@ RPC-related types. Request messages, response messages, and dependant types. Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto) -Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a ResponseMessage ( -likewise wrapped in a KaspadMessage) respective to the original RequestMessage. +Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a +ResponseMessage (likewise wrapped in a KaspadMessage) respective to the original RequestMessage. **IMPORTANT:** This API is a work in progress and is subject to break between versions. @@ -103,207 +109,340 @@ likewise wrapped in a KaspadMessage) respective to the original RequestMessage. ### RPCError - RPCError represents a generic non-internal error. Receivers of any ResponseMessage are expected to check whether its error field is not null. + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | message | [string](#string) | | | + + + + + ### GetCurrentNetworkRequestMessage - GetCurrentNetworkRequestMessage requests the network kaspad is currently running against. Possible networks are: Mainnet, Testnet, Simnet, Devnet + + + + + ### GetCurrentNetworkResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | currentNetwork | [string](#string) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### SubmitBlockRequestMessage - -SubmitBlockRequestMessage requests to submit a block into the DAG. Blocks are generally expected to have been generated -using the getBlockTemplate call. +SubmitBlockRequestMessage requests to submit a block into the DAG. +Blocks are generally expected to have been generated using the getBlockTemplate call. See: GetBlockTemplateRequestMessage + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | block | [BlockMessage](#protowire.BlockMessage) | | | + + + + + ### SubmitBlockResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | +| rejectReason | [SubmitBlockResponseMessage.RejectReason](#protowire.SubmitBlockResponseMessage.RejectReason) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetBlockTemplateRequestMessage - -GetBlockTemplateRequestMessage requests a current block template. Callers are expected to solve the block template and -submit it using the submitBlock call +GetBlockTemplateRequestMessage requests a current block template. +Callers are expected to solve the block template and submit it using the submitBlock call See: SubmitBlockRequestMessage + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | payAddress | [string](#string) | | Which kaspa address should the coinbase block reward transaction pay into | + + + + + ### GetBlockTemplateResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | blockMessage | [BlockMessage](#protowire.BlockMessage) | | | | isSynced | [bool](#bool) | | Whether kaspad thinks that it's synced. Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. That is because when kaspad isn't in sync with the rest of the network there's a high chance the block will never be accepted, thus the solving effort would have been wasted. | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### NotifyBlockAddedRequestMessage - NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications. See: BlockAddedNotificationMessage + + + + + ### NotifyBlockAddedResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### BlockAddedNotificationMessage - BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted) into the DAG. See: NotifyBlockAddedRequestMessage + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | block | [BlockMessage](#protowire.BlockMessage) | | | + + + + + ### GetPeerAddressesRequestMessage +GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the +current network. (mainnet, testnet, etc.) + + + + -GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the current network. (mainnet, testnet, -etc.) ### GetPeerAddressesResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | addresses | [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) | repeated | | | bannedAddresses | [GetPeerAddressesKnownAddressMessage](#protowire.GetPeerAddressesKnownAddressMessage) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetPeerAddressesKnownAddressMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | Addr | [string](#string) | | | + + + + + ### GetSelectedTipHashRequestMessage +GetSelectedTipHashRequestMessage requests the hash of the current virtual's +selected parent. + + + + -GetSelectedTipHashRequestMessage requests the hash of the current virtual's selected parent. ### GetSelectedTipHashResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | selectedTipHash | [string](#string) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetMempoolEntryRequestMessage +GetMempoolEntryRequestMessage requests information about a specific transaction +in the mempool. -GetMempoolEntryRequestMessage requests information about a specific transaction in the mempool. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | txId | [string](#string) | | The transaction's TransactionID. | + + + + + ### GetMempoolEntryResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | entry | [MempoolEntry](#protowire.MempoolEntry) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetMempoolEntriesRequestMessage +GetMempoolEntriesRequestMessage requests information about all the transactions +currently in the mempool. + + + + -GetMempoolEntriesRequestMessage requests information about all the transactions currently in the mempool. ### GetMempoolEntriesResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | entries | [MempoolEntry](#protowire.MempoolEntry) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### MempoolEntry + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | fee | [uint64](#uint64) | | | | transactionVerboseData | [TransactionVerboseData](#protowire.TransactionVerboseData) | | | + + + + + ### GetConnectedPeerInfoRequestMessage +GetConnectedPeerInfoRequestMessage requests information about all the p2p peers +currently connected to this kaspad. + + + + -GetConnectedPeerInfoRequestMessage requests information about all the p2p peers currently connected to this kaspad. ### GetConnectedPeerInfoResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | infos | [GetConnectedPeerInfoMessage](#protowire.GetConnectedPeerInfoMessage) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetConnectedPeerInfoMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | id | [string](#string) | | | @@ -316,119 +455,191 @@ GetConnectedPeerInfoRequestMessage requests information about all the p2p peers | timeConnected | [int64](#int64) | | The timestamp of when this peer connected to this kaspad | | isIbdPeer | [bool](#bool) | | Whether this peer is the IBD peer (if IBD is running) | + + + + + ### AddPeerRequestMessage +AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. +This will, in most cases, result in kaspad connecting to said peer. -AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. This will, in most cases, result in kaspad -connecting to said peer. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | address | [string](#string) | | | | isPermanent | [bool](#bool) | | Whether to keep attempting to connect to this peer after disconnection | + + + + + ### AddPeerResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### SubmitTransactionRequestMessage - SubmitTransactionRequestMessage submits a transaction to the mempool + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | transaction | [RpcTransaction](#protowire.RpcTransaction) | | | + + + + + ### SubmitTransactionResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | transactionId | [string](#string) | | The transaction ID of the submitted transaction | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### NotifyVirtualSelectedParentChainChangedRequestMessage - -NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged -notifications. +NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged notifications. See: VirtualSelectedParentChainChangedNotificationMessage + + + + + ### NotifyVirtualSelectedParentChainChangedResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### VirtualSelectedParentChainChangedNotificationMessage - -VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent chain had changed. +VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent +chain had changed. See: NotifyVirtualSelectedParentChainChangedRequestMessage + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | removedChainBlockHashes | [string](#string) | repeated | The chain blocks that were removed, in high-to-low order | | addedChainBlocks | [ChainBlock](#protowire.ChainBlock) | repeated | The chain blocks that were added, in low-to-high order | + + + + + ### ChainBlock + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | hash | [string](#string) | | | | acceptedBlocks | [AcceptedBlock](#protowire.AcceptedBlock) | repeated | | + + + + + ### AcceptedBlock + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | hash | [string](#string) | | | | acceptedTransactionIds | [string](#string) | repeated | | + + + + + ### GetBlockRequestMessage - GetBlockRequestMessage requests information about a specific block + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | hash | [string](#string) | | The hash of the requested block | -| subnetworkId | [string](#string) | | | | includeTransactionVerboseData | [bool](#bool) | | Whether to include transaction data in the response | + + + + + ### GetBlockResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | blockHash | [string](#string) | | | | blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### BlockVerboseData + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | hash | [string](#string) | | | @@ -448,10 +659,17 @@ GetBlockRequestMessage requests information about a specific block | isHeaderOnly | [bool](#bool) | | | | blueScore | [uint64](#uint64) | | | + + + + + ### TransactionVerboseData + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | txId | [string](#string) | | | @@ -469,10 +687,17 @@ GetBlockRequestMessage requests information about a specific block | time | [uint64](#uint64) | | | | blockTime | [uint64](#uint64) | | | + + + + + ### TransactionVerboseInput + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | txId | [string](#string) | | | @@ -480,29 +705,50 @@ GetBlockRequestMessage requests information about a specific block | scriptSig | [ScriptSig](#protowire.ScriptSig) | | | | sequence | [uint64](#uint64) | | | + + + + + ### ScriptSig + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | asm | [string](#string) | | | | hex | [string](#string) | | | + + + + + ### TransactionVerboseOutput + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | value | [uint64](#uint64) | | | | index | [uint32](#uint32) | | | | scriptPublicKey | [ScriptPublicKeyResult](#protowire.ScriptPublicKeyResult) | | | + + + + + ### ScriptPublicKeyResult + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | asm | [string](#string) | | | @@ -510,33 +756,50 @@ GetBlockRequestMessage requests information about a specific block | type | [string](#string) | | | | address | [string](#string) | | | + + + + + ### GetSubnetworkRequestMessage - GetSubnetworkRequestMessage requests information about a specific subnetwork Currently unimplemented + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | subnetworkId | [string](#string) | | | + + + + + ### GetSubnetworkResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | gasLimit | [uint64](#uint64) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetVirtualSelectedParentChainFromBlockRequestMessage +GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected +parent chain from some startHash to this kaspad's current virtual -GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected parent chain from some startHash to -this kaspad's current virtual | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -551,17 +814,25 @@ this kaspad's current virtual ### GetVirtualSelectedParentChainFromBlockResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | removedChainBlockHashes | [string](#string) | repeated | The chain blocks that were removed, in high-to-low order | | addedChainBlocks | [ChainBlock](#protowire.ChainBlock) | repeated | The chain blocks that were added, in low-to-high order | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetBlocksRequestMessage +GetBlocksRequestMessage requests blocks between a certain block lowHash up to this +kaspad's current virtual. -GetBlocksRequestMessage requests blocks between a certain block lowHash up to this kaspad's current virtual. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -570,10 +841,17 @@ GetBlocksRequestMessage requests blocks between a certain block lowHash up to th | includeBlockVerboseData | [bool](#bool) | | | | includeTransactionVerboseData | [bool](#bool) | | | + + + + + ### GetBlocksResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | blockHashes | [string](#string) | repeated | | @@ -581,33 +859,56 @@ GetBlocksRequestMessage requests blocks between a certain block lowHash up to th | blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetBlockCountRequestMessage +GetBlockCountRequestMessage requests the current number of blocks in this kaspad. +Note that this number may decrease as pruning occurs. + + + + -GetBlockCountRequestMessage requests the current number of blocks in this kaspad. Note that this number may decrease as -pruning occurs. ### GetBlockCountResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | blockCount | [uint64](#uint64) | | | | headerCount | [uint64](#uint64) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetBlockDagInfoRequestMessage +GetBlockDagInfoRequestMessage requests general information about the current state +of this kaspad's DAG. + + + + -GetBlockDagInfoRequestMessage requests general information about the current state of this kaspad's DAG. ### GetBlockDagInfoResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | networkName | [string](#string) | | | @@ -619,69 +920,127 @@ GetBlockDagInfoRequestMessage requests general information about the current sta | virtualParentHashes | [string](#string) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### ResolveFinalityConflictRequestMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | finalityBlockHash | [string](#string) | | | + + + + + ### ResolveFinalityConflictResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### NotifyFinalityConflictsRequestMessage + + + + + + ### NotifyFinalityConflictsResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### FinalityConflictNotificationMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | violatingBlockHash | [string](#string) | | | + + + + + ### FinalityConflictResolvedNotificationMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | finalityBlockHash | [string](#string) | | | + + + + + ### ShutDownRequestMessage - ShutDownRequestMessage shuts down this kaspad. + + + + + ### ShutDownResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetHeadersRequestMessage +GetHeadersRequestMessage requests headers between the given startHash and the +current virtual, up to the given limit. -GetHeadersRequestMessage requests headers between the given startHash and the current virtual, up to the given limit. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | @@ -689,54 +1048,86 @@ GetHeadersRequestMessage requests headers between the given startHash and the cu | limit | [uint64](#uint64) | | | | isAscending | [bool](#bool) | | | + + + + + ### GetHeadersResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | headers | [string](#string) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### NotifyUtxosChangedRequestMessage - -NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications for the given addresses. +NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications +for the given addresses. This call is only available when this kaspad was started with `--utxoindex` See: UtxosChangedNotificationMessage + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | addresses | [string](#string) | repeated | | + + + + + ### NotifyUtxosChangedResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### UtxosChangedNotificationMessage - UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated. See: NotifyUtxosChangedRequestMessage + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | added | [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) | repeated | | | removed | [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) | repeated | | + + + + + ### UtxosByAddressesEntry + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | address | [string](#string) | | | @@ -774,43 +1165,73 @@ See: NotifyUtxosChangedRequestMessage ### RpcTransactionInput + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | previousOutpoint | [RpcOutpoint](#protowire.RpcOutpoint) | | | | signatureScript | [string](#string) | | | | sequence | [uint64](#uint64) | | | + + + + + ### RpcScriptPublicKey + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | version | [uint32](#uint32) | | | | scriptPublicKey | [string](#string) | | | + + + + + ### RpcTransactionOutput + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | amount | [uint64](#uint64) | | | | scriptPublicKey | [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) | | | + + + + + ### RpcOutpoint + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | transactionId | [string](#string) | | | | index | [uint32](#uint32) | | | + + + + + ### RpcUtxoEntry + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | amount | [uint64](#uint64) | | | @@ -818,56 +1239,90 @@ See: NotifyUtxosChangedRequestMessage | blockBlueScore | [uint64](#uint64) | | | | isCoinbase | [bool](#bool) | | | + + + + + ### GetUtxosByAddressesRequestMessage - GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses This call is only available when this kaspad was started with `--utxoindex` + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | addresses | [string](#string) | repeated | | + + + + + ### GetUtxosByAddressesResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | entries | [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) | repeated | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### GetVirtualSelectedParentBlueScoreRequestMessage +GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent +of the virtual block. + + + + -GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent of the virtual -block. ### GetVirtualSelectedParentBlueScoreResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | blueScore | [uint64](#uint64) | | | | error | [RPCError](#protowire.RPCError) | | | + + + + + ### NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - NotifyVirtualSelectedParentBlueScoreChangedRequestMessage registers this connection for virtualSelectedParentBlueScoreChanged notifications. See: VirtualSelectedParentBlueScoreChangedNotificationMessage + + + + + ### NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + + | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | error | [RPCError](#protowire.RPCError) | | | @@ -880,9 +1335,8 @@ See: VirtualSelectedParentBlueScoreChangedNotificationMessage ### VirtualSelectedParentBlueScoreChangedNotificationMessage - -VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score of the virtual's selected -parent changes. +VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score +of the virtual's selected parent changes. See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage @@ -895,8 +1349,81 @@ See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + + + +### BanRequestMessage +BanRequestMessage bans the given ip. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| ip | [string](#string) | | | + + + + + + + + +### BanResponseMessage + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + + + + + + +### UnbanRequestMessage +UnbanRequestMessage unbans the given ip. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| ip | [string](#string) | | | + + + + + + + + +### UnbanResponseMessage + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | + + + + + + + + +### SubmitBlockResponseMessage.RejectReason + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| NONE | 0 | | +| BLOCK_INVALID | 1 | | +| IS_IN_IBD | 2 | | + + diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 5bb291b95..2f43dbc0d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -4523,6 +4523,196 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSel return 0 } +// BanRequestMessage bans the given ip. +type BanRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` +} + +func (x *BanRequestMessage) Reset() { + *x = BanRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BanRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BanRequestMessage) ProtoMessage() {} + +func (x *BanRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[77] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BanRequestMessage.ProtoReflect.Descriptor instead. +func (*BanRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{77} +} + +func (x *BanRequestMessage) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +type BanResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *BanResponseMessage) Reset() { + *x = BanResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BanResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BanResponseMessage) ProtoMessage() {} + +func (x *BanResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[78] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BanResponseMessage.ProtoReflect.Descriptor instead. +func (*BanResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{78} +} + +func (x *BanResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + +// UnbanRequestMessage unbans the given ip. +type UnbanRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` +} + +func (x *UnbanRequestMessage) Reset() { + *x = UnbanRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnbanRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnbanRequestMessage) ProtoMessage() {} + +func (x *UnbanRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[79] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnbanRequestMessage.ProtoReflect.Descriptor instead. +func (*UnbanRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{79} +} + +func (x *UnbanRequestMessage) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +type UnbanResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *UnbanResponseMessage) Reset() { + *x = UnbanResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[80] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnbanResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnbanResponseMessage) ProtoMessage() {} + +func (x *UnbanResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[80] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnbanResponseMessage.ProtoReflect.Descriptor instead. +func (*UnbanResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{80} +} + +func (x *UnbanResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + var File_rpc_proto protoreflect.FileDescriptor var file_rpc_proto_rawDesc = []byte{ @@ -5124,10 +5314,23 @@ var file_rpc_proto_rawDesc = []byte{ 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, + 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, + 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, + 0x22, 0x40, 0x0a, 0x12, 0x42, 0x61, 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, 0x25, 0x0a, 0x13, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, + 0x61, 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, 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 ( @@ -5143,7 +5346,7 @@ func file_rpc_proto_rawDescGZIP() []byte { } var file_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 77) +var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 81) var file_rpc_proto_goTypes = []interface{}{ (SubmitBlockResponseMessage_RejectReason)(0), // 0: protowire.SubmitBlockResponseMessage.RejectReason (*RPCError)(nil), // 1: protowire.RPCError @@ -5223,17 +5426,21 @@ var file_rpc_proto_goTypes = []interface{}{ (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 75: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 76: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 77: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - (*BlockMessage)(nil), // 78: protowire.BlockMessage + (*BanRequestMessage)(nil), // 78: protowire.BanRequestMessage + (*BanResponseMessage)(nil), // 79: protowire.BanResponseMessage + (*UnbanRequestMessage)(nil), // 80: protowire.UnbanRequestMessage + (*UnbanResponseMessage)(nil), // 81: protowire.UnbanResponseMessage + (*BlockMessage)(nil), // 82: protowire.BlockMessage } var file_rpc_proto_depIdxs = []int32{ 1, // 0: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 78, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 82, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage 0, // 2: protowire.SubmitBlockResponseMessage.rejectReason:type_name -> protowire.SubmitBlockResponseMessage.RejectReason 1, // 3: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 78, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 82, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage 1, // 5: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError 1, // 6: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 78, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 82, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage 13, // 8: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage 13, // 9: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage 1, // 10: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError @@ -5283,11 +5490,13 @@ var file_rpc_proto_depIdxs = []int32{ 1, // 54: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError 1, // 55: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError 1, // 56: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 57, // [57:57] is the sub-list for method output_type - 57, // [57:57] is the sub-list for method input_type - 57, // [57:57] is the sub-list for extension type_name - 57, // [57:57] is the sub-list for extension extendee - 0, // [0:57] is the sub-list for field type_name + 1, // 57: protowire.BanResponseMessage.error:type_name -> protowire.RPCError + 1, // 58: protowire.UnbanResponseMessage.error:type_name -> protowire.RPCError + 59, // [59:59] is the sub-list for method output_type + 59, // [59:59] is the sub-list for method input_type + 59, // [59:59] is the sub-list for extension type_name + 59, // [59:59] is the sub-list for extension extendee + 0, // [0:59] is the sub-list for field type_name } func init() { file_rpc_proto_init() } @@ -6221,6 +6430,54 @@ func file_rpc_proto_init() { return nil } } + file_rpc_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BanRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BanResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnbanRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnbanResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -6228,7 +6485,7 @@ func file_rpc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_proto_rawDesc, NumEnums: 1, - NumMessages: 77, + NumMessages: 81, NumExtensions: 0, NumServices: 0, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index 87705bfc0..e504eb97a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -532,3 +532,21 @@ message NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { message VirtualSelectedParentBlueScoreChangedNotificationMessage { uint64 virtualSelectedParentBlueScore = 1; } + +// BanRequestMessage bans the given ip. +message BanRequestMessage{ + string ip = 1; +} + +message BanResponseMessage{ + RPCError error = 1000; +} + +// UnbanRequestMessage unbans the given ip. +message UnbanRequestMessage{ + string ip = 1; +} + +message UnbanResponseMessage{ + RPCError error = 1000; +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_ban.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_ban.go new file mode 100644 index 000000000..548cbf2f7 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_ban.go @@ -0,0 +1,37 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_BanRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.BanRequestMessage{ + IP: x.BanRequest.Ip, + }, nil +} + +func (x *KaspadMessage_BanRequest) fromAppMessage(message *appmessage.BanRequestMessage) error { + x.BanRequest = &BanRequestMessage{Ip: message.IP} + return nil +} + +func (x *KaspadMessage_BanResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.BanResponse.Error != nil { + err = &appmessage.RPCError{Message: x.BanResponse.Error.Message} + } + return &appmessage.BanResponseMessage{ + Error: err, + }, nil +} + +func (x *KaspadMessage_BanResponse) fromAppMessage(message *appmessage.BanResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.BanResponse = &BanResponseMessage{ + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_unban.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_unban.go new file mode 100644 index 000000000..82b504024 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_unban.go @@ -0,0 +1,37 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_UnbanRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.UnbanRequestMessage{ + IP: x.UnbanRequest.Ip, + }, nil +} + +func (x *KaspadMessage_UnbanRequest) fromAppMessage(message *appmessage.UnbanRequestMessage) error { + x.UnbanRequest = &UnbanRequestMessage{Ip: message.IP} + return nil +} + +func (x *KaspadMessage_UnbanResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.UnbanResponse.Error != nil { + err = &appmessage.RPCError{Message: x.UnbanResponse.Error.Message} + } + return &appmessage.UnbanResponseMessage{ + Error: err, + }, nil +} + +func (x *KaspadMessage_UnbanResponse) fromAppMessage(message *appmessage.UnbanResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.UnbanResponse = &UnbanResponseMessage{ + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index d0a8a08be..0b9f4bb21 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -685,6 +685,34 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.BanRequestMessage: + payload := new(KaspadMessage_BanRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.BanResponseMessage: + payload := new(KaspadMessage_BanResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.UnbanRequestMessage: + payload := new(KaspadMessage_UnbanRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.UnbanResponseMessage: + payload := new(KaspadMessage_UnbanResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil default: return nil, nil } From aeb8e9d2cd1ae003b0e86ed0f27ceb7fa14dab76 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 1 Feb 2021 18:52:49 +0200 Subject: [PATCH 303/351] Unban address after one day (#1479) * Unban address after one day * Unban addresses one by one Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- .../network/addressmanager/addressmanager.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/infrastructure/network/addressmanager/addressmanager.go b/infrastructure/network/addressmanager/addressmanager.go index adfe8f887..df01497b4 100644 --- a/infrastructure/network/addressmanager/addressmanager.go +++ b/infrastructure/network/addressmanager/addressmanager.go @@ -5,8 +5,10 @@ package addressmanager import ( + "github.com/kaspanet/kaspad/util/mstime" "net" "sync" + "time" "github.com/kaspanet/kaspad/app/appmessage" "github.com/pkg/errors" @@ -205,14 +207,13 @@ func (am *AddressManager) Unban(address *appmessage.NetAddress) error { defer am.mutex.Unlock() key := netAddressKey(address) - bannedAddress, ok := am.bannedAddresses[key.address] + _, ok := am.bannedAddresses[key.address] if !ok { return errors.Wrapf(ErrAddressNotFound, "address %s "+ "is not registered with the address manager as banned", address.TCPAddress()) } delete(am.bannedAddresses, key.address) - am.addresses[key] = bannedAddress return nil } @@ -222,6 +223,7 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) defer am.mutex.Unlock() key := netAddressKey(address) + am.unbanIfOldEnough(key.address) if _, ok := am.bannedAddresses[key.address]; !ok { if _, ok = am.addresses[key]; !ok { return false, errors.Wrapf(ErrAddressNotFound, "address %s "+ @@ -233,3 +235,15 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) return true, nil } + +func (am *AddressManager) unbanIfOldEnough(ipv6Address ipv6) { + address, ok := am.bannedAddresses[ipv6Address] + if !ok { + return + } + + const maxBanTime = 24 * time.Hour + if mstime.Since(address.Timestamp) > maxBanTime { + delete(am.bannedAddresses, ipv6Address) + } +} From 97be133cee6615d7e67b413d9008a79643262621 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Mon, 1 Feb 2021 19:15:50 +0200 Subject: [PATCH 304/351] Add logs to help debug long virtual parent selection. (#1470) Co-authored-by: Ori Newman --- .../calculate_past_utxo.go | 12 ++++++++++-- .../pick_virtual_parents.go | 17 +++++++++++------ .../consensusstatemanager/update_virtual.go | 10 +++++++++- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 6c6ba244a..3bf0328cf 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -4,6 +4,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/multiset" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -15,8 +16,10 @@ import ( func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) ( model.UTXODiff, externalapi.AcceptanceData, model.Multiset, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "CalculatePastUTXOAndAcceptanceData") + defer onEnd() + log.Debugf("CalculatePastUTXOAndAcceptanceData start for block %s", blockHash) - defer log.Debugf("CalculatePastUTXOAndAcceptanceData end for block %s", blockHash) if blockHash.Equal(csm.genesisHash) { log.Debugf("Block %s is the genesis. By definition, "+ @@ -35,6 +38,9 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * if err != nil { return nil, nil, nil, err } + log.Debugf("Restored the past UTXO of block %s with selectedParent %s. "+ + "Diff toAdd length: %d, toRemove length: %d", blockHash, blockGHOSTDAGData.SelectedParent(), + selectedParentPastUTXO.ToAdd().Len(), selectedParentPastUTXO.ToRemove().Len()) log.Debugf("Applying blue blocks to the selected parent past UTXO of block %s", blockHash) acceptanceData, utxoDiff, err := csm.applyMergeSetBlocks(blockHash, selectedParentPastUTXO, blockGHOSTDAGData) @@ -53,8 +59,10 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash * } func (csm *consensusStateManager) restorePastUTXO(blockHash *externalapi.DomainHash) (model.MutableUTXODiff, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "restorePastUTXO") + defer onEnd() + log.Debugf("restorePastUTXO start for block %s", blockHash) - defer log.Debugf("restorePastUTXO end for block %s", blockHash) var err error diff --git a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go index 459c313dd..84d835a83 100644 --- a/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go +++ b/domain/consensus/processes/consensusstatemanager/pick_virtual_parents.go @@ -1,6 +1,7 @@ package consensusstatemanager import ( + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/pkg/errors" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -9,8 +10,10 @@ import ( ) func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "pickVirtualParents") + defer onEnd() + log.Debugf("pickVirtualParents start for tips len: %d", len(tips)) - defer log.Debugf("pickVirtualParents end for tips len: %d", len(tips)) log.Debugf("Pushing all tips into a DownHeap") candidatesHeap := csm.dagTraversalManager.NewDownHeap() @@ -84,8 +87,8 @@ func (csm *consensusStateManager) pickVirtualParents(tips []*externalapi.DomainH func (csm *consensusStateManager) selectVirtualSelectedParent( candidatesHeap model.BlockHeap) (*externalapi.DomainHash, error) { - log.Tracef("selectVirtualSelectedParent start") - defer log.Tracef("selectVirtualSelectedParent end") + onEnd := logger.LogAndMeasureExecutionTime(log, "selectVirtualSelectedParent") + defer onEnd() disqualifiedCandidates := hashset.New() @@ -153,8 +156,8 @@ func (csm *consensusStateManager) selectVirtualSelectedParent( func (csm *consensusStateManager) mergeSetIncrease( candidate *externalapi.DomainHash, selectedVirtualParents hashset.HashSet) (uint64, error) { - log.Tracef("mergeSetIncrease start") - defer log.Tracef("mergeSetIncrease end") + onEnd := logger.LogAndMeasureExecutionTime(log, "mergeSetIncrease") + defer onEnd() visited := hashset.New() queue := csm.dagTraversalManager.NewDownHeap() @@ -204,8 +207,10 @@ func (csm *consensusStateManager) mergeSetIncrease( func (csm *consensusStateManager) boundedMergeBreakingParents( parents []*externalapi.DomainHash) (hashset.HashSet, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "boundedMergeBreakingParents") + defer onEnd() + log.Tracef("boundedMergeBreakingParents start for parents: %s", parents) - defer log.Tracef("boundedMergeBreakingParents end for parents: %s", parents) log.Debug("Temporarily setting virtual to all parents, so that we can run ghostdag on it") err := csm.dagTopologyManager.SetParents(model.VirtualBlockHash, parents) diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index c1f3eb13a..2a20d96fe 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -3,13 +3,16 @@ package consensusstatemanager import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/infrastructure/logger" ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) (*externalapi.SelectedChainPath, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "updateVirtual") + defer onEnd() + log.Debugf("updateVirtual start for block %s", newBlockHash) - defer log.Debugf("updateVirtual end for block %s", newBlockHash) log.Debugf("Saving a reference to the GHOSTDAG data of the old virtual") var oldVirtualSelectedParent *externalapi.DomainHash @@ -44,6 +47,9 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain if err != nil { return nil, err } + log.Debugf("Calculated the past UTXO of the new virtual. "+ + "Diff toAdd length: %d, toRemove length: %d", + virtualUTXODiff.ToAdd().Len(), virtualUTXODiff.ToRemove().Len()) log.Debugf("Staging new acceptance data for the virtual block") csm.acceptanceDataStore.Stage(model.VirtualBlockHash, virtualAcceptanceData) @@ -73,6 +79,8 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain if err != nil { return nil, err } + log.Debugf("Selected parent chain changes: %d blocks were removed and %d blocks were added", + len(selectedParentChainChanges.Removed), len(selectedParentChainChanges.Added)) } return selectedParentChainChanges, nil From e7f9606683f82a371ff7add9fe35fbb4548d8b20 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 2 Feb 2021 18:20:15 +0200 Subject: [PATCH 305/351] Add dummy go files for test only package, to mitigate golang/go#27333 (#1480) * Add dummy go files for test only package, to mitigate golang/go#27333 * Stop ignoring errors when producing the coverage * Add comments explaining the dummy go files * Make the coverage output non-json --- .github/workflows/go.yml | 3 +-- app/protocol/flows/testing/testing.go | 4 ++++ testing/integration/integration.go | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 app/protocol/flows/testing/testing.go create mode 100644 testing/integration/integration.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 57398f5b5..9ac54e3ba 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -63,8 +63,7 @@ jobs: go-version: 1.15 - name: Create coverage file - # Because of https://github.com/golang/go/issues/27333 this seem to "fail" even though nothing is wrong, so ignore the failure - run: go test -json -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./... || true + run: go test -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./... - name: Upload coverage file run: bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/app/protocol/flows/testing/testing.go b/app/protocol/flows/testing/testing.go new file mode 100644 index 000000000..a31e8c8c9 --- /dev/null +++ b/app/protocol/flows/testing/testing.go @@ -0,0 +1,4 @@ +package testing + +// Because of a bug in Go coverage fails if you have packages with test files only. See https://github.com/golang/go/issues/27333 +// So this is a dummy non-test go file in the package. diff --git a/testing/integration/integration.go b/testing/integration/integration.go new file mode 100644 index 000000000..6524145dc --- /dev/null +++ b/testing/integration/integration.go @@ -0,0 +1,4 @@ +package integration + +// Because of a bug in Go coverage fails if you have packages with test files only. See https://github.com/golang/go/issues/27333 +// So this is a dummy non-test go file in the package. From ee8fa32ff822ba1905afe14f7844f2af215a3499 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 3 Feb 2021 11:53:55 +0200 Subject: [PATCH 306/351] Refactor miner and mine when waiting for block to validate (#1481) * Refactor miner and mine when waiting for block to validate * Fix -n to work after the refactor. Change foundBlockChan capacity. Use lock instead of atomic in the template manager. * Fix self assignment * Fix lock * Fix Dockerfile * Add comment --- cmd/kaspaminer/mineloop.go | 155 +++++++++--------- .../templatemanager/templatemanager.go | 23 +++ docker/Dockerfile | 2 +- 3 files changed, 100 insertions(+), 80 deletions(-) create mode 100644 cmd/kaspaminer/templatemanager/templatemanager.go diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index d07da2f19..43d62f429 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -2,13 +2,13 @@ package main import ( nativeerrors "errors" + "github.com/kaspanet/kaspad/cmd/kaspaminer/templatemanager" + "github.com/kaspanet/kaspad/domain/consensus/model/pow" "github.com/kaspanet/kaspad/util/difficulty" "math/rand" "sync/atomic" "time" - "github.com/kaspanet/kaspad/domain/consensus/model/pow" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -29,11 +29,19 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond rand.Seed(time.Now().UnixNano()) // Seed the global concurrent-safe random source. errChan := make(chan error) - - templateStopChan := make(chan struct{}) - doneChan := make(chan struct{}) - spawn("mineLoop-internalLoop", func() { + + // We don't want to send router.DefaultMaxMessages blocks at once because there's + // a high chance we'll get disconnected from the node, so we make the channel + // capacity router.DefaultMaxMessages/2 (we give some slack for getBlockTemplate + // requests) + foundBlockChan := make(chan *externalapi.DomainBlock, router.DefaultMaxMessages/2) + + spawn("templatesLoop", func() { + templatesLoop(client, miningAddr, errChan) + }) + + spawn("blocksLoop", func() { const windowSize = 10 var expectedDurationForWindow time.Duration var windowExpectedEndTime time.Time @@ -44,16 +52,8 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond } blockInWindowIndex := 0 - for i := uint64(0); numberOfBlocks == 0 || i < numberOfBlocks; i++ { - - foundBlock := make(chan *externalapi.DomainBlock) - mineNextBlock(client, miningAddr, foundBlock, mineWhenNotSynced, templateStopChan, errChan) - block := <-foundBlock - templateStopChan <- struct{}{} - err := handleFoundBlock(client, block) - if err != nil { - errChan <- err - } + for { + foundBlockChan <- mineNextBlock(mineWhenNotSynced) if hasBlockRateTarget { blockInWindowIndex++ @@ -70,6 +70,17 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, targetBlocksPerSecond } } + }) + + spawn("handleFoundBlock", func() { + for i := uint64(0); numberOfBlocks == 0 || i < numberOfBlocks; i++ { + block := <-foundBlockChan + err := handleFoundBlock(client, block) + if err != nil { + errChan <- err + return + } + } doneChan <- struct{}{} }) @@ -99,21 +110,9 @@ func logHashRate() { }) } -func mineNextBlock(client *minerClient, miningAddr util.Address, foundBlock chan *externalapi.DomainBlock, mineWhenNotSynced bool, - templateStopChan chan struct{}, errChan chan error) { - - newTemplateChan := make(chan *appmessage.GetBlockTemplateResponseMessage) - spawn("templatesLoop", func() { - templatesLoop(client, miningAddr, newTemplateChan, errChan, templateStopChan) - }) - spawn("solveLoop", func() { - solveLoop(newTemplateChan, foundBlock, mineWhenNotSynced) - }) -} - func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error { blockHash := consensushashing.BlockHash(block) - log.Infof("Found block %s with parents %s. Submitting to %s", blockHash, block.Header.ParentHashes(), client.Address()) + log.Infof("Submitting block %s to %s", blockHash, client.Address()) rejectReason, err := client.SubmitBlock(block) if err != nil { @@ -132,48 +131,73 @@ func handleFoundBlock(client *minerClient, block *externalapi.DomainBlock) error return nil } -func solveBlock(block *externalapi.DomainBlock, stopChan chan struct{}, foundBlock chan *externalapi.DomainBlock) { - targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) - headerForMining := block.Header.ToMutable() - initialNonce := rand.Uint64() // Use the global concurrent-safe random source. - for i := initialNonce; i != initialNonce-1; i++ { - select { - case <-stopChan: - return - default: - headerForMining.SetNonce(i) - atomic.AddUint64(&hashesTried, 1) - if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { - block.Header = headerForMining.ToImmutable() - foundBlock <- block - return - } +func mineNextBlock(mineWhenNotSynced bool) *externalapi.DomainBlock { + nonce := rand.Uint64() // Use the global concurrent-safe random source. + for { + nonce++ + // For each nonce we try to build a block from the most up to date + // block template. + // In the rare case where the nonce space is exhausted for a specific + // block, it'll keep looping the nonce until a new block template + // is discovered. + block := getBlockForMining(mineWhenNotSynced) + targetDifficulty := difficulty.CompactToBig(block.Header.Bits()) + headerForMining := block.Header.ToMutable() + headerForMining.SetNonce(nonce) + atomic.AddUint64(&hashesTried, 1) + if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) { + block.Header = headerForMining.ToImmutable() + log.Infof("Found block %s with parents %s", consensushashing.BlockHash(block), block.Header.ParentHashes()) + return block } } } -func templatesLoop(client *minerClient, miningAddr util.Address, - newTemplateChan chan *appmessage.GetBlockTemplateResponseMessage, errChan chan error, stopChan chan struct{}) { +func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock { + tryCount := 0 + for { + tryCount++ + const sleepTime = 500 * time.Millisecond + shouldLog := (tryCount-1)%10 == 0 + template := templatemanager.Get() + if template == nil { + if shouldLog { + log.Info("Waiting for the initial template") + } + time.Sleep(sleepTime) + continue + } + if !template.IsSynced && !mineWhenNotSynced { + if shouldLog { + log.Warnf("Kaspad is not synced. Skipping current block template") + } + time.Sleep(sleepTime) + continue + } + return appmessage.MsgBlockToDomainBlock(template.MsgBlock) + } +} + +func templatesLoop(client *minerClient, miningAddr util.Address, errChan chan error) { getBlockTemplate := func() { template, err := client.GetBlockTemplate(miningAddr.String()) if nativeerrors.Is(err, router.ErrTimeout) { log.Warnf("Got timeout while requesting block template from %s: %s", client.Address(), err) return - } else if err != nil { + } + if err != nil { errChan <- errors.Errorf("Error getting block template from %s: %s", client.Address(), err) return } - newTemplateChan <- template + templatemanager.Set(template) } + getBlockTemplate() const tickerTime = 500 * time.Millisecond ticker := time.NewTicker(tickerTime) for { select { - case <-stopChan: - close(newTemplateChan) - return case <-client.blockAddedNotificationChan: getBlockTemplate() ticker.Reset(tickerTime) @@ -182,30 +206,3 @@ func templatesLoop(client *minerClient, miningAddr util.Address, } } } - -func solveLoop(newTemplateChan chan *appmessage.GetBlockTemplateResponseMessage, foundBlock chan *externalapi.DomainBlock, - mineWhenNotSynced bool) { - - var stopOldTemplateSolving chan struct{} - for template := range newTemplateChan { - if !template.IsSynced && !mineWhenNotSynced { - log.Warnf("Kaspad is not synced. Skipping current block template") - continue - } - - if stopOldTemplateSolving != nil { - close(stopOldTemplateSolving) - } - - stopOldTemplateSolving = make(chan struct{}) - block := appmessage.MsgBlockToDomainBlock(template.MsgBlock) - - stopOldTemplateSolvingCopy := stopOldTemplateSolving - spawn("solveBlock", func() { - solveBlock(block, stopOldTemplateSolvingCopy, foundBlock) - }) - } - if stopOldTemplateSolving != nil { - close(stopOldTemplateSolving) - } -} diff --git a/cmd/kaspaminer/templatemanager/templatemanager.go b/cmd/kaspaminer/templatemanager/templatemanager.go new file mode 100644 index 000000000..96eddfe67 --- /dev/null +++ b/cmd/kaspaminer/templatemanager/templatemanager.go @@ -0,0 +1,23 @@ +package templatemanager + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "sync" +) + +var currentTemplate *appmessage.GetBlockTemplateResponseMessage +var lock = &sync.Mutex{} + +// Get returns the template to work on +func Get() *appmessage.GetBlockTemplateResponseMessage { + lock.Lock() + defer lock.Unlock() + return currentTemplate +} + +// Set sets the current template to work on +func Set(template *appmessage.GetBlockTemplateResponseMessage) { + lock.Lock() + defer lock.Unlock() + currentTemplate = template +} diff --git a/docker/Dockerfile b/docker/Dockerfile index b4b16315a..1a00521e1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -27,7 +27,7 @@ WORKDIR /app RUN apk add --no-cache ca-certificates tini COPY --from=build /go/src/github.com/kaspanet/kaspad/kaspad /app/ -COPY --from=build /go/src/github.com/kaspanet/kaspad/sample-kaspad.conf /app/ +COPY --from=build /go/src/github.com/kaspanet/kaspad/infrastructure/config/sample-kaspad.conf /app/ USER nobody ENTRYPOINT [ "/sbin/tini", "--" ] From 238950cb98804956d5d9aea40e137a5c1b1154b6 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 3 Feb 2021 17:47:59 +0200 Subject: [PATCH 307/351] Add logs (#1484) * Add logs * Fix log name --- .../processes/blockprocessor/validateandinsertblock.go | 3 +++ .../processes/consensusstatemanager/calculate_past_utxo.go | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 528826ee6..fd2bcb748 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -290,6 +290,9 @@ func (bp *blockProcessor) discardAllChanges() { } func (bp *blockProcessor) commitAllChanges() error { + onEnd := logger.LogAndMeasureExecutionTime(log, "commitAllChanges") + defer onEnd() + dbTx, err := bp.databaseContext.Begin() if err != nil { return err diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 3bf0328cf..376a194f1 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -271,6 +271,9 @@ func (csm *consensusStateManager) checkTransactionMass( func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) ( model.ReadOnlyUTXOSetIterator, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "RestorePastUTXOSetIterator") + defer onEnd() + blockStatus, err := csm.resolveBlockStatus(blockHash) if err != nil { return nil, err @@ -284,7 +287,7 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash) defer log.Tracef("RestorePastUTXOSetIterator end for block %s", blockHash) - log.Tracef("Calculating UTXO diff for block %s", blockHash) + log.Debugf("Calculating UTXO diff for block %s", blockHash) blockDiff, err := csm.restorePastUTXO(blockHash) if err != nil { return nil, err From dbababb97889afa5046190c874406d074586b7c2 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Wed, 3 Feb 2021 19:45:39 +0200 Subject: [PATCH 308/351] Limit mempool size to million transactions and remove the least profitable transactions (#1483) * Limit mempool size to million transactions and remove the least profitable transactions * Simplify insert * Fix typo * Improve findTxIndexInOrderedTransactionsByFeeRate readability --- app/protocol/flowcontext/orphans.go | 3 + domain/consensus/model/externalapi/hash.go | 15 ++-- .../model/externalapi/transaction.go | 10 +++ .../processes/blockbuilder/block_builder.go | 3 +- .../verify_and_build_utxo.go | 5 +- .../processes/ghostdagmanager/compare.go | 2 +- .../consensus/utils/transactionid/compare.go | 10 --- domain/miningmanager/mempool/mempool.go | 90 +++++++++++++++++-- 8 files changed, 110 insertions(+), 28 deletions(-) delete mode 100644 domain/consensus/utils/transactionid/compare.go diff --git a/app/protocol/flowcontext/orphans.go b/app/protocol/flowcontext/orphans.go index b0f4ffe2c..36e915753 100644 --- a/app/protocol/flowcontext/orphans.go +++ b/app/protocol/flowcontext/orphans.go @@ -194,6 +194,9 @@ func (f *FlowContext) GetOrphanRoots(orphan *externalapi.DomainHash) ([]*externa if !blockInfo.Exists || blockInfo.BlockStatus == externalapi.StatusHeaderOnly { roots = append(roots, current) + } else { + log.Debugf("Block %s was skipped when checking for orphan roots: "+ + "exists: %t, status: %s", current, blockInfo.Exists, blockInfo.BlockStatus) } continue } diff --git a/domain/consensus/model/externalapi/hash.go b/domain/consensus/model/externalapi/hash.go index 21ab2fca6..4918cc4c3 100644 --- a/domain/consensus/model/externalapi/hash.go +++ b/domain/consensus/model/externalapi/hash.go @@ -85,6 +85,16 @@ func (hash *DomainHash) Equal(other *DomainHash) bool { return hash.hashArray == other.hashArray } +// Less returns true if hash is less than other +func (hash *DomainHash) Less(other *DomainHash) bool { + return bytes.Compare(hash.hashArray[:], other.hashArray[:]) < 0 +} + +// LessOrEqual returns true if hash is smaller or equal to other +func (hash *DomainHash) LessOrEqual(other *DomainHash) bool { + return bytes.Compare(hash.hashArray[:], other.hashArray[:]) <= 0 +} + // CloneHashes returns a clone of the given hashes slice. // Note: since DomainHash is a read-only type, the clone is shallow func CloneHashes(hashes []*DomainHash) []*DomainHash { @@ -106,8 +116,3 @@ func HashesEqual(a, b []*DomainHash) bool { } return true } - -// Less returns true iff hash a is less than hash b -func Less(a, b *DomainHash) bool { - return bytes.Compare(a.hashArray[:], b.hashArray[:]) < 0 -} diff --git a/domain/consensus/model/externalapi/transaction.go b/domain/consensus/model/externalapi/transaction.go index e65c871cc..11d3f7fb4 100644 --- a/domain/consensus/model/externalapi/transaction.go +++ b/domain/consensus/model/externalapi/transaction.go @@ -313,6 +313,16 @@ func (id *DomainTransactionID) Equal(other *DomainTransactionID) bool { return (*DomainHash)(id).Equal((*DomainHash)(other)) } +// Less returns true if id is less than other +func (id *DomainTransactionID) Less(other *DomainTransactionID) bool { + return (*DomainHash)(id).Less((*DomainHash)(other)) +} + +// LessOrEqual returns true if id is smaller or equal to other +func (id *DomainTransactionID) LessOrEqual(other *DomainTransactionID) bool { + return (*DomainHash)(id).LessOrEqual((*DomainHash)(other)) +} + // ByteArray returns the bytes in this transactionID represented as a byte array. // The transactionID bytes are cloned, therefore it is safe to modify the resulting array. func (id *DomainTransactionID) ByteArray() *[DomainHashSize]byte { diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 044134f67..43ccbc4fb 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -9,7 +9,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/util/mstime" ) @@ -197,7 +196,7 @@ func (bb *blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData externalapi sort.Slice(acceptedTransactions, func(i, j int) bool { acceptedTransactionIID := consensushashing.TransactionID(acceptedTransactions[i]) acceptedTransactionJID := consensushashing.TransactionID(acceptedTransactions[j]) - return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID) + return acceptedTransactionIID.Less(acceptedTransactionJID) }) return merkle.CalculateIDMerkleRoot(acceptedTransactions), nil diff --git a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go index b3d0b63c0..e986f7097 100644 --- a/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/verify_and_build_utxo.go @@ -5,8 +5,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" - "github.com/kaspanet/kaspad/domain/consensus/utils/transactionid" - "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" @@ -142,8 +140,7 @@ func calculateAcceptedIDMerkleRoot(multiblockAcceptanceData externalapi.Acceptan } } sort.Slice(acceptedTransactions, func(i, j int) bool { - return transactionid.Less( - consensushashing.TransactionID(acceptedTransactions[i]), + return consensushashing.TransactionID(acceptedTransactions[i]).Less( consensushashing.TransactionID(acceptedTransactions[j])) }) diff --git a/domain/consensus/processes/ghostdagmanager/compare.go b/domain/consensus/processes/ghostdagmanager/compare.go index 3b0b3777a..f8df7343e 100644 --- a/domain/consensus/processes/ghostdagmanager/compare.go +++ b/domain/consensus/processes/ghostdagmanager/compare.go @@ -60,7 +60,7 @@ func (gm *ghostdagManager) Less(blockHashA *externalapi.DomainHash, ghostdagData case 1: return false case 0: - return externalapi.Less(blockHashA, blockHashB) + return blockHashA.Less(blockHashB) default: panic("big.Int.Cmp is defined to always return -1/1/0 and nothing else") } diff --git a/domain/consensus/utils/transactionid/compare.go b/domain/consensus/utils/transactionid/compare.go deleted file mode 100644 index ab28853c2..000000000 --- a/domain/consensus/utils/transactionid/compare.go +++ /dev/null @@ -1,10 +0,0 @@ -package transactionid - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// Less returns true iff transaction ID a is less than hash b -func Less(a, b *externalapi.DomainTransactionID) bool { - return externalapi.Less((*externalapi.DomainHash)(a), (*externalapi.DomainHash)(b)) -} diff --git a/domain/miningmanager/mempool/mempool.go b/domain/miningmanager/mempool/mempool.go index 92e5e0e38..7d91145f4 100644 --- a/domain/miningmanager/mempool/mempool.go +++ b/domain/miningmanager/mempool/mempool.go @@ -7,6 +7,7 @@ package mempool import ( "container/list" "fmt" + "sort" "sync" "time" @@ -78,6 +79,8 @@ type mempool struct { mempoolUTXOSet *mempoolUTXOSet consensus consensusexternalapi.Consensus + orderedTransactionsByFeeRate []*consensusexternalapi.DomainTransaction + // nextExpireScan is the time after which the orphan pool will be // scanned in order to evict orphans. This is NOT a hard deadline as // the scan will only run when an orphan is added to the pool as opposed @@ -378,16 +381,18 @@ func (mp *mempool) removeBlockTransactionsFromPool(txs []*consensusexternalapi.D for _, tx := range txs[transactionhelper.CoinbaseTransactionIndex+1:] { txID := consensushashing.TransactionID(tx) - if _, exists := mp.fetchTxDesc(txID); !exists { + // We use the mempool transaction, because it has populated fee and mass + mempoolTx, exists := mp.fetchTxDesc(txID) + if !exists { continue } - err := mp.cleanTransactionFromSets(tx) + err := mp.cleanTransactionFromSets(mempoolTx.DomainTransaction) if err != nil { return err } - mp.updateBlockTransactionChainedTransactions(tx) + mp.updateBlockTransactionChainedTransactions(mempoolTx.DomainTransaction) } return nil } @@ -434,7 +439,7 @@ func (mp *mempool) cleanTransactionFromSets(tx *consensusexternalapi.DomainTrans delete(mp.pool, *txID) delete(mp.chainedTransactions, *txID) - return nil + return mp.removeTransactionFromOrderedTransactionsByFeeRate(tx) } // updateBlockTransactionChainedTransactions processes the dependencies of a @@ -504,7 +509,7 @@ func (mp *mempool) removeDoubleSpends(tx *consensusexternalapi.DomainTransaction // helper for maybeAcceptTransaction. // // This function MUST be called with the mempool lock held (for writes). -func (mp *mempool) addTransaction(tx *consensusexternalapi.DomainTransaction, mass uint64, fee uint64, parentsInPool []consensusexternalapi.DomainOutpoint) (*txDescriptor, error) { +func (mp *mempool) addTransaction(tx *consensusexternalapi.DomainTransaction, parentsInPool []consensusexternalapi.DomainOutpoint) (*txDescriptor, error) { // Add the transaction to the pool and mark the referenced outpoints // as spent by the pool. txDescriptor := &txDescriptor{ @@ -527,9 +532,77 @@ func (mp *mempool) addTransaction(tx *consensusexternalapi.DomainTransaction, ma return nil, err } + err = mp.addTransactionToOrderedTransactionsByFeeRate(tx) + if err != nil { + return nil, err + } + return txDescriptor, nil } +func (mp *mempool) findTxIndexInOrderedTransactionsByFeeRate(tx *consensusexternalapi.DomainTransaction) (int, error) { + if tx.Fee == 0 || tx.Mass == 0 { + return 0, errors.Errorf("findTxIndexInOrderedTransactionsByFeeRate expects a transaction with " + + "populated fee and mass") + } + txID := consensushashing.TransactionID(tx) + txFeeRate := float64(tx.Fee) / float64(tx.Mass) + + return sort.Search(len(mp.orderedTransactionsByFeeRate), func(i int) bool { + elementFeeRate := float64(mp.orderedTransactionsByFeeRate[i].Fee) / float64(mp.orderedTransactionsByFeeRate[i].Mass) + if elementFeeRate > txFeeRate { + return true + } + + if elementFeeRate == txFeeRate && txID.LessOrEqual(consensushashing.TransactionID(mp.orderedTransactionsByFeeRate[i])) { + return true + } + + return false + }), nil +} + +func (mp *mempool) addTransactionToOrderedTransactionsByFeeRate(tx *consensusexternalapi.DomainTransaction) error { + index, err := mp.findTxIndexInOrderedTransactionsByFeeRate(tx) + if err != nil { + return err + } + + mp.orderedTransactionsByFeeRate = append(mp.orderedTransactionsByFeeRate[:index], + append([]*consensusexternalapi.DomainTransaction{tx}, mp.orderedTransactionsByFeeRate[index:]...)...) + + return nil +} + +func (mp *mempool) removeTransactionFromOrderedTransactionsByFeeRate(tx *consensusexternalapi.DomainTransaction) error { + index, err := mp.findTxIndexInOrderedTransactionsByFeeRate(tx) + if err != nil { + return err + } + + txID := consensushashing.TransactionID(tx) + if !consensushashing.TransactionID(mp.orderedTransactionsByFeeRate[index]).Equal(txID) { + return errors.Errorf("Couldn't find %s in mp.orderedTransactionsByFeeRate", txID) + } + + mp.orderedTransactionsByFeeRate = append(mp.orderedTransactionsByFeeRate[:index], mp.orderedTransactionsByFeeRate[index+1:]...) + return nil +} + +func (mp *mempool) enforceTransactionLimit() error { + const limit = 1_000_000 + if len(mp.pool)+len(mp.chainedTransactions) > limit { + // mp.orderedTransactionsByFeeRate[0] is the least profitable transaction + txToRemove := mp.orderedTransactionsByFeeRate[0] + log.Debugf("Mempool size is over the limit of %d transactions. Removing %s", + limit, + consensushashing.TransactionID(txToRemove), + ) + return mp.removeTransactionAndItsChainedTransactions(txToRemove) + } + return nil +} + // checkPoolDoubleSpend checks whether or not the passed transaction is // attempting to spend coins already spent by other transactions in the pool. // Note it does not check for double spends against transactions already in the @@ -673,7 +746,7 @@ func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransac return nil, nil, txRuleError(RejectInsufficientFee, str) } // Add to transaction pool. - txDesc, err := mp.addTransaction(tx, tx.Mass, tx.Fee, parentsInPool) + txDesc, err := mp.addTransaction(tx, parentsInPool) if err != nil { return nil, nil, err } @@ -681,6 +754,11 @@ func (mp *mempool) maybeAcceptTransaction(tx *consensusexternalapi.DomainTransac log.Debugf("Accepted transaction %s (pool size: %d)", txID, len(mp.pool)) + err = mp.enforceTransactionLimit() + if err != nil { + return nil, nil, err + } + return nil, txDesc, nil } From 44280b9006ab0bb3246ee0ee97999023e6c7a170 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 4 Feb 2021 09:42:02 +0200 Subject: [PATCH 309/351] Require the --miningaddr parameter in kaspaminer. (#1482) Co-authored-by: Ori Newman --- cmd/kaspaminer/config.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/kaspaminer/config.go b/cmd/kaspaminer/config.go index f78860feb..ee3f2645b 100644 --- a/cmd/kaspaminer/config.go +++ b/cmd/kaspaminer/config.go @@ -77,6 +77,10 @@ func parseConfig() (*configFlags, error) { } } + if cfg.MiningAddr == "" { + return nil, errors.New("--miningaddr is required") + } + initLog(defaultLogFile, defaultErrLogFile) return cfg, nil From 6f53da18b19f05a7fd35e1229bbce7da9e8df101 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 4 Feb 2021 10:06:02 +0200 Subject: [PATCH 310/351] Increase stores cache (#1485) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- domain/consensus/factory.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 96a72c928..ae2702985 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -70,6 +70,10 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat pruningWindowSizeForCaches := int(dagParams.PruningDepth()) + // This is used for caches that are used as part of deletePastBlocks that need to traverse until + // the previous pruning point. + pruningWindowSizePlusFinalityDepthForCache := int(dagParams.PruningDepth() + dagParams.FinalityDepth()) + // Data Structures acceptanceDataStore := acceptancedatastore.New(200) blockStore, err := blockstore.New(dbManager, 200) @@ -80,11 +84,12 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat if err != nil { return nil, err } - blockRelationStore := blockrelationstore.New(pruningWindowSizeForCaches) - blockStatusStore := blockstatusstore.New(200) + blockRelationStore := blockrelationstore.New(pruningWindowSizePlusFinalityDepthForCache) + + blockStatusStore := blockstatusstore.New(pruningWindowSizePlusFinalityDepthForCache) multisetStore := multisetstore.New(200) pruningStore := pruningstore.New() - reachabilityDataStore := reachabilitydatastore.New(pruningWindowSizeForCaches) + reachabilityDataStore := reachabilitydatastore.New(pruningWindowSizePlusFinalityDepthForCache) utxoDiffStore := utxodiffstore.New(200) consensusStateStore := consensusstatestore.New(10_000) ghostdagDataStore := ghostdagdatastore.New(pruningWindowSizeForCaches) From 8941c518fccfbd3126114bf13ec38f9968db8068 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 4 Feb 2021 16:06:20 +0200 Subject: [PATCH 311/351] Remove the no-longer relevant highHashReceived mechanism in syncHeaders. (#1489) --- app/protocol/flows/blockrelay/ibd.go | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 6538fec4f..b0d937b0a 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -56,28 +56,28 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain } func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) error { - highHashReceived := false - for !highHashReceived { - log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) - highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) - if err != nil { - return err - } - log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) - - err = flow.downloadHeaders(highestSharedBlockHash, highHash) - if err != nil { - return err - } - - // We're finished once highHash has been inserted into the DAG - blockInfo, err := flow.Domain().Consensus().GetBlockInfo(highHash) - if err != nil { - return err - } - highHashReceived = blockInfo.Exists - log.Debugf("Headers downloaded from peer %s. Are further headers required: %t", flow.peer, !highHashReceived) + log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) + highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) + if err != nil { + return err } + log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) + + err = flow.downloadHeaders(highestSharedBlockHash, highHash) + if err != nil { + return err + } + + // If the highHash has not been received, the peer is misbehaving + highHashBlockInfo, err := flow.Domain().Consensus().GetBlockInfo(highHash) + if err != nil { + return err + } + if !highHashBlockInfo.Exists { + return protocolerrors.Errorf(true, "did not receive "+ + "highHash header %s from peer %s during header download", highHash, flow.peer) + } + log.Debugf("Headers downloaded from peer %s", flow.peer) return nil } From a792d4a19e3ab81363a80f86b8089807f8baef3b Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Thu, 4 Feb 2021 16:36:46 +0200 Subject: [PATCH 312/351] Don't fsync immediately after all writes (#1490) --- infrastructure/db/database/ldb/options.go | 1 + infrastructure/db/database/ldb/transaction.go | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/db/database/ldb/options.go b/infrastructure/db/database/ldb/options.go index 92e61cfea..00a9e5e47 100644 --- a/infrastructure/db/database/ldb/options.go +++ b/infrastructure/db/database/ldb/options.go @@ -8,6 +8,7 @@ var ( BlockCacheCapacity: 256 * opt.MiB, WriteBuffer: 128 * opt.MiB, DisableSeeksCompaction: true, + NoSync: true, } // Options is a function that returns a leveldb diff --git a/infrastructure/db/database/ldb/transaction.go b/infrastructure/db/database/ldb/transaction.go index 095bc37fc..10cfa2035 100644 --- a/infrastructure/db/database/ldb/transaction.go +++ b/infrastructure/db/database/ldb/transaction.go @@ -4,7 +4,6 @@ import ( "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/opt" ) // LevelDBTransaction is a thin wrapper around native leveldb @@ -41,7 +40,7 @@ func (tx *LevelDBTransaction) Commit() error { } tx.isClosed = true - return errors.WithStack(tx.db.ldb.Write(tx.batch, &opt.WriteOptions{Sync: true})) + return errors.WithStack(tx.db.ldb.Write(tx.batch, nil)) } // Rollback rolls back whatever changes were made to the From 608d1f8ef9c7f5d8d0b78502edf0715fabedbb3b Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 4 Feb 2021 17:12:33 +0200 Subject: [PATCH 313/351] Add TestBlueWork (#1488) * Add TestBlueWork * Add comments and blue score check Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- .../ghostdagmanager/ghostdag_test.go | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index d004f11dd..ee557cebc 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/util/difficulty" + "math" "math/big" "os" "path/filepath" @@ -177,6 +178,101 @@ func TestGHOSTDAG(t *testing.T) { }) } +// TestBlueWork tests if GHOSTDAG picks as selected parent the parent +// with the most blue work, even if its blue score is not the greatest. +// To do that it creates one chain of 3 blocks over genesis, and another +// chain of 2 blocks with more blue work than the 3 blocks chain, and +// checks that a block that points to both chain tips will have the +// 2 blocks chain tip as its selected parent. +func TestBlueWork(t *testing.T) { + dagTopology := &DAGTopologyManagerImpl{ + parentsMap: make(map[externalapi.DomainHash][]*externalapi.DomainHash), + } + + ghostdagDataStore := &GHOSTDAGDataStoreImpl{ + dagMap: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), + } + + blockHeadersStore := &blockHeadersStore{ + dagMap: make(map[externalapi.DomainHash]externalapi.BlockHeader), + } + + fakeGenesisHash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0}) + longestChainBlock1Hash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}) + longestChainBlock2Hash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{2}) + longestChainBlock3Hash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{3}) + heaviestChainBlock1Hash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{4}) + heaviestChainBlock2Hash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{5}) + tipHash := externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{6}) + + lowDifficultyHeader := blockheader.NewImmutableBlockHeader( + 0, + nil, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ) + + dagTopology.parentsMap[*fakeGenesisHash] = nil + ghostdagDataStore.dagMap[*fakeGenesisHash] = model.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil) + blockHeadersStore.dagMap[*fakeGenesisHash] = lowDifficultyHeader + + dagTopology.parentsMap[*longestChainBlock1Hash] = []*externalapi.DomainHash{fakeGenesisHash} + blockHeadersStore.dagMap[*longestChainBlock1Hash] = lowDifficultyHeader + + dagTopology.parentsMap[*longestChainBlock2Hash] = []*externalapi.DomainHash{longestChainBlock1Hash} + blockHeadersStore.dagMap[*longestChainBlock2Hash] = lowDifficultyHeader + + dagTopology.parentsMap[*longestChainBlock3Hash] = []*externalapi.DomainHash{longestChainBlock2Hash} + blockHeadersStore.dagMap[*longestChainBlock3Hash] = lowDifficultyHeader + + dagTopology.parentsMap[*heaviestChainBlock1Hash] = []*externalapi.DomainHash{fakeGenesisHash} + blockHeadersStore.dagMap[*heaviestChainBlock1Hash] = blockheader.NewImmutableBlockHeader( + 0, + nil, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + math.MaxUint32, // Put a very high difficulty so the chain that contains this block will have a very high blue work + 0, + ) + + dagTopology.parentsMap[*heaviestChainBlock2Hash] = []*externalapi.DomainHash{heaviestChainBlock1Hash} + blockHeadersStore.dagMap[*heaviestChainBlock2Hash] = lowDifficultyHeader + + dagTopology.parentsMap[*tipHash] = []*externalapi.DomainHash{heaviestChainBlock2Hash, longestChainBlock3Hash} + blockHeadersStore.dagMap[*tipHash] = lowDifficultyHeader + + manager := ghostdagmanager.New(nil, dagTopology, ghostdagDataStore, blockHeadersStore, 18) + blocksForGHOSTDAG := []*externalapi.DomainHash{ + longestChainBlock1Hash, + longestChainBlock2Hash, + longestChainBlock3Hash, + heaviestChainBlock1Hash, + heaviestChainBlock2Hash, + tipHash, + } + + for _, blockHash := range blocksForGHOSTDAG { + err := manager.GHOSTDAG(blockHash) + if err != nil { + t.Fatalf("GHOSTDAG: %+v", err) + } + } + + if ghostdagDataStore.dagMap[*longestChainBlock3Hash].BlueScore() <= ghostdagDataStore.dagMap[*heaviestChainBlock2Hash].BlueScore() { + t.Fatalf("Expected longestChainBlock3Hash to have greater blue score than heaviestChainBlock2Hash") + } + + if !ghostdagDataStore.dagMap[*tipHash].SelectedParent().Equal(heaviestChainBlock2Hash) { + t.Fatalf("Expected the block with the most blue work to be the selected parent of the tip") + } +} + func hashesToStrings(arr []*externalapi.DomainHash) []string { var strArr = make([]string, len(arr)) for i, hash := range arr { From 6bc7a4eb854e7ea2fef721fdcae8c361db581afe Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 7 Feb 2021 16:12:15 +0200 Subject: [PATCH 314/351] Allow GetMissingBlockBodyHashes return an empty list if the missing blocks were requested before IBD start (#1498) * Allow GetMissingBlockBodyHashes return an empty list if the missing blocks were requested before IBD start * Add link to issue in comment about error to be fixed --- app/protocol/flows/blockrelay/ibd.go | 7 +++++++ .../consensusstatemanager/import_pruning_utxo_set.go | 2 +- domain/consensus/processes/syncmanager/antipast.go | 10 ++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index b0d937b0a..54e65ed46 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -468,6 +468,13 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do if err != nil { return err } + if len(hashes) == 0 { + // Blocks can be inserted inside the DAG during IBD if those were requested before IBD started. + // In rare cases, all the IBD blocks might be already inserted by the time we reach this point. + // In these cases - GetMissingBlockBodyHashes would return an empty array. + log.Debugf("No missing block body hashes found.") + return nil + } for offset := 0; offset < len(hashes); offset += ibdBatchSize { var hashesToRequest []*externalapi.DomainHash diff --git a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go index f69387f13..81e9d4a7e 100644 --- a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go @@ -86,7 +86,7 @@ func (csm *consensusStateManager) importPruningPoint(newPruningPoint *externalap return err } - log.Debugf("Staging the new pruning point") + log.Debugf("Staging the new pruning point %s", newPruningPointHash) csm.pruningStore.StagePruningPoint(newPruningPointHash) log.Debugf("Populating the pruning point with UTXO entries") diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 44c85968e..82c9b1744 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -126,8 +126,14 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) lowHash = selectedChild } if !foundHeaderOnlyBlock { - // TODO: Once block children are fixed, this error - // should be returned instead of simply logged + if lowHash == highHash { + // Blocks can be inserted inside the DAG during IBD if those were requested before IBD started. + // In rare cases, all the IBD blocks might be already inserted by the time we reach this point. + // In these cases - return an empty list of blocks to sync + return []*externalapi.DomainHash{}, nil + } + // TODO: Once block children are fixed (https://github.com/kaspanet/kaspad/issues/1499), + // this error should be returned rather the logged log.Errorf("no header-only blocks between %s and %s", lowHash, highHash) } From d30f05b25059d79fd5efe94733e9627ed53cbc39 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 8 Feb 2021 10:04:19 +0200 Subject: [PATCH 315/351] Remove IsPushOnlyScript from mempool validation (#1492) * Remove IsPushOnlyScript from mempool validation * Fix TestCheckTransactionStandard --- domain/consensus/utils/txscript/error.go | 2 +- domain/consensus/utils/txscript/script.go | 11 ------- .../consensus/utils/txscript/script_test.go | 31 +++++++++++++------ domain/miningmanager/mempool/policy.go | 13 -------- domain/miningmanager/mempool/policy_test.go | 12 ------- 5 files changed, 22 insertions(+), 47 deletions(-) diff --git a/domain/consensus/utils/txscript/error.go b/domain/consensus/utils/txscript/error.go index 04c940016..73ddd3105 100644 --- a/domain/consensus/utils/txscript/error.go +++ b/domain/consensus/utils/txscript/error.go @@ -192,7 +192,7 @@ const ( // or to be in compressed format as a 32 byte string prefixed with 0x02 or 0x03 to signal oddness. ErrPubKeyFormat - // ErrCleanStack is returned when after evalution, the stack + // ErrCleanStack is returned when after evaluation, the stack // contains more than one element. ErrCleanStack diff --git a/domain/consensus/utils/txscript/script.go b/domain/consensus/utils/txscript/script.go index a65aa1037..61d677528 100644 --- a/domain/consensus/utils/txscript/script.go +++ b/domain/consensus/utils/txscript/script.go @@ -84,17 +84,6 @@ func isPushOnly(pops []parsedOpcode) bool { return true } -// IsPushOnlyScript returns whether or not the passed script only pushes data. -// -// False will be returned when the script does not parse. -func IsPushOnlyScript(script []byte) (bool, error) { - pops, err := parseScript(script) - if err != nil { - return false, err - } - return isPushOnly(pops), nil -} - // parseScriptTemplate is the same as parseScript but allows the passing of the // template list for testing purposes. When there are parse errors, it returns // the list of parsed opcodes up to the point of failure along with the error. diff --git a/domain/consensus/utils/txscript/script_test.go b/domain/consensus/utils/txscript/script_test.go index 16e2a708f..7e819366c 100644 --- a/domain/consensus/utils/txscript/script_test.go +++ b/domain/consensus/utils/txscript/script_test.go @@ -3723,6 +3723,17 @@ func TestPushedData(t *testing.T) { } } +// isPushOnlyScript returns whether or not the passed script only pushes data. +// +// False will be returned when the script does not parse. +func isPushOnlyScript(script []byte) (bool, error) { + pops, err := parseScript(script) + if err != nil { + return false, err + } + return isPushOnly(pops), nil +} + // TestHasCanonicalPush ensures the canonicalPush function works as expected. func TestHasCanonicalPush(t *testing.T) { t.Parallel() @@ -3734,8 +3745,8 @@ func TestHasCanonicalPush(t *testing.T) { err) continue } - if result, _ := IsPushOnlyScript(script); !result { - t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i, + if result, _ := isPushOnlyScript(script); !result { + t.Errorf("isPushOnlyScript: test #%d failed: %x\n", i, script) continue } @@ -3760,8 +3771,8 @@ func TestHasCanonicalPush(t *testing.T) { t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err) continue } - if result, _ := IsPushOnlyScript(script); !result { - t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script) + if result, _ := isPushOnlyScript(script); !result { + t.Errorf("StandardPushesTests isPushOnlyScript test #%d failed: %x\n", i, script) continue } pops, err := parseScript(script) @@ -3889,9 +3900,9 @@ func TestHasCanonicalPushes(t *testing.T) { } } -// TestIsPushOnlyScript ensures the IsPushOnlyScript function returns the +// TestIsPushOnly ensures the isPushOnly function returns the // expected results. -func TestIsPushOnlyScript(t *testing.T) { +func TestIsPushOnly(t *testing.T) { t.Parallel() tests := []struct { @@ -3922,19 +3933,19 @@ func TestIsPushOnlyScript(t *testing.T) { } for _, test := range tests { - isPushOnly, err := IsPushOnlyScript(test.script) + isPushOnly, err := isPushOnlyScript(test.script) if isPushOnly != test.expectedResult { - t.Errorf("IsPushOnlyScript (%s) wrong result\ngot: %v\nwant: "+ + t.Errorf("isPushOnlyScript (%s) wrong result\ngot: %v\nwant: "+ "%v", test.name, isPushOnly, test.expectedResult) } if test.shouldFail && err == nil { - t.Errorf("IsPushOnlyScript (%s) expected an error but got ", test.name) + t.Errorf("isPushOnlyScript (%s) expected an error but got ", test.name) } if !test.shouldFail && err != nil { - t.Errorf("IsPushOnlyScript (%s) expected no error but got: %v", test.name, err) + t.Errorf("isPushOnlyScript (%s) expected no error but got: %v", test.name, err) } } } diff --git a/domain/miningmanager/mempool/policy.go b/domain/miningmanager/mempool/policy.go index ff5538cf7..583797227 100644 --- a/domain/miningmanager/mempool/policy.go +++ b/domain/miningmanager/mempool/policy.go @@ -222,19 +222,6 @@ func checkTransactionStandard(tx *consensusexternalapi.DomainTransaction, policy maxStandardSigScriptSize) return txRuleError(RejectNonstandard, str) } - - // Each transaction input signature script must only contain - // opcodes which push data onto the stack. - isPushOnly, err := txscript.IsPushOnlyScript(txIn.SignatureScript) - if err != nil { - str := fmt.Sprintf("transaction input %d: IsPushOnlyScript: %t. Error %s", i, isPushOnly, err) - return txRuleError(RejectNonstandard, str) - } - if !isPushOnly { - str := fmt.Sprintf("transaction input %d: signature "+ - "script is not push only", i) - return txRuleError(RejectNonstandard, str) - } } // None of the output public key scripts can be a non-standard script or diff --git a/domain/miningmanager/mempool/policy_test.go b/domain/miningmanager/mempool/policy_test.go index 1968db7c2..2919e83a5 100644 --- a/domain/miningmanager/mempool/policy_test.go +++ b/domain/miningmanager/mempool/policy_test.go @@ -235,18 +235,6 @@ func TestCheckTransactionStandard(t *testing.T) { isStandard: false, code: RejectNonstandard, }, - { - name: "Signature script that does more than push data", - tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{{ - PreviousOutpoint: dummyPrevOut, - SignatureScript: []byte{ - txscript.OpCheckSigVerify}, - Sequence: constants.MaxTxInSequenceNum, - }}, Outputs: []*consensusexternalapi.DomainTransactionOutput{&dummyTxOut}}, - height: 300000, - isStandard: false, - code: RejectNonstandard, - }, { name: "Valid but non standard public key script", tx: consensusexternalapi.DomainTransaction{Version: 0, Inputs: []*consensusexternalapi.DomainTransactionInput{&dummyTxIn}, Outputs: []*consensusexternalapi.DomainTransactionOutput{{ From 5b5a7e60af6c8415b3971e9dca3ddf9158ef4e23 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 8 Feb 2021 10:45:13 +0200 Subject: [PATCH 316/351] Add aggregated headers processing logs (#1487) * Add aggregated headers processing logs * Unite headers and blocks log Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/protocol/flowcontext/blocks.go | 3 -- .../blocklogger/blocklogger.go | 38 +++++++++++-------- .../blockprocessor}/blocklogger/log.go | 2 +- .../blockprocessor/validateandinsertblock.go | 3 ++ 4 files changed, 27 insertions(+), 19 deletions(-) rename {app/protocol => domain/consensus/processes/blockprocessor}/blocklogger/blocklogger.go (58%) rename {app/protocol => domain/consensus/processes/blockprocessor}/blocklogger/log.go (81%) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 59e502b1e..6eacd7dd2 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -1,7 +1,6 @@ package flowcontext import ( - "github.com/kaspanet/kaspad/app/protocol/blocklogger" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/pkg/errors" @@ -38,8 +37,6 @@ func (f *FlowContext) OnNewBlock(block *externalapi.DomainBlock, } for i, newBlock := range newBlocks { - blocklogger.LogBlock(block) - log.Debugf("OnNewBlock: passing block %s transactions to mining manager", hash) _, err = f.Domain().MiningManager().HandleNewBlockTransactions(newBlock.Transactions) if err != nil { diff --git a/app/protocol/blocklogger/blocklogger.go b/domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go similarity index 58% rename from app/protocol/blocklogger/blocklogger.go rename to domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go index d17001b06..c012f82ba 100644 --- a/app/protocol/blocklogger/blocklogger.go +++ b/domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go @@ -5,7 +5,6 @@ package blocklogger import ( - "sync" "time" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -13,46 +12,55 @@ import ( ) var ( - receivedLogBlocks int64 - receivedLogTx int64 - lastBlockLogTime = mstime.Now() - mtx sync.Mutex + receivedLogBlocks int64 + receivedLogHeaders int64 + receivedLogTransactions int64 + lastBlockLogTime time.Time ) // LogBlock logs a new block blue score as an information message // to show progress to the user. In order to prevent spam, it limits logging to // one message every 10 seconds with duration and totals included. func LogBlock(block *externalapi.DomainBlock) { - mtx.Lock() - defer mtx.Unlock() + if len(block.Transactions) == 0 { + receivedLogHeaders++ + } else { + receivedLogBlocks++ + } - receivedLogBlocks++ - receivedLogTx += int64(len(block.Transactions)) + receivedLogTransactions += int64(len(block.Transactions)) - now := mstime.Now() + now := time.Now() duration := now.Sub(lastBlockLogTime) if duration < time.Second*10 { return } // Truncate the duration to 10s of milliseconds. - tDuration := duration.Round(10 * time.Millisecond) + truncatedDuration := duration.Round(10 * time.Millisecond) // Log information about new block blue score. blockStr := "blocks" if receivedLogBlocks == 1 { blockStr = "block" } + txStr := "transactions" - if receivedLogTx == 1 { + if receivedLogTransactions == 1 { txStr = "transaction" } - log.Infof("Processed %d %s in the last %s (%d %s, %s)", - receivedLogBlocks, blockStr, tDuration, receivedLogTx, + headerStr := "headers" + if receivedLogBlocks == 1 { + headerStr = "header" + } + + log.Infof("Processed %d %s and %d %s in the last %s (%d %s, %s)", + receivedLogBlocks, blockStr, receivedLogHeaders, headerStr, truncatedDuration, receivedLogTransactions, txStr, mstime.UnixMilliseconds(block.Header.TimeInMilliseconds())) receivedLogBlocks = 0 - receivedLogTx = 0 + receivedLogHeaders = 0 + receivedLogTransactions = 0 lastBlockLogTime = now } diff --git a/app/protocol/blocklogger/log.go b/domain/consensus/processes/blockprocessor/blocklogger/log.go similarity index 81% rename from app/protocol/blocklogger/log.go rename to domain/consensus/processes/blockprocessor/blocklogger/log.go index c28108500..2e424cb10 100644 --- a/app/protocol/blocklogger/log.go +++ b/domain/consensus/processes/blockprocessor/blocklogger/log.go @@ -8,4 +8,4 @@ import ( "github.com/kaspanet/kaspad/infrastructure/logger" ) -var log, _ = logger.Get(logger.SubsystemTags.PROT) +var log, _ = logger.Get(logger.SubsystemTags.BDAG) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index fd2bcb748..c7a051f2a 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -2,6 +2,7 @@ package blockprocessor import ( "fmt" + "github.com/kaspanet/kaspad/domain/consensus/processes/blockprocessor/blocklogger" "github.com/kaspanet/kaspad/util/difficulty" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -143,6 +144,8 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, return nil, logClosureErr } + blocklogger.LogBlock(block) + return &externalapi.BlockInsertionResult{ VirtualSelectedParentChainChanges: selectedParentChainChanges, }, nil From 1a3b16aaa3f6838d566ef807ac46c0a3af0c3504 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 8 Feb 2021 14:00:53 +0200 Subject: [PATCH 317/351] Don't change the new reindex root if the blue score of the selected tip is lower than the current reindex root (#1501) --- .../processes/reachabilitymanager/tree.go | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index e328f88f6..5597a10ba 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -337,30 +337,36 @@ func (rt *reachabilityManager) updateReindexRoot(selectedTip *externalapi.Domain rc := newReindexContext(rt) - // Iterate from reindexRootAncestor towards newReindexRoot - for { - chosenChild, err := rt.FindNextAncestor(selectedTip, reindexRootAncestor) - if err != nil { - return err + if !newReindexRoot.Equal(reindexRootAncestor) { + log.Debugf("Concentrating the intervals towards the new reindex root") + // Iterate from reindexRootAncestor towards newReindexRoot + for { + chosenChild, err := rt.FindNextAncestor(selectedTip, reindexRootAncestor) + if err != nil { + return err + } + + isFinalReindexRoot := chosenChild.Equal(newReindexRoot) + + // Concentrate interval from current ancestor to its chosen child + err = rc.concentrateInterval(reindexRootAncestor, chosenChild, isFinalReindexRoot) + if err != nil { + return err + } + + if isFinalReindexRoot { + break + } + + reindexRootAncestor = chosenChild } - - isFinalReindexRoot := chosenChild.Equal(newReindexRoot) - - // Concentrate interval from current ancestor to it's chosen child - err = rc.concentrateInterval(reindexRootAncestor, chosenChild, isFinalReindexRoot) - if err != nil { - return err - } - - if isFinalReindexRoot { - break - } - - reindexRootAncestor = chosenChild + } else { + log.Debugf("newReindexRoot is the same as reindexRootAncestor. Skipping concentration...") } // Update reindex root data store rt.stageReindexRoot(newReindexRoot) + log.Debugf("Updated the reindex root to %s", newReindexRoot) return nil } @@ -393,8 +399,12 @@ func (rt *reachabilityManager) findNextReindexRoot(currentReindexRoot, selectedT // We have reindex root out of selected tip chain, however we switch chains only after a sufficient // threshold of reindexSlack score in order to address possible alternating reorg attacks. // The reindexSlack constant is used as an heuristic for a large enough constant on the one hand, but - // one which will not harm performance on the other hand - given the available slack at the chain split point - if selectedTipGHOSTDAGData.BlueScore()-currentRootGHOSTDAGData.BlueScore() < rt.reindexSlack { + // one which will not harm performance on the other hand - given the available slack at the chain split point. + // + // Note: In some cases the blue score selected tip can be lower than the current reindex root blue score. + // If that's the case we keep the reindex root unchanged. + if selectedTipGHOSTDAGData.BlueScore() < currentRootGHOSTDAGData.BlueScore() || + selectedTipGHOSTDAGData.BlueScore()-currentRootGHOSTDAGData.BlueScore() < rt.reindexSlack { // Return current - this indicates no change return currentReindexRoot, currentReindexRoot, nil } @@ -422,6 +432,11 @@ func (rt *reachabilityManager) findNextReindexRoot(currentReindexRoot, selectedT return nil, nil, err } + if selectedTipGHOSTDAGData.BlueScore() < chosenChildGHOSTDAGData.BlueScore() { + return nil, nil, errors.Errorf("chosen child %s has blue score greater "+ + "than %s although it's in its selected parent chain", chosenChild, selectedTip) + } + if selectedTipGHOSTDAGData.BlueScore()-chosenChildGHOSTDAGData.BlueScore() < rt.reindexWindow { break } From 4a354cd5383c4f62559d8cc2fbef77cd028e9beb Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 8 Feb 2021 14:59:43 +0200 Subject: [PATCH 318/351] Validate transactions on BuildBlock (#1491) * Validate transactions on BuildBlock * Rename tx -> transactions * Add transaction validator to block builder constructor and fix TestValidateAndInsertErrors Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- domain/consensus/factory.go | 2 + .../processes/blockbuilder/block_builder.go | 66 ++++++++++++- .../blockbuilder/block_builder_test.go | 96 +++++++++++++++++-- .../validateandinsertblock_test.go | 3 +- domain/consensus/ruleerrors/rule_error.go | 4 +- .../consensus/ruleerrors/rule_error_test.go | 4 +- 6 files changed, 157 insertions(+), 18 deletions(-) diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index ae2702985..4a4e2b123 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -275,6 +275,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat coinbaseManager, consensusStateManager, ghostdagManager, + transactionValidator, + acceptanceDataStore, blockRelationStore, multisetStore, diff --git a/domain/consensus/processes/blockbuilder/block_builder.go b/domain/consensus/processes/blockbuilder/block_builder.go index 43ccbc4fb..fde8216c8 100644 --- a/domain/consensus/processes/blockbuilder/block_builder.go +++ b/domain/consensus/processes/blockbuilder/block_builder.go @@ -1,7 +1,9 @@ package blockbuilder import ( + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/pkg/errors" "sort" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -21,6 +23,7 @@ type blockBuilder struct { coinbaseManager model.CoinbaseManager consensusStateManager model.ConsensusStateManager ghostdagManager model.GHOSTDAGManager + transactionValidator model.TransactionValidator acceptanceDataStore model.AcceptanceDataStore blockRelationStore model.BlockRelationStore @@ -37,6 +40,7 @@ func New( coinbaseManager model.CoinbaseManager, consensusStateManager model.ConsensusStateManager, ghostdagManager model.GHOSTDAGManager, + transactionValidator model.TransactionValidator, acceptanceDataStore model.AcceptanceDataStore, blockRelationStore model.BlockRelationStore, @@ -51,10 +55,12 @@ func New( coinbaseManager: coinbaseManager, consensusStateManager: consensusStateManager, ghostdagManager: ghostdagManager, - acceptanceDataStore: acceptanceDataStore, - blockRelationStore: blockRelationStore, - multisetStore: multisetStore, - ghostdagDataStore: ghostdagDataStore, + transactionValidator: transactionValidator, + + acceptanceDataStore: acceptanceDataStore, + blockRelationStore: blockRelationStore, + multisetStore: multisetStore, + ghostdagDataStore: ghostdagDataStore, } } @@ -72,6 +78,11 @@ func (bb *blockBuilder) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, func (bb *blockBuilder) buildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { + err := bb.validateTransactions(transactions) + if err != nil { + return nil, err + } + coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData) if err != nil { return nil, err @@ -89,6 +100,53 @@ func (bb *blockBuilder) buildBlock(coinbaseData *externalapi.DomainCoinbaseData, }, nil } +func (bb *blockBuilder) validateTransactions(transactions []*externalapi.DomainTransaction) error { + invalidTransactions := make([]ruleerrors.InvalidTransaction, 0) + for _, transaction := range transactions { + err := bb.validateTransaction(transaction) + if err != nil { + if !errors.As(err, &ruleerrors.RuleError{}) { + return err + } + invalidTransactions = append(invalidTransactions, + ruleerrors.InvalidTransaction{Transaction: transaction, Error: err}) + } + } + + if len(invalidTransactions) > 0 { + return ruleerrors.NewErrInvalidTransactionsInNewBlock(invalidTransactions) + } + + return nil +} + +func (bb *blockBuilder) validateTransaction(transaction *externalapi.DomainTransaction) error { + originalEntries := make([]externalapi.UTXOEntry, len(transaction.Inputs)) + for i, input := range transaction.Inputs { + originalEntries[i] = input.UTXOEntry + input.UTXOEntry = nil + } + + defer func() { + for i, input := range transaction.Inputs { + input.UTXOEntry = originalEntries[i] + } + }() + + err := bb.consensusStateManager.PopulateTransactionWithUTXOEntries(transaction) + if err != nil { + return err + } + + virtualSelectedParentMedianTime, err := bb.pastMedianTimeManager.PastMedianTime(model.VirtualBlockHash) + if err != nil { + return err + } + + return bb.transactionValidator.ValidateTransactionInContextAndPopulateMassAndFee(transaction, + model.VirtualBlockHash, virtualSelectedParentMedianTime) +} + func (bb *blockBuilder) newBlockCoinbaseTransaction( coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) { diff --git a/domain/consensus/processes/blockbuilder/block_builder_test.go b/domain/consensus/processes/blockbuilder/block_builder_test.go index 9cb48e636..8bcec9422 100644 --- a/domain/consensus/processes/blockbuilder/block_builder_test.go +++ b/domain/consensus/processes/blockbuilder/block_builder_test.go @@ -1,6 +1,8 @@ package blockbuilder_test import ( + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" "testing" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" @@ -22,12 +24,14 @@ func TestBuildBlockErrorCases(t *testing.T) { } defer teardown(false) - tests := []struct { - name string - coinbaseData *externalapi.DomainCoinbaseData - transactions []*externalapi.DomainTransaction - expectedErrorType error - }{ + type testData struct { + name string + coinbaseData *externalapi.DomainCoinbaseData + transactions []*externalapi.DomainTransaction + testFunc func(test testData, err error) error + } + + tests := []testData{ { "scriptPublicKey too long", &externalapi.DomainCoinbaseData{ @@ -38,7 +42,78 @@ func TestBuildBlockErrorCases(t *testing.T) { ExtraData: nil, }, nil, - ruleerrors.ErrBadCoinbasePayloadLen, + func(_ testData, err error) error { + if !errors.Is(err, ruleerrors.ErrBadCoinbasePayloadLen) { + return errors.Errorf("Unexpected error: %+v", err) + } + return nil + }, + }, + { + "missing UTXO transactions", + &externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + ExtraData: nil, + }, + []*externalapi.DomainTransaction{ + { + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, Index: 0}, + }, + }, + Outputs: nil, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + Gas: 0, + PayloadHash: externalapi.DomainHash{}, + Payload: []byte{0}, + }, + { + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{ + { + PreviousOutpoint: externalapi.DomainOutpoint{ + TransactionID: externalapi.DomainTransactionID{}, Index: 0}, + }, + }, + Outputs: nil, + LockTime: 0, + SubnetworkID: subnetworks.SubnetworkIDNative, + Gas: 0, + PayloadHash: externalapi.DomainHash{}, + Payload: []byte{1}, + }, + }, + + func(test testData, err error) error { + errInvalidTransactionsInNewBlock := ruleerrors.ErrInvalidTransactionsInNewBlock{} + if !errors.As(err, &errInvalidTransactionsInNewBlock) { + return errors.Errorf("Unexpected error: %+v", err) + } + + if len(errInvalidTransactionsInNewBlock.InvalidTransactions) != len(test.transactions) { + return errors.Errorf("Expected %d transaction but got %d", + len(test.transactions), len(errInvalidTransactionsInNewBlock.InvalidTransactions)) + } + + for i, invalidTx := range errInvalidTransactionsInNewBlock.InvalidTransactions { + if !invalidTx.Transaction.Equal(test.transactions[i]) { + return errors.Errorf("Expected transaction %d to be equal to its corresponding "+ + "test transaction", i) + } + + if !errors.As(invalidTx.Error, &ruleerrors.ErrMissingTxOut{}) { + return errors.Errorf("Unexpected error for transaction %d: %+v", i, invalidTx.Error) + } + } + return nil + }, }, } @@ -48,8 +123,11 @@ func TestBuildBlockErrorCases(t *testing.T) { t.Errorf("%s: No error from BuildBlock", test.name) return } - if test.expectedErrorType != nil && !errors.Is(err, test.expectedErrorType) { - t.Errorf("%s: Expected error '%s', but got '%s'", test.name, test.expectedErrorType, err) + + err := test.testFunc(test, err) + if err != nil { + t.Errorf("%s: %s", test.name, err) + return } } }) diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go index 03086d213..8115d76af 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock_test.go @@ -126,7 +126,8 @@ func TestValidateAndInsertErrors(t *testing.T) { tipHash, emptyCoinbase, tx1 := initData(params) // Tests all the error case on the function: "checkBlockStatus"(sub-function in function validateBlock) - blockWithStatusInvalid, err := tc.BuildBlock(&emptyCoinbase, []*externalapi.DomainTransaction{tx1, tx1}) + blockWithStatusInvalid, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, + &emptyCoinbase, []*externalapi.DomainTransaction{tx1, tx1}) if err != nil { t.Fatalf("AddBlock: %+v", err) } diff --git a/domain/consensus/ruleerrors/rule_error.go b/domain/consensus/ruleerrors/rule_error.go index 12d2e106e..8554a17af 100644 --- a/domain/consensus/ruleerrors/rule_error.go +++ b/domain/consensus/ruleerrors/rule_error.go @@ -263,11 +263,11 @@ func NewErrMissingParents(missingParentHashes []*externalapi.DomainHash) error { // InvalidTransaction is a struct containing an invalid transaction, and the error explaining why it's invalid. type InvalidTransaction struct { Transaction *externalapi.DomainTransaction - err error + Error error } func (invalid InvalidTransaction) String() string { - return fmt.Sprintf("(%v: %s)", consensushashing.TransactionID(invalid.Transaction), invalid.err) + return fmt.Sprintf("(%v: %s)", consensushashing.TransactionID(invalid.Transaction), invalid.Error) } // ErrInvalidTransactionsInNewBlock indicates that some transactions in a new block are invalid diff --git a/domain/consensus/ruleerrors/rule_error_test.go b/domain/consensus/ruleerrors/rule_error_test.go index 717375f84..c74dbbc05 100644 --- a/domain/consensus/ruleerrors/rule_error_test.go +++ b/domain/consensus/ruleerrors/rule_error_test.go @@ -56,8 +56,8 @@ func TestNewErrInvalidTransactionsInNewBlock(t *testing.T) { if len(inner.InvalidTransactions) != 1 { t.Fatalf("TestNewErrInvalidTransactionsInNewBlock: Expected len(inner.MissingOutpoints) 1, found: %d", len(inner.InvalidTransactions)) } - if inner.InvalidTransactions[0].err != ErrNoTxInputs { - t.Fatalf("TestNewErrInvalidTransactionsInNewBlock: Expected ErrNoTxInputs. found: %v", inner.InvalidTransactions[0].err) + if inner.InvalidTransactions[0].Error != ErrNoTxInputs { + t.Fatalf("TestNewErrInvalidTransactionsInNewBlock: Expected ErrNoTxInputs. found: %v", inner.InvalidTransactions[0].Error) } if inner.InvalidTransactions[0].Transaction.Fee != 1337 { t.Fatalf("TestNewErrInvalidTransactionsInNewBlock: Expected 1337. found: %v", inner.InvalidTransactions[0].Transaction.Fee) From 3d0a2a47b2fb27b151968c7b5d2abba3b19d533b Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 8 Feb 2021 15:24:26 +0200 Subject: [PATCH 319/351] Move testGHOSTDagSorter to testutils, and build a boilerplate for overriding specific managers (#1486) * Move testGHOSTDagSorter to testutils * Allow overriding managers in consensus, starting with ghostdag * Add test prefix to SetDataDir and SetGHOSTDAGManager Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- domain/consensus/constructors.go | 6 +++ domain/consensus/factory.go | 48 +++++++++++-------- .../virtual_parents_test.go | 8 ++-- .../dagtraversalmanager/window_test.go | 2 +- .../testutils/test_ghostdag.go} | 2 +- 5 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 domain/consensus/constructors.go rename domain/consensus/{test_ghostdag_sorter.go => utils/testutils/test_ghostdag.go} (98%) diff --git a/domain/consensus/constructors.go b/domain/consensus/constructors.go new file mode 100644 index 000000000..29b7a2167 --- /dev/null +++ b/domain/consensus/constructors.go @@ -0,0 +1,6 @@ +package consensus + +import "github.com/kaspanet/kaspad/domain/consensus/model" + +// GHOSTDAGManagerConstructor is the function signature for a constructor of a type implementing model.GHOSTDAGManager +type GHOSTDAGManagerConstructor func(model.DBReader, model.DAGTopologyManager, model.GHOSTDAGDataStore, model.BlockHeaderStore, model.KType) model.GHOSTDAGManager diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 4a4e2b123..743c08f2f 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -51,15 +51,21 @@ type Factory interface { externalapi.Consensus, error) NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode bool, testName string) ( tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) - NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string, isArchivalNode bool) ( - tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) + + SetTestDataDir(dataDir string) + SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) } -type factory struct{} +type factory struct { + dataDir string + ghostdagConstructor GHOSTDAGManagerConstructor +} // NewFactory creates a new Consensus factory func NewFactory() Factory { - return &factory{} + return &factory{ + ghostdagConstructor: ghostdagmanager.New, + } } // NewConsensus instantiates a new Consensus @@ -107,7 +113,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat reachabilityManager, blockRelationStore, ghostdagDataStore) - ghostdagManager := ghostdagmanager.New( + ghostdagManager := f.ghostdagConstructor( dbManager, dagTopologyManager, ghostdagDataStore, @@ -382,19 +388,14 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode bool, testName string) ( tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) { - - dataDir, err := ioutil.TempDir("", testName) - if err != nil { - return nil, nil, err + datadir := f.dataDir + if datadir == "" { + datadir, err = ioutil.TempDir("", testName) + if err != nil { + return nil, nil, err + } } - - return f.NewTestConsensusWithDataDir(dagParams, dataDir, isArchivalNode) -} - -func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string, isArchivalNode bool) ( - tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) { - - db, err := ldb.NewLevelDB(dataDir) + db, err := ldb.NewLevelDB(datadir) if err != nil { return nil, nil, err } @@ -404,9 +405,7 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD } consensusAsImplementation := consensusAsInterface.(*consensus) - testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager) - testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator) tstConsensus := &testConsensus{ @@ -422,12 +421,19 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD teardown = func(keepDataDir bool) { db.Close() if !keepDataDir { - err := os.RemoveAll(dataDir) + err := os.RemoveAll(f.dataDir) if err != nil { log.Errorf("Error removing data directory for test consensus: %s", err) } } } - return tstConsensus, teardown, nil } + +func (f *factory) SetTestDataDir(dataDir string) { + f.dataDir = dataDir +} + +func (f *factory) SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) { + f.ghostdagConstructor = ghostdagConstructor +} diff --git a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go index dfaa9c990..b5cb2176b 100644 --- a/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go +++ b/domain/consensus/processes/consensusstatemanager/virtual_parents_test.go @@ -32,8 +32,8 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) { t.Fatalf("Consensus failed building a block: %v", err) } blockParents := block.Header.ParentHashes() - sort.Sort(consensus.NewTestGhostDAGSorter(virtualRelations.Parents, tc, t)) - sort.Sort(consensus.NewTestGhostDAGSorter(blockParents, tc, t)) + sort.Sort(testutils.NewTestGhostDAGSorter(virtualRelations.Parents, tc, t)) + sort.Sort(testutils.NewTestGhostDAGSorter(blockParents, tc, t)) if !externalapi.HashesEqual(virtualRelations.Parents, blockParents) { t.Fatalf("Block relations and BuildBlock return different parents for virtual, %s != %s", virtualRelations.Parents, blockParents) } @@ -54,7 +54,7 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) { } virtualParents := getSortedVirtualParents(tc) - sort.Sort(consensus.NewTestGhostDAGSorter(parents, tc, t)) + sort.Sort(testutils.NewTestGhostDAGSorter(parents, tc, t)) // Make sure the first half of the blocks are with highest blueWork // we use (max+1)/2 because the first "half" is rounded up, so `(dividend + (divisor - 1)) / divisor` = `(max + (2-1))/2` = `(max+1)/2` @@ -102,7 +102,7 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) { parents = append(parents, block) } - sort.Sort(consensus.NewTestGhostDAGSorter(parents, tc, t)) + sort.Sort(testutils.NewTestGhostDAGSorter(parents, tc, t)) virtualParents = getSortedVirtualParents(tc) if !externalapi.HashesEqual(virtualParents, parents) { t.Fatalf("Expected VirtualParents and parents to be equal, instead: %s != %s", virtualParents, parents) diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index e62c52e61..188129bb6 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -344,7 +344,7 @@ func TestBlueBlockWindow(t *testing.T) { if err != nil { t.Fatalf("BlueWindow: %s", err) } - sort.Sort(consensus.NewTestGhostDAGSorter(window, tc, t)) + sort.Sort(testutils.NewTestGhostDAGSorter(window, tc, t)) if err := checkWindowIDs(window, blockData.expectedWindowWithGenesisPadding, idByBlockMap); err != nil { t.Errorf("Unexpected values for window for block %s: %s", blockData.id, err) } diff --git a/domain/consensus/test_ghostdag_sorter.go b/domain/consensus/utils/testutils/test_ghostdag.go similarity index 98% rename from domain/consensus/test_ghostdag_sorter.go rename to domain/consensus/utils/testutils/test_ghostdag.go index a42b49140..c72e968c9 100644 --- a/domain/consensus/test_ghostdag_sorter.go +++ b/domain/consensus/utils/testutils/test_ghostdag.go @@ -1,4 +1,4 @@ -package consensus +package testutils import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" From 8225f7fb3c113176d7cf8380bfda65513f4eeea5 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 8 Feb 2021 16:33:21 +0200 Subject: [PATCH 320/351] Add GetInfo RPC command (#1504) * Add GetInfo RPC command * Rename ID to p2p ID --- app/appmessage/message.go | 4 + app/appmessage/rpc_get_info.go | 38 +++++ app/rpc/rpc.go | 1 + app/rpc/rpchandlers/get_info.go | 13 ++ cmd/kaspactl/commands.go | 1 + .../grpcserver/protowire/messages.pb.go | 93 +++++++--- .../grpcserver/protowire/messages.proto | 2 + .../server/grpcserver/protowire/rpc.md | 28 +++ .../server/grpcserver/protowire/rpc.pb.go | 159 ++++++++++++++++-- .../server/grpcserver/protowire/rpc.proto | 9 + .../grpcserver/protowire/rpc_get_info.go | 37 ++++ .../server/grpcserver/protowire/wire.go | 14 ++ 12 files changed, 359 insertions(+), 40 deletions(-) create mode 100644 app/appmessage/rpc_get_info.go create mode 100644 app/rpc/rpchandlers/get_info.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_info.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 15ad2a5c9..462617757 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -127,6 +127,8 @@ const ( CmdBanResponseMessage CmdUnbanRequestMessage CmdUnbanResponseMessage + CmdGetInfoRequestMessage + CmdGetInfoResponseMessage ) // ProtocolMessageCommandToString maps all MessageCommands to their string representation @@ -228,6 +230,8 @@ var RPCMessageCommandToString = map[MessageCommand]string{ CmdBanResponseMessage: "BanResponse", CmdUnbanRequestMessage: "UnbanRequest", CmdUnbanResponseMessage: "UnbanResponse", + CmdGetInfoRequestMessage: "GetInfoRequestMessage", + CmdGetInfoResponseMessage: "GeInfoResponseMessage", } // Message is an interface that describes a kaspa message. A type that diff --git a/app/appmessage/rpc_get_info.go b/app/appmessage/rpc_get_info.go new file mode 100644 index 000000000..4fff7ddeb --- /dev/null +++ b/app/appmessage/rpc_get_info.go @@ -0,0 +1,38 @@ +package appmessage + +// GetInfoRequestMessage is an appmessage corresponding to +// its respective RPC message +type GetInfoRequestMessage struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *GetInfoRequestMessage) Command() MessageCommand { + return CmdGetInfoRequestMessage +} + +// NewGeInfoRequestMessage returns a instance of the message +func NewGeInfoRequestMessage() *GetInfoRequestMessage { + return &GetInfoRequestMessage{} +} + +// GetInfoResponseMessage is an appmessage corresponding to +// its respective RPC message +type GetInfoResponseMessage struct { + baseMessage + P2PID string + + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *GetInfoResponseMessage) Command() MessageCommand { + return CmdGetInfoResponseMessage +} + +// NewGetInfoResponseMessage returns a instance of the message +func NewGetInfoResponseMessage(p2pID string) *GetInfoResponseMessage { + return &GetInfoResponseMessage{ + P2PID: p2pID, + } +} diff --git a/app/rpc/rpc.go b/app/rpc/rpc.go index b978ec943..57e6a4f0c 100644 --- a/app/rpc/rpc.go +++ b/app/rpc/rpc.go @@ -40,6 +40,7 @@ var handlers = map[appmessage.MessageCommand]handler{ appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualSelectedParentBlueScoreChanged, appmessage.CmdBanRequestMessage: rpchandlers.HandleBan, appmessage.CmdUnbanRequestMessage: rpchandlers.HandleUnban, + appmessage.CmdGetInfoRequestMessage: rpchandlers.HandleGetInfo, } func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) { diff --git a/app/rpc/rpchandlers/get_info.go b/app/rpc/rpchandlers/get_info.go new file mode 100644 index 000000000..3cdc43e0b --- /dev/null +++ b/app/rpc/rpchandlers/get_info.go @@ -0,0 +1,13 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleGetInfo handles the respectively named RPC command +func HandleGetInfo(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) { + response := appmessage.NewGetInfoResponseMessage(context.NetAdapter.ID().String()) + return response, nil +} diff --git a/cmd/kaspactl/commands.go b/cmd/kaspactl/commands.go index 24c54ed23..51d4cefb5 100644 --- a/cmd/kaspactl/commands.go +++ b/cmd/kaspactl/commands.go @@ -13,6 +13,7 @@ var commandTypes = []reflect.Type{ reflect.TypeOf(protowire.KaspadMessage_GetConnectedPeerInfoRequest{}), reflect.TypeOf(protowire.KaspadMessage_GetPeerAddressesRequest{}), reflect.TypeOf(protowire.KaspadMessage_GetCurrentNetworkRequest{}), + reflect.TypeOf(protowire.KaspadMessage_GetInfoRequest{}), reflect.TypeOf(protowire.KaspadMessage_GetBlockRequest{}), reflect.TypeOf(protowire.KaspadMessage_GetBlocksRequest{}), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 1437fdadc..53b229181 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -124,6 +124,8 @@ type KaspadMessage struct { // *KaspadMessage_BanResponse // *KaspadMessage_UnbanRequest // *KaspadMessage_UnbanResponse + // *KaspadMessage_GetInfoRequest + // *KaspadMessage_GetInfoResponse Payload isKaspadMessage_Payload `protobuf_oneof:"payload"` } @@ -817,6 +819,20 @@ func (x *KaspadMessage) GetUnbanResponse() *UnbanResponseMessage { return nil } +func (x *KaspadMessage) GetGetInfoRequest() *GetInfoRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetInfoRequest); ok { + return x.GetInfoRequest + } + return nil +} + +func (x *KaspadMessage) GetGetInfoResponse() *GetInfoResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_GetInfoResponse); ok { + return x.GetInfoResponse + } + return nil +} + type isKaspadMessage_Payload interface { isKaspadMessage_Payload() } @@ -1193,6 +1209,14 @@ type KaspadMessage_UnbanResponse struct { UnbanResponse *UnbanResponseMessage `protobuf:"bytes,1062,opt,name=unbanResponse,proto3,oneof"` } +type KaspadMessage_GetInfoRequest struct { + GetInfoRequest *GetInfoRequestMessage `protobuf:"bytes,1063,opt,name=getInfoRequest,proto3,oneof"` +} + +type KaspadMessage_GetInfoResponse struct { + GetInfoResponse *GetInfoResponseMessage `protobuf:"bytes,1064,opt,name=getInfoResponse,proto3,oneof"` +} + func (*KaspadMessage_Addresses) isKaspadMessage_Payload() {} func (*KaspadMessage_Block) isKaspadMessage_Payload() {} @@ -1379,13 +1403,17 @@ func (*KaspadMessage_UnbanRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_UnbanResponse) isKaspadMessage_Payload() {} +func (*KaspadMessage_GetInfoRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_GetInfoResponse) isKaspadMessage_Payload() {} + var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xba, 0x4a, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x6f, 0x22, 0xd7, 0x4b, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, @@ -1980,21 +2008,30 @@ var file_messages_proto_rawDesc = []byte{ 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa7, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x0e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xa8, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x0f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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 ( @@ -2104,6 +2141,8 @@ var file_messages_proto_goTypes = []interface{}{ (*BanResponseMessage)(nil), // 90: protowire.BanResponseMessage (*UnbanRequestMessage)(nil), // 91: protowire.UnbanRequestMessage (*UnbanResponseMessage)(nil), // 92: protowire.UnbanResponseMessage + (*GetInfoRequestMessage)(nil), // 93: protowire.GetInfoRequestMessage + (*GetInfoResponseMessage)(nil), // 94: protowire.GetInfoResponseMessage } var file_messages_proto_depIdxs = []int32{ 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -2199,15 +2238,17 @@ var file_messages_proto_depIdxs = []int32{ 90, // 90: protowire.KaspadMessage.banResponse:type_name -> protowire.BanResponseMessage 91, // 91: protowire.KaspadMessage.unbanRequest:type_name -> protowire.UnbanRequestMessage 92, // 92: protowire.KaspadMessage.unbanResponse:type_name -> protowire.UnbanResponseMessage - 0, // 93: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 94: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 95: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 96: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 95, // [95:97] is the sub-list for method output_type - 93, // [93:95] is the sub-list for method input_type - 93, // [93:93] is the sub-list for extension type_name - 93, // [93:93] is the sub-list for extension extendee - 0, // [0:93] is the sub-list for field type_name + 93, // 93: protowire.KaspadMessage.getInfoRequest:type_name -> protowire.GetInfoRequestMessage + 94, // 94: protowire.KaspadMessage.getInfoResponse:type_name -> protowire.GetInfoResponseMessage + 0, // 95: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 96: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 97: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 98: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 97, // [97:99] is the sub-list for method output_type + 95, // [95:97] is the sub-list for method input_type + 95, // [95:95] is the sub-list for extension type_name + 95, // [95:95] is the sub-list for extension extendee + 0, // [0:95] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2325,6 +2366,8 @@ func file_messages_proto_init() { (*KaspadMessage_BanResponse)(nil), (*KaspadMessage_UnbanRequest)(nil), (*KaspadMessage_UnbanResponse)(nil), + (*KaspadMessage_GetInfoRequest)(nil), + (*KaspadMessage_GetInfoResponse)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 349e55b7f..903dfa7cc 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -102,6 +102,8 @@ message KaspadMessage { BanResponseMessage banResponse = 1060; UnbanRequestMessage unbanRequest = 1061; UnbanResponseMessage unbanResponse = 1062; + GetInfoRequestMessage getInfoRequest = 1063; + GetInfoResponseMessage getInfoResponse = 1064; } } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md index 0aafcb3d7..485876f9a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -85,6 +85,8 @@ - [BanResponseMessage](#protowire.BanResponseMessage) - [UnbanRequestMessage](#protowire.UnbanRequestMessage) - [UnbanResponseMessage](#protowire.UnbanResponseMessage) + - [GetInfoRequestMessage](#protowire.GetInfoRequestMessage) + - [GetInfoResponseMessage](#protowire.GetInfoResponseMessage) - [SubmitBlockResponseMessage.RejectReason](#protowire.SubmitBlockResponseMessage.RejectReason) @@ -1409,6 +1411,32 @@ UnbanRequestMessage unbans the given ip. + + + +### GetInfoRequestMessage +GetInfoRequestMessage returns info about the node. + + + + + + + + +### GetInfoResponseMessage + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| p2pId | [string](#string) | | | +| error | [RPCError](#protowire.RPCError) | | | + + + + + diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 2f43dbc0d..a6b983d14 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -4713,6 +4713,100 @@ func (x *UnbanResponseMessage) GetError() *RPCError { return nil } +// GetInfoRequestMessage returns info about the node. +type GetInfoRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetInfoRequestMessage) Reset() { + *x = GetInfoRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[81] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetInfoRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInfoRequestMessage) ProtoMessage() {} + +func (x *GetInfoRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[81] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInfoRequestMessage.ProtoReflect.Descriptor instead. +func (*GetInfoRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{81} +} + +type GetInfoResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + P2PId string `protobuf:"bytes,1,opt,name=p2pId,proto3" json:"p2pId,omitempty"` + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *GetInfoResponseMessage) Reset() { + *x = GetInfoResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[82] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetInfoResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetInfoResponseMessage) ProtoMessage() {} + +func (x *GetInfoResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[82] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetInfoResponseMessage.ProtoReflect.Descriptor instead. +func (*GetInfoResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{82} +} + +func (x *GetInfoResponseMessage) GetP2PId() string { + if x != nil { + return x.P2PId + } + return "" +} + +func (x *GetInfoResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + var File_rpc_proto protoreflect.FileDescriptor var file_rpc_proto_rawDesc = []byte{ @@ -5327,10 +5421,18 @@ var file_rpc_proto_rawDesc = []byte{ 0x61, 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, 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, + 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x17, 0x0a, + 0x15, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, 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, 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 ( @@ -5346,7 +5448,7 @@ func file_rpc_proto_rawDescGZIP() []byte { } var file_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 81) +var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 83) var file_rpc_proto_goTypes = []interface{}{ (SubmitBlockResponseMessage_RejectReason)(0), // 0: protowire.SubmitBlockResponseMessage.RejectReason (*RPCError)(nil), // 1: protowire.RPCError @@ -5430,17 +5532,19 @@ var file_rpc_proto_goTypes = []interface{}{ (*BanResponseMessage)(nil), // 79: protowire.BanResponseMessage (*UnbanRequestMessage)(nil), // 80: protowire.UnbanRequestMessage (*UnbanResponseMessage)(nil), // 81: protowire.UnbanResponseMessage - (*BlockMessage)(nil), // 82: protowire.BlockMessage + (*GetInfoRequestMessage)(nil), // 82: protowire.GetInfoRequestMessage + (*GetInfoResponseMessage)(nil), // 83: protowire.GetInfoResponseMessage + (*BlockMessage)(nil), // 84: protowire.BlockMessage } var file_rpc_proto_depIdxs = []int32{ 1, // 0: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 82, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 84, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage 0, // 2: protowire.SubmitBlockResponseMessage.rejectReason:type_name -> protowire.SubmitBlockResponseMessage.RejectReason 1, // 3: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 82, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 84, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage 1, // 5: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError 1, // 6: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 82, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 84, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage 13, // 8: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage 13, // 9: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage 1, // 10: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError @@ -5492,11 +5596,12 @@ var file_rpc_proto_depIdxs = []int32{ 1, // 56: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError 1, // 57: protowire.BanResponseMessage.error:type_name -> protowire.RPCError 1, // 58: protowire.UnbanResponseMessage.error:type_name -> protowire.RPCError - 59, // [59:59] is the sub-list for method output_type - 59, // [59:59] is the sub-list for method input_type - 59, // [59:59] is the sub-list for extension type_name - 59, // [59:59] is the sub-list for extension extendee - 0, // [0:59] is the sub-list for field type_name + 1, // 59: protowire.GetInfoResponseMessage.error:type_name -> protowire.RPCError + 60, // [60:60] is the sub-list for method output_type + 60, // [60:60] is the sub-list for method input_type + 60, // [60:60] is the sub-list for extension type_name + 60, // [60:60] is the sub-list for extension extendee + 0, // [0:60] is the sub-list for field type_name } func init() { file_rpc_proto_init() } @@ -6478,6 +6583,30 @@ func file_rpc_proto_init() { return nil } } + file_rpc_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetInfoRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetInfoResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -6485,7 +6614,7 @@ func file_rpc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_proto_rawDesc, NumEnums: 1, - NumMessages: 81, + NumMessages: 83, NumExtensions: 0, NumServices: 0, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index e504eb97a..f1504ce2d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -550,3 +550,12 @@ message UnbanRequestMessage{ message UnbanResponseMessage{ RPCError error = 1000; } + +// GetInfoRequestMessage returns info about the node. +message GetInfoRequestMessage{ +} + +message GetInfoResponseMessage{ + string p2pId = 1; + RPCError error = 1000; +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_info.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_info.go new file mode 100644 index 000000000..cafec09ff --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_info.go @@ -0,0 +1,37 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_GetInfoRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.GetInfoRequestMessage{}, nil +} + +func (x *KaspadMessage_GetInfoRequest) fromAppMessage(_ *appmessage.GetInfoRequestMessage) error { + x.GetInfoRequest = &GetInfoRequestMessage{} + return nil +} + +func (x *KaspadMessage_GetInfoResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.GetInfoResponse.Error != nil { + err = &appmessage.RPCError{Message: x.GetInfoResponse.Error.Message} + } + return &appmessage.GetInfoResponseMessage{ + P2PID: x.GetInfoResponse.P2PId, + Error: err, + }, nil +} + +func (x *KaspadMessage_GetInfoResponse) fromAppMessage(message *appmessage.GetInfoResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.GetInfoResponse = &GetInfoResponseMessage{ + P2PId: message.P2PID, + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index 0b9f4bb21..9d4107379 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -713,6 +713,20 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.GetInfoRequestMessage: + payload := new(KaspadMessage_GetInfoRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.GetInfoResponseMessage: + payload := new(KaspadMessage_GetInfoResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil default: return nil, nil } From 2edf6bfd07bc0c32514415472bfa15195bf9476b Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Mon, 8 Feb 2021 18:37:02 +0200 Subject: [PATCH 321/351] Minimize memory usage in tests (#1495) * Make leveldb cache configurable * Fix leveldb tests * Add a preallocate option to all caches and disable in tests Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/app.go | 4 +- .../acceptancedatastore.go | 4 +- .../blockheaderstore/blockheaderstore.go | 4 +- .../blockrelationstore/blockrelationstore.go | 4 +- .../blockstatusstore/blockstatusstore.go | 4 +- .../datastructures/blockstore/blockstore.go | 4 +- .../consensusstatestore.go | 4 +- .../finalitystore/finality_store.go | 4 +- .../ghostdagdatastore/ghostdagdatastore.go | 4 +- .../headersselectedchainstore.go | 6 +- .../multisetstore/multisetstore.go | 4 +- .../reachabilitydatastore.go | 4 +- .../utxodiffstore/utxodiffstore.go | 6 +- domain/consensus/factory.go | 59 +++++++++++++++---- domain/consensus/factory_test.go | 2 +- domain/consensus/utils/lrucache/lrucache.go | 10 +++- .../lrucacheuint64tohash.go | 10 +++- .../utils/utxolrucache/utxolrucache.go | 10 +++- infrastructure/db/database/common_test.go | 2 +- infrastructure/db/database/ldb/leveldb.go | 8 ++- .../db/database/ldb/leveldb_test.go | 2 +- infrastructure/db/database/ldb/options.go | 17 ++---- testing/integration/setup_test.go | 2 +- 23 files changed, 114 insertions(+), 64 deletions(-) diff --git a/app/app.go b/app/app.go index 624da91ec..1ee77df48 100644 --- a/app/app.go +++ b/app/app.go @@ -22,6 +22,8 @@ import ( "github.com/kaspanet/kaspad/infrastructure/os/winservice" ) +const leveldbCacheSizeMiB = 256 + var desiredLimits = &limits.DesiredLimits{ FileLimitWant: 2048, FileLimitMin: 1024, @@ -181,5 +183,5 @@ func removeDatabase(cfg *config.Config) error { func openDB(cfg *config.Config) (database.Database, error) { dbPath := databasePath(cfg) log.Infof("Loading database from '%s'", dbPath) - return ldb.NewLevelDB(dbPath) + return ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB) } diff --git a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go index 8698904bc..03cd36f45 100644 --- a/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go +++ b/domain/consensus/datastructures/acceptancedatastore/acceptancedatastore.go @@ -19,11 +19,11 @@ type acceptanceDataStore struct { } // New instantiates a new AcceptanceDataStore -func New(cacheSize int) model.AcceptanceDataStore { +func New(cacheSize int, preallocate bool) model.AcceptanceDataStore { return &acceptanceDataStore{ staging: make(map[externalapi.DomainHash]externalapi.AcceptanceData), toDelete: make(map[externalapi.DomainHash]struct{}), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go index 2d5a9d25a..fda8a4fb4 100644 --- a/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go +++ b/domain/consensus/datastructures/blockheaderstore/blockheaderstore.go @@ -21,11 +21,11 @@ type blockHeaderStore struct { } // New instantiates a new BlockHeaderStore -func New(dbContext model.DBReader, cacheSize int) (model.BlockHeaderStore, error) { +func New(dbContext model.DBReader, cacheSize int, preallocate bool) (model.BlockHeaderStore, error) { blockHeaderStore := &blockHeaderStore{ staging: make(map[externalapi.DomainHash]externalapi.BlockHeader), toDelete: make(map[externalapi.DomainHash]struct{}), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } err := blockHeaderStore.initializeCount(dbContext) diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index ec7a2e566..282668fc2 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -18,10 +18,10 @@ type blockRelationStore struct { } // New instantiates a new BlockRelationStore -func New(cacheSize int) model.BlockRelationStore { +func New(cacheSize int, preallocate bool) model.BlockRelationStore { return &blockRelationStore{ staging: make(map[externalapi.DomainHash]*model.BlockRelations), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index e6fc1ed1c..69d1cc9d2 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -18,10 +18,10 @@ type blockStatusStore struct { } // New instantiates a new BlockStatusStore -func New(cacheSize int) model.BlockStatusStore { +func New(cacheSize int, preallocate bool) model.BlockStatusStore { return &blockStatusStore{ staging: make(map[externalapi.DomainHash]externalapi.BlockStatus), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index fd332c4a0..b613b150c 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -21,11 +21,11 @@ type blockStore struct { } // New instantiates a new BlockStore -func New(dbContext model.DBReader, cacheSize int) (model.BlockStore, error) { +func New(dbContext model.DBReader, cacheSize int, preallocate bool) (model.BlockStore, error) { blockStore := &blockStore{ staging: make(map[externalapi.DomainHash]*externalapi.DomainBlock), toDelete: make(map[externalapi.DomainHash]struct{}), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } err := blockStore.initializeCount(dbContext) diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go index 424906873..fcb627e05 100644 --- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go +++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go @@ -19,9 +19,9 @@ type consensusStateStore struct { } // New instantiates a new ConsensusStateStore -func New(utxoSetCacheSize int) model.ConsensusStateStore { +func New(utxoSetCacheSize int, preallocate bool) model.ConsensusStateStore { return &consensusStateStore{ - virtualUTXOSetCache: utxolrucache.New(utxoSetCacheSize), + virtualUTXOSetCache: utxolrucache.New(utxoSetCacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/finalitystore/finality_store.go b/domain/consensus/datastructures/finalitystore/finality_store.go index 3d726adab..67ea3bc8a 100644 --- a/domain/consensus/datastructures/finalitystore/finality_store.go +++ b/domain/consensus/datastructures/finalitystore/finality_store.go @@ -16,11 +16,11 @@ type finalityStore struct { } // New instantiates a new FinalityStore -func New(cacheSize int) model.FinalityStore { +func New(cacheSize int, preallocate bool) model.FinalityStore { return &finalityStore{ staging: make(map[externalapi.DomainHash]*externalapi.DomainHash), toDelete: make(map[externalapi.DomainHash]struct{}), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go index 41f0ba58b..3e03b3d7b 100644 --- a/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go +++ b/domain/consensus/datastructures/ghostdagdatastore/ghostdagdatastore.go @@ -18,10 +18,10 @@ type ghostdagDataStore struct { } // New instantiates a new GHOSTDAGDataStore -func New(cacheSize int) model.GHOSTDAGDataStore { +func New(cacheSize int, preallocate bool) model.GHOSTDAGDataStore { return &ghostdagDataStore{ staging: make(map[externalapi.DomainHash]*model.BlockGHOSTDAGData), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go b/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go index f6b2334a2..ca5f4e3b0 100644 --- a/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go +++ b/domain/consensus/datastructures/headersselectedchainstore/headersselectedchainstore.go @@ -26,14 +26,14 @@ type headersSelectedChainStore struct { } // New instantiates a new HeadersSelectedChainStore -func New(cacheSize int) model.HeadersSelectedChainStore { +func New(cacheSize int, preallocate bool) model.HeadersSelectedChainStore { return &headersSelectedChainStore{ stagingAddedByHash: make(map[externalapi.DomainHash]uint64), stagingRemovedByHash: make(map[externalapi.DomainHash]struct{}), stagingAddedByIndex: make(map[uint64]*externalapi.DomainHash), stagingRemovedByIndex: make(map[uint64]struct{}), - cacheByIndex: lrucacheuint64tohash.New(cacheSize), - cacheByHash: lrucache.New(cacheSize), + cacheByIndex: lrucacheuint64tohash.New(cacheSize, preallocate), + cacheByHash: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/multisetstore/multisetstore.go b/domain/consensus/datastructures/multisetstore/multisetstore.go index b6a565d2d..ff4c98508 100644 --- a/domain/consensus/datastructures/multisetstore/multisetstore.go +++ b/domain/consensus/datastructures/multisetstore/multisetstore.go @@ -19,11 +19,11 @@ type multisetStore struct { } // New instantiates a new MultisetStore -func New(cacheSize int) model.MultisetStore { +func New(cacheSize int, preallocate bool) model.MultisetStore { return &multisetStore{ staging: make(map[externalapi.DomainHash]model.Multiset), toDelete: make(map[externalapi.DomainHash]struct{}), - cache: lrucache.New(cacheSize), + cache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index 7d72e0e96..a36020a11 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -21,10 +21,10 @@ type reachabilityDataStore struct { } // New instantiates a new ReachabilityDataStore -func New(cacheSize int) model.ReachabilityDataStore { +func New(cacheSize int, preallocate bool) model.ReachabilityDataStore { return &reachabilityDataStore{ reachabilityDataStaging: make(map[externalapi.DomainHash]model.ReachabilityData), - reachabilityDataCache: lrucache.New(cacheSize), + reachabilityDataCache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go index caab31e3e..bd156e739 100644 --- a/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go +++ b/domain/consensus/datastructures/utxodiffstore/utxodiffstore.go @@ -23,13 +23,13 @@ type utxoDiffStore struct { } // New instantiates a new UTXODiffStore -func New(cacheSize int) model.UTXODiffStore { +func New(cacheSize int, preallocate bool) model.UTXODiffStore { return &utxoDiffStore{ utxoDiffStaging: make(map[externalapi.DomainHash]model.UTXODiff), utxoDiffChildStaging: make(map[externalapi.DomainHash]*externalapi.DomainHash), toDelete: make(map[externalapi.DomainHash]struct{}), - utxoDiffCache: lrucache.New(cacheSize), - utxoDiffChildCache: lrucache.New(cacheSize), + utxoDiffCache: lrucache.New(cacheSize, preallocate), + utxoDiffChildCache: lrucache.New(cacheSize, preallocate), } } diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 743c08f2f..14688bf13 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -45,6 +45,12 @@ import ( "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" ) +const ( + defaultTestLeveldbCacheSizeMiB = 8 + defaultPreallocateCaches = true + defaultTestPreallocateCaches = false +) + // Factory instantiates new Consensuses type Factory interface { NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) ( @@ -54,11 +60,15 @@ type Factory interface { SetTestDataDir(dataDir string) SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) + SetTestLevelDBCacheSize(cacheSizeMiB int) + SetTestPreAllocateCache(preallocateCaches bool) } type factory struct { dataDir string ghostdagConstructor GHOSTDAGManagerConstructor + cacheSizeMiB *int + preallocateCaches *bool } // NewFactory creates a new Consensus factory @@ -76,32 +86,39 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat pruningWindowSizeForCaches := int(dagParams.PruningDepth()) + var preallocateCaches bool + if f.preallocateCaches != nil { + preallocateCaches = *f.preallocateCaches + } else { + preallocateCaches = defaultPreallocateCaches + } + // This is used for caches that are used as part of deletePastBlocks that need to traverse until // the previous pruning point. pruningWindowSizePlusFinalityDepthForCache := int(dagParams.PruningDepth() + dagParams.FinalityDepth()) // Data Structures - acceptanceDataStore := acceptancedatastore.New(200) - blockStore, err := blockstore.New(dbManager, 200) + acceptanceDataStore := acceptancedatastore.New(200, preallocateCaches) + blockStore, err := blockstore.New(dbManager, 200, preallocateCaches) if err != nil { return nil, err } - blockHeaderStore, err := blockheaderstore.New(dbManager, 10_000) + blockHeaderStore, err := blockheaderstore.New(dbManager, 10_000, preallocateCaches) if err != nil { return nil, err } - blockRelationStore := blockrelationstore.New(pruningWindowSizePlusFinalityDepthForCache) + blockRelationStore := blockrelationstore.New(pruningWindowSizePlusFinalityDepthForCache, preallocateCaches) - blockStatusStore := blockstatusstore.New(pruningWindowSizePlusFinalityDepthForCache) - multisetStore := multisetstore.New(200) + blockStatusStore := blockstatusstore.New(pruningWindowSizePlusFinalityDepthForCache, preallocateCaches) + multisetStore := multisetstore.New(200, preallocateCaches) pruningStore := pruningstore.New() - reachabilityDataStore := reachabilitydatastore.New(pruningWindowSizePlusFinalityDepthForCache) - utxoDiffStore := utxodiffstore.New(200) - consensusStateStore := consensusstatestore.New(10_000) - ghostdagDataStore := ghostdagdatastore.New(pruningWindowSizeForCaches) + reachabilityDataStore := reachabilitydatastore.New(pruningWindowSizePlusFinalityDepthForCache, preallocateCaches) + utxoDiffStore := utxodiffstore.New(200, preallocateCaches) + consensusStateStore := consensusstatestore.New(10_000, preallocateCaches) + ghostdagDataStore := ghostdagdatastore.New(pruningWindowSizeForCaches, preallocateCaches) headersSelectedTipStore := headersselectedtipstore.New() - finalityStore := finalitystore.New(200) - headersSelectedChainStore := headersselectedchainstore.New(pruningWindowSizeForCaches) + finalityStore := finalitystore.New(200, preallocateCaches) + headersSelectedChainStore := headersselectedchainstore.New(pruningWindowSizeForCaches, preallocateCaches) // Processes reachabilityManager := reachabilitymanager.New( @@ -395,7 +412,16 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode b return nil, nil, err } } - db, err := ldb.NewLevelDB(datadir) + var cacheSizeMiB int + if f.cacheSizeMiB != nil { + cacheSizeMiB = *f.cacheSizeMiB + } else { + cacheSizeMiB = defaultTestLeveldbCacheSizeMiB + } + if f.preallocateCaches == nil { + f.SetTestPreAllocateCache(defaultTestPreallocateCaches) + } + db, err := ldb.NewLevelDB(datadir, cacheSizeMiB) if err != nil { return nil, nil, err } @@ -437,3 +463,10 @@ func (f *factory) SetTestDataDir(dataDir string) { func (f *factory) SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) { f.ghostdagConstructor = ghostdagConstructor } + +func (f *factory) SetTestLevelDBCacheSize(cacheSizeMiB int) { + f.cacheSizeMiB = &cacheSizeMiB +} +func (f *factory) SetTestPreAllocateCache(preallocateCaches bool) { + f.preallocateCaches = &preallocateCaches +} diff --git a/domain/consensus/factory_test.go b/domain/consensus/factory_test.go index e352e15ee..1390c85fa 100644 --- a/domain/consensus/factory_test.go +++ b/domain/consensus/factory_test.go @@ -18,7 +18,7 @@ func TestNewConsensus(t *testing.T) { return } - db, err := ldb.NewLevelDB(tmpDir) + db, err := ldb.NewLevelDB(tmpDir, 8) if err != nil { t.Fatalf("error in NewLevelDB: %s", err) } diff --git a/domain/consensus/utils/lrucache/lrucache.go b/domain/consensus/utils/lrucache/lrucache.go index 94b175a0d..bf54abcf0 100644 --- a/domain/consensus/utils/lrucache/lrucache.go +++ b/domain/consensus/utils/lrucache/lrucache.go @@ -12,9 +12,15 @@ type LRUCache struct { } // New creates a new LRUCache -func New(capacity int) *LRUCache { +func New(capacity int, preallocate bool) *LRUCache { + var cache map[externalapi.DomainHash]interface{} + if preallocate { + cache = make(map[externalapi.DomainHash]interface{}, capacity+1) + } else { + cache = make(map[externalapi.DomainHash]interface{}) + } return &LRUCache{ - cache: make(map[externalapi.DomainHash]interface{}, capacity+1), + cache: cache, capacity: capacity, } } diff --git a/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go b/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go index c2317d5f0..7df4b1e0f 100644 --- a/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go +++ b/domain/consensus/utils/lrucacheuint64tohash/lrucacheuint64tohash.go @@ -10,9 +10,15 @@ type LRUCache struct { } // New creates a new LRUCache -func New(capacity int) *LRUCache { +func New(capacity int, preallocate bool) *LRUCache { + var cache map[uint64]*externalapi.DomainHash + if preallocate { + cache = make(map[uint64]*externalapi.DomainHash, capacity+1) + } else { + cache = make(map[uint64]*externalapi.DomainHash) + } return &LRUCache{ - cache: make(map[uint64]*externalapi.DomainHash, capacity+1), + cache: cache, capacity: capacity, } } diff --git a/domain/consensus/utils/utxolrucache/utxolrucache.go b/domain/consensus/utils/utxolrucache/utxolrucache.go index 70a9e879b..8ae041341 100644 --- a/domain/consensus/utils/utxolrucache/utxolrucache.go +++ b/domain/consensus/utils/utxolrucache/utxolrucache.go @@ -12,9 +12,15 @@ type LRUCache struct { } // New creates a new LRUCache -func New(capacity int) *LRUCache { +func New(capacity int, preallocate bool) *LRUCache { + var cache map[externalapi.DomainOutpoint]externalapi.UTXOEntry + if preallocate { + cache = make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, capacity+1) + } else { + cache = make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry) + } return &LRUCache{ - cache: make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, capacity+1), + cache: cache, capacity: capacity, } } diff --git a/infrastructure/db/database/common_test.go b/infrastructure/db/database/common_test.go index 2b16f9b39..82c9e538d 100644 --- a/infrastructure/db/database/common_test.go +++ b/infrastructure/db/database/common_test.go @@ -25,7 +25,7 @@ func prepareLDBForTest(t *testing.T, testName string) (db database.Database, nam t.Fatalf("%s: TempDir unexpectedly "+ "failed: %s", testName, err) } - db, err = ldb.NewLevelDB(path) + db, err = ldb.NewLevelDB(path, 8) if err != nil { t.Fatalf("%s: Open unexpectedly "+ "failed: %s", testName, err) diff --git a/infrastructure/db/database/ldb/leveldb.go b/infrastructure/db/database/ldb/leveldb.go index 109c2511b..7a911391c 100644 --- a/infrastructure/db/database/ldb/leveldb.go +++ b/infrastructure/db/database/ldb/leveldb.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" "github.com/syndtr/goleveldb/leveldb" ldbErrors "github.com/syndtr/goleveldb/leveldb/errors" + "github.com/syndtr/goleveldb/leveldb/opt" ) // LevelDB defines a thin wrapper around leveldb. @@ -13,9 +14,12 @@ type LevelDB struct { } // NewLevelDB opens a leveldb instance defined by the given path. -func NewLevelDB(path string) (*LevelDB, error) { +func NewLevelDB(path string, cacheSizeMiB int) (*LevelDB, error) { // Open leveldb. If it doesn't exist, create it. - ldb, err := leveldb.OpenFile(path, Options()) + options := Options() + options.BlockCacheCapacity = cacheSizeMiB * opt.MiB + options.WriteBuffer = (cacheSizeMiB * opt.MiB) / 2 + ldb, err := leveldb.OpenFile(path, &options) // If the database is corrupted, attempt to recover. if _, corrupted := err.(*ldbErrors.ErrCorrupted); corrupted { diff --git a/infrastructure/db/database/ldb/leveldb_test.go b/infrastructure/db/database/ldb/leveldb_test.go index 51f3aab32..7920e0909 100644 --- a/infrastructure/db/database/ldb/leveldb_test.go +++ b/infrastructure/db/database/ldb/leveldb_test.go @@ -15,7 +15,7 @@ func prepareDatabaseForTest(t *testing.T, testName string) (ldb *LevelDB, teardo t.Fatalf("%s: TempDir unexpectedly "+ "failed: %s", testName, err) } - ldb, err = NewLevelDB(path) + ldb, err = NewLevelDB(path, 8) if err != nil { t.Fatalf("%s: NewLevelDB unexpectedly "+ "failed: %s", testName, err) diff --git a/infrastructure/db/database/ldb/options.go b/infrastructure/db/database/ldb/options.go index 00a9e5e47..d5f830db3 100644 --- a/infrastructure/db/database/ldb/options.go +++ b/infrastructure/db/database/ldb/options.go @@ -2,19 +2,12 @@ package ldb import "github.com/syndtr/goleveldb/leveldb/opt" -var ( - defaultOptions = opt.Options{ +// Options is a function that returns a leveldb +// opt.Options struct for opening a database. +func Options() opt.Options { + return opt.Options{ Compression: opt.NoCompression, - BlockCacheCapacity: 256 * opt.MiB, - WriteBuffer: 128 * opt.MiB, DisableSeeksCompaction: true, NoSync: true, } - - // Options is a function that returns a leveldb - // opt.Options struct for opening a database. - // It's defined as a variable for the sake of testing. - Options = func() *opt.Options { - return &defaultOptions - } -) +} diff --git a/testing/integration/setup_test.go b/testing/integration/setup_test.go index c1bbab12a..0d440f0bc 100644 --- a/testing/integration/setup_test.go +++ b/testing/integration/setup_test.go @@ -134,5 +134,5 @@ func setDatabaseContext(t *testing.T, harness *appHarness) { func openDB(cfg *config.Config) (database.Database, error) { dbPath := filepath.Join(cfg.DataDir, "db") - return ldb.NewLevelDB(dbPath) + return ldb.NewLevelDB(dbPath, 8) } From 3a4fa6e0e135c9c3b2f42bc85d1ba939b748f9dd Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Tue, 9 Feb 2021 10:30:16 +0200 Subject: [PATCH 322/351] Add blockVerboseData to blockAddedNotifications (#1508) * Add blockVerboseData to blockAddedNotifications. * Run the documentation generator. --- app/appmessage/rpc_notify_block_added.go | 8 +- app/rpc/manager.go | 7 +- app/rpc/rpccontext/verbosedata.go | 22 +- app/rpc/rpchandlers/get_block.go | 2 +- .../server/grpcserver/protowire/rpc.md | 1 + .../server/grpcserver/protowire/rpc.pb.go | 1247 +++++++++-------- .../server/grpcserver/protowire/rpc.proto | 1 + .../protowire/rpc_notify_block_added.go | 15 +- 8 files changed, 674 insertions(+), 629 deletions(-) diff --git a/app/appmessage/rpc_notify_block_added.go b/app/appmessage/rpc_notify_block_added.go index 4580a3216..4ff9dbe63 100644 --- a/app/appmessage/rpc_notify_block_added.go +++ b/app/appmessage/rpc_notify_block_added.go @@ -37,7 +37,8 @@ func NewNotifyBlockAddedResponseMessage() *NotifyBlockAddedResponseMessage { // its respective RPC message type BlockAddedNotificationMessage struct { baseMessage - Block *MsgBlock + Block *MsgBlock + BlockVerboseData *BlockVerboseData } // Command returns the protocol command string for the message @@ -46,8 +47,9 @@ func (msg *BlockAddedNotificationMessage) Command() MessageCommand { } // NewBlockAddedNotificationMessage returns a instance of the message -func NewBlockAddedNotificationMessage(block *MsgBlock) *BlockAddedNotificationMessage { +func NewBlockAddedNotificationMessage(block *MsgBlock, blockVerboseData *BlockVerboseData) *BlockAddedNotificationMessage { return &BlockAddedNotificationMessage{ - Block: block, + Block: block, + BlockVerboseData: blockVerboseData, } } diff --git a/app/rpc/manager.go b/app/rpc/manager.go index 1d050ad69..9fed26f87 100644 --- a/app/rpc/manager.go +++ b/app/rpc/manager.go @@ -69,7 +69,12 @@ func (m *Manager) NotifyBlockAddedToDAG(block *externalapi.DomainBlock, blockIns return err } - blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(appmessage.DomainBlockToMsgBlock(block)) + msgBlock := appmessage.DomainBlockToMsgBlock(block) + blockVerboseData, err := m.context.BuildBlockVerboseData(block.Header, block, false) + if err != nil { + return err + } + blockAddedNotification := appmessage.NewBlockAddedNotificationMessage(msgBlock, blockVerboseData) return m.context.NotificationManager.NotifyBlockAdded(blockAddedNotification) } diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 16b8556ce..b6dbd8944 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "fmt" "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/util/difficulty" "math" "math/big" @@ -23,8 +24,14 @@ import ( "github.com/kaspanet/kaspad/util/pointers" ) -// BuildBlockVerboseData builds a BlockVerboseData from the given block. -func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { +// BuildBlockVerboseData builds a BlockVerboseData from the given blockHeader. +// A block may optionally also be given if it's available in the calling context. +func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, block *externalapi.DomainBlock, + includeTransactionVerboseData bool) (*appmessage.BlockVerboseData, error) { + + onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockVerboseData") + defer onEnd() + hash := consensushashing.HeaderHash(blockHeader) blockInfo, err := ctx.Domain.Consensus().GetBlockInfo(hash) @@ -48,9 +55,11 @@ func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, i } if blockInfo.BlockStatus != externalapi.StatusHeaderOnly { - block, err := ctx.Domain.Consensus().GetBlock(hash) - if err != nil { - return nil, err + if block == nil { + block, err = ctx.Domain.Consensus().GetBlock(hash) + if err != nil { + return nil, err + } } txIDs := make([]string, len(block.Transactions)) @@ -100,6 +109,9 @@ func (ctx *Context) BuildTransactionVerboseData(tx *externalapi.DomainTransactio blockHeader externalapi.BlockHeader, blockHash string) ( *appmessage.TransactionVerboseData, error) { + onEnd := logger.LogAndMeasureExecutionTime(log, "BuildTransactionVerboseData") + defer onEnd() + var payloadHash string if tx.SubnetworkID != subnetworks.SubnetworkIDNative { payloadHash = tx.PayloadHash.String() diff --git a/app/rpc/rpchandlers/get_block.go b/app/rpc/rpchandlers/get_block.go index 1d358deea..bb340c91e 100644 --- a/app/rpc/rpchandlers/get_block.go +++ b/app/rpc/rpchandlers/get_block.go @@ -28,7 +28,7 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme response := appmessage.NewGetBlockResponseMessage() - blockVerboseData, err := context.BuildBlockVerboseData(header, getBlockRequest.IncludeTransactionVerboseData) + blockVerboseData, err := context.BuildBlockVerboseData(header, nil, getBlockRequest.IncludeTransactionVerboseData) if err != nil { return nil, err } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md index 485876f9a..e1e0fd91a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -261,6 +261,7 @@ See: NotifyBlockAddedRequestMessage | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | block | [BlockMessage](#protowire.BlockMessage) | | | +| blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | | | diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index a6b983d14..7b37e4056 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -552,7 +552,8 @@ type BlockAddedNotificationMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Block *BlockMessage `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` + Block *BlockMessage `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` + BlockVerboseData *BlockVerboseData `protobuf:"bytes,2,opt,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` } func (x *BlockAddedNotificationMessage) Reset() { @@ -594,6 +595,13 @@ func (x *BlockAddedNotificationMessage) GetBlock() *BlockMessage { return nil } +func (x *BlockAddedNotificationMessage) GetBlockVerboseData() *BlockVerboseData { + if x != nil { + return x.BlockVerboseData + } + return nil +} + // GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the // current network. (mainnet, testnet, etc.) type GetPeerAddressesRequestMessage struct { @@ -4864,575 +4872,579 @@ var file_rpc_proto_rawDesc = []byte{ 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, 0x4e, 0x0a, 0x1d, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, - 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, - 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, - 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, - 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x39, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, - 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, - 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, + 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x97, 0x01, 0x0a, 0x1d, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x22, 0x20, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, + 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4b, 0x6e, 0x6f, + 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 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, 0x33, 0x0a, - 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, - 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, - 0x74, 0x72, 0x79, 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, - 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, - 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x22, 0x24, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 0xd3, 0x02, 0x0a, 0x1b, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, - 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, - 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, - 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, - 0x72, 0x22, 0x53, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, - 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, - 0x72, 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, 0x5e, 0x0a, 0x1f, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, - 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 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, 0x37, 0x0a, 0x35, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xb3, 0x01, 0x0a, 0x34, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, - 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 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, 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, 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, 0x72, 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, 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, 0xdb, 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, 0x0d, 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, + 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x39, 0x0a, + 0x23, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x41, 0x64, 0x64, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x79, 0x0a, 0x21, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, + 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, + 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 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, 0x33, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x65, + 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x1e, + 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, + 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 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, 0x21, 0x0a, 0x1f, 0x47, 0x65, 0x74, + 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x81, 0x01, 0x0a, + 0x20, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x31, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, + 0x72, 0x69, 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, 0x7b, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, + 0x65, 0x65, 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, 0x02, 0x20, 0x01, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, - 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 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, - 0x0d, 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, 0x92, - 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x15, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 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, 0x22, - 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0x24, 0x0a, + 0x22, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x23, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x69, + 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x66, 0x6f, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 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, 0x95, 0x01, - 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, - 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, - 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, - 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, - 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, - 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, - 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, - 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, - 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, - 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, - 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, 0x31, - 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 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, - 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, - 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xd3, 0x02, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x2a, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x50, + 0x69, 0x6e, 0x67, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x69, + 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x69, 0x73, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x74, + 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, + 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x19, 0x61, 0x64, 0x76, + 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x19, 0x61, 0x64, + 0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, + 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x69, 0x73, 0x49, 0x62, 0x64, 0x50, 0x65, 0x65, 0x72, 0x22, 0x53, 0x0a, 0x15, 0x41, + 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65, 0x6e, 0x74, + 0x22, 0x44, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x5e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x20, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 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, 0x37, 0x0a, 0x35, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x64, 0x0a, 0x36, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 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, 0xb3, 0x01, 0x0a, 0x34, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x22, 0x62, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x69, 0x6e, 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, 0x40, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, + 0x6c, 0x6f, 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, 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, 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, 0x72, 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, 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, 0xdb, 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, 0x0d, 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, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x6e, 0x6c, + 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 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, 0x0d, 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, 0x92, 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, 0x4a, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0f, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x69, 0x0a, + 0x15, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 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, 0x54, 0x0a, 0x34, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x22, 0xe0, 0x01, 0x0a, 0x35, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, + 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, + 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, + 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, + 0x07, 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, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, + 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, + 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, + 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, + 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, + 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, + 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, + 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, + 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, + 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, + 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, + 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, - 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, - 0x22, 0x40, 0x0a, 0x12, 0x42, 0x61, 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, 0x25, 0x0a, 0x13, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, - 0x61, 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, 0x17, 0x0a, - 0x15, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, 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, 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, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, 0x12, 0x42, 0x61, + 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, 0x25, 0x0a, 0x13, + 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 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, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x32, + 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, + 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, 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 ( @@ -5545,63 +5557,64 @@ var file_rpc_proto_depIdxs = []int32{ 1, // 5: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError 1, // 6: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError 84, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage - 13, // 8: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 13, // 9: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage - 1, // 10: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError - 1, // 11: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError - 20, // 12: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry - 1, // 13: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError - 20, // 14: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry - 1, // 15: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError - 36, // 16: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 23, // 17: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage - 1, // 18: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError - 1, // 19: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 65, // 20: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction - 1, // 21: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError - 1, // 22: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError - 31, // 23: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 32, // 24: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock - 35, // 25: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 1, // 26: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError - 36, // 27: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData - 37, // 28: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput - 39, // 29: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput - 38, // 30: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig - 40, // 31: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult - 1, // 32: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError - 31, // 33: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock - 1, // 34: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError - 35, // 35: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData - 1, // 36: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError - 1, // 37: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError - 1, // 38: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError - 1, // 39: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError - 1, // 40: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError - 1, // 41: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError - 1, // 42: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError - 1, // 43: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError - 64, // 44: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry - 64, // 45: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 69, // 46: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 70, // 47: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 66, // 48: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 68, // 49: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 69, // 50: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 67, // 51: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 67, // 52: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 64, // 53: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 1, // 54: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 1, // 55: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 1, // 56: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 1, // 57: protowire.BanResponseMessage.error:type_name -> protowire.RPCError - 1, // 58: protowire.UnbanResponseMessage.error:type_name -> protowire.RPCError - 1, // 59: protowire.GetInfoResponseMessage.error:type_name -> protowire.RPCError - 60, // [60:60] is the sub-list for method output_type - 60, // [60:60] is the sub-list for method input_type - 60, // [60:60] is the sub-list for extension type_name - 60, // [60:60] is the sub-list for extension extendee - 0, // [0:60] is the sub-list for field type_name + 35, // 8: protowire.BlockAddedNotificationMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 13, // 9: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 13, // 10: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage + 1, // 11: protowire.GetPeerAddressesResponseMessage.error:type_name -> protowire.RPCError + 1, // 12: protowire.GetSelectedTipHashResponseMessage.error:type_name -> protowire.RPCError + 20, // 13: protowire.GetMempoolEntryResponseMessage.entry:type_name -> protowire.MempoolEntry + 1, // 14: protowire.GetMempoolEntryResponseMessage.error:type_name -> protowire.RPCError + 20, // 15: protowire.GetMempoolEntriesResponseMessage.entries:type_name -> protowire.MempoolEntry + 1, // 16: protowire.GetMempoolEntriesResponseMessage.error:type_name -> protowire.RPCError + 36, // 17: protowire.MempoolEntry.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 23, // 18: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage + 1, // 19: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError + 1, // 20: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError + 65, // 21: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 1, // 22: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError + 1, // 23: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError + 31, // 24: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 32, // 25: protowire.ChainBlock.acceptedBlocks:type_name -> protowire.AcceptedBlock + 35, // 26: protowire.GetBlockResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 1, // 27: protowire.GetBlockResponseMessage.error:type_name -> protowire.RPCError + 36, // 28: protowire.BlockVerboseData.transactionVerboseData:type_name -> protowire.TransactionVerboseData + 37, // 29: protowire.TransactionVerboseData.transactionVerboseInputs:type_name -> protowire.TransactionVerboseInput + 39, // 30: protowire.TransactionVerboseData.transactionVerboseOutputs:type_name -> protowire.TransactionVerboseOutput + 38, // 31: protowire.TransactionVerboseInput.scriptSig:type_name -> protowire.ScriptSig + 40, // 32: protowire.TransactionVerboseOutput.scriptPublicKey:type_name -> protowire.ScriptPublicKeyResult + 1, // 33: protowire.GetSubnetworkResponseMessage.error:type_name -> protowire.RPCError + 31, // 34: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.addedChainBlocks:type_name -> protowire.ChainBlock + 1, // 35: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage.error:type_name -> protowire.RPCError + 35, // 36: protowire.GetBlocksResponseMessage.blockVerboseData:type_name -> protowire.BlockVerboseData + 1, // 37: protowire.GetBlocksResponseMessage.error:type_name -> protowire.RPCError + 1, // 38: protowire.GetBlockCountResponseMessage.error:type_name -> protowire.RPCError + 1, // 39: protowire.GetBlockDagInfoResponseMessage.error:type_name -> protowire.RPCError + 1, // 40: protowire.ResolveFinalityConflictResponseMessage.error:type_name -> protowire.RPCError + 1, // 41: protowire.NotifyFinalityConflictsResponseMessage.error:type_name -> protowire.RPCError + 1, // 42: protowire.ShutDownResponseMessage.error:type_name -> protowire.RPCError + 1, // 43: protowire.GetHeadersResponseMessage.error:type_name -> protowire.RPCError + 1, // 44: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 64, // 45: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry + 64, // 46: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry + 69, // 47: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 70, // 48: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 66, // 49: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 68, // 50: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 69, // 51: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 67, // 52: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 67, // 53: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 64, // 54: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 1, // 55: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 1, // 56: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 1, // 57: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 1, // 58: protowire.BanResponseMessage.error:type_name -> protowire.RPCError + 1, // 59: protowire.UnbanResponseMessage.error:type_name -> protowire.RPCError + 1, // 60: protowire.GetInfoResponseMessage.error:type_name -> protowire.RPCError + 61, // [61:61] is the sub-list for method output_type + 61, // [61:61] is the sub-list for method input_type + 61, // [61:61] is the sub-list for extension type_name + 61, // [61:61] is the sub-list for extension extendee + 0, // [0:61] is the sub-list for field type_name } func init() { file_rpc_proto_init() } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index f1504ce2d..8991b90c4 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -87,6 +87,7 @@ message NotifyBlockAddedResponseMessage{ // See: NotifyBlockAddedRequestMessage message BlockAddedNotificationMessage{ BlockMessage block = 1; + BlockVerboseData blockVerboseData = 2; } // GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go index b4b718dc1..ab3436ee9 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_notify_block_added.go @@ -37,8 +37,13 @@ func (x *KaspadMessage_BlockAddedNotification) toAppMessage() (appmessage.Messag if err != nil { return nil, err } + blockVerboseData, err := x.BlockAddedNotification.BlockVerboseData.toAppMessage() + if err != nil { + return nil, err + } return &appmessage.BlockAddedNotificationMessage{ - Block: block, + Block: block, + BlockVerboseData: blockVerboseData, }, nil } @@ -48,8 +53,14 @@ func (x *KaspadMessage_BlockAddedNotification) fromAppMessage(message *appmessag if err != nil { return err } + blockVerboseData := &BlockVerboseData{} + err = blockVerboseData.fromAppMessage(message.BlockVerboseData) + if err != nil { + return err + } x.BlockAddedNotification = &BlockAddedNotificationMessage{ - Block: blockMessage, + Block: blockMessage, + BlockVerboseData: blockVerboseData, } return nil } From 2d61a67592cb98b5ba5337645fb0b720ffca3d9e Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 9 Feb 2021 14:00:02 +0200 Subject: [PATCH 323/351] Change some logs (#1511) --- .../processes/consensusstatemanager/calculate_past_utxo.go | 2 +- .../processes/consensusstatemanager/resolve_block_status.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go index 376a194f1..c7b4d88e9 100644 --- a/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go +++ b/domain/consensus/processes/consensusstatemanager/calculate_past_utxo.go @@ -119,7 +119,7 @@ func (csm *consensusStateManager) applyMergeSetBlocks(blockHash *externalapi.Dom externalapi.AcceptanceData, model.MutableUTXODiff, error) { log.Debugf("applyMergeSetBlocks start for block %s", blockHash) - defer log.Tracef("applyMergeSetBlocks end for block %s", blockHash) + defer log.Debugf("applyMergeSetBlocks end for block %s", blockHash) mergeSetHashes := ghostdagData.MergeSet() log.Debugf("Merge set for block %s is %v", blockHash, mergeSetHashes) diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index fef69c2af..fe080bf73 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -56,7 +56,7 @@ func (csm *consensusStateManager) resolveBlockStatus(blockHash *externalapi.Doma csm.blockStatusStore.Stage(unverifiedBlockHash, blockStatus) selectedParentStatus = blockStatus - log.Debugf("Block %s status resolved to `%s`", unverifiedBlockHash, blockStatus) + log.Debugf("Block %s status resolved to `%s`, finished %d/%d of unverified blocks", unverifiedBlockHash, blockStatus, len(unverifiedBlocks)-i, len(unverifiedBlocks)) } return blockStatus, nil @@ -122,7 +122,7 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks( func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) { log.Debugf("resolveSingleBlockStatus start for block %s", blockHash) - defer log.Tracef("resolveSingleBlockStatus end for block %s", blockHash) + defer log.Debugf("resolveSingleBlockStatus end for block %s", blockHash) log.Tracef("Calculating pastUTXO and acceptance data and multiset for block %s", blockHash) pastUTXODiff, acceptanceData, multiset, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash) From f13fc35b9e3845046931c1b5126ae0b45865c1ea Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:28:37 +0200 Subject: [PATCH 324/351] Adds new tests for "BlockAtDepth" function and validate the old tests on DAGTraversal. (#1500) * Adds tests for the "blockAtDepth" function and verify old other tests. * Optimization on create the Dag chain. * Changes according to the review - more detailed error messages, added constants, changed to 3 independent graphs (instead of extending), and changes all the abbreviations. * Changes according to the review - divide the test into three separate tests and change names to variables. * Changes according to the review - the order of the function has changed. * delete double lines Co-authored-by: tal Co-authored-by: Svarog --- .../dagtraversalmanager_test.go | 190 +++++++++++++++++- 1 file changed, 189 insertions(+), 1 deletion(-) diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go index cd4c9f2fe..a46c155ce 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager_test.go @@ -3,11 +3,200 @@ package dagtraversalmanager_test import ( "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" "testing" ) +const commonChainSize = 5 +const depth uint64 = 2 + +//TestBlockAtDepthOnChainDag compares the result of BlockAtDepth to the result of looping over the SelectedChain on a single chain DAG. +func TestBlockAtDepthOnChainDag(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestBlockAtDepthOnChainDag") + if err != nil { + t.Fatalf("Failed creating a NewTestConsensus: %s", err) + } + defer tearDown(false) + + highHash, err := createAChainDAG(params.GenesisHash, tc) + if err != nil { + t.Fatalf("Failed creating a Chain DAG In BlockAtDepthTEST: %+v", err) + } + currentBlockHash := highHash + currentBlockData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), currentBlockHash) + if err != nil { + t.Fatalf("Failed getting GHOSTDAGData for block with hash %s: %+v", currentBlockHash.String(), err) + } + + for i := uint64(0); i <= depth; i++ { + if currentBlockData.SelectedParent() == nil { + break + } + currentBlockHash = currentBlockData.SelectedParent() + currentBlockData, err = tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), currentBlockHash) + if err != nil { + t.Fatalf("Failed getting GHOSTDAGData for block with hash %s: %+v", currentBlockHash.String(), err) + } + } + expectedBlockHash := currentBlockHash + actualBlockHash, err := tc.DAGTraversalManager().BlockAtDepth(highHash, depth) + if err != nil { + t.Fatalf("Failed on BlockAtDepth: %+v", err) + } + if !actualBlockHash.Equal(expectedBlockHash) { + t.Fatalf("Expected block %s but got %s", expectedBlockHash, actualBlockHash) + } + }) +} + +func createAChainDAG(genesisHash *externalapi.DomainHash, tc testapi.TestConsensus) (*externalapi.DomainHash, error) { + block := genesisHash + var err error + for i := 0; i < commonChainSize; i++ { + block, _, err = tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, err + } + } + return block, nil +} + +// TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent compares the results of BlockAtDepth +// of 2 children that have the same selectedParent. +func TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent") + if err != nil { + t.Fatalf("Failed creating a NewTestConsensus: %s", err) + } + defer tearDown(false) + + firstChild, secondChild, err := createADAGTwoChildrenWithSameSelectedParent(params.GenesisHash, tc) + if err != nil { + t.Fatalf("Failed creating a DAG where two blocks have same selected parent: %+v", err) + } + actualBlockHash, err := tc.DAGTraversalManager().BlockAtDepth(firstChild, depth) + if err != nil { + t.Fatalf("Failed at BlockAtDepth: %+v", err) + } + expectedSameHash, err := tc.DAGTraversalManager().BlockAtDepth(secondChild, depth) + if err != nil { + t.Fatalf("Failed in BlockAtDepth: %+v", err) + } + if !actualBlockHash.Equal(expectedSameHash) { + t.Fatalf("Expected block %s but got %s", expectedSameHash, actualBlockHash) + } + }) +} + +func createADAGTwoChildrenWithSameSelectedParent(genesisHash *externalapi.DomainHash, + tc testapi.TestConsensus) (*externalapi.DomainHash, *externalapi.DomainHash, error) { + + block := genesisHash + var err error + for i := 0; i < commonChainSize; i++ { + block, _, err = tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, nil, err + } + } + firstChild, _, err := tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, nil, err + } + secondChild, _, err := tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, nil, err + } + return firstChild, secondChild, nil +} + +// TestBlockAtDepthOnDAGWithTwoDifferentChains compares results of BlockAtDepth on two different chains, +// on the same DAG, and validates they merge at the correct point. +func TestBlockAtDepthOnDAGWithTwoDifferentChains(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestBlockAtDepthOnDAGWithTwoDifferentChains") + if err != nil { + t.Fatalf("Failed creating a NewTestConsensus: %s", err) + } + defer tearDown(false) + + const sizeOfTheFirstChildSubChainDAG = 3 + const sizeOfTheSecondChildSubChainDAG = 2 + + firstChild, secondChild, err := createADAGWithTwoDifferentChains(params.GenesisHash, tc, sizeOfTheFirstChildSubChainDAG, + sizeOfTheSecondChildSubChainDAG) + if err != nil { + t.Fatalf("Failed creating a DAG with two different chains in BlockAtDepthTEST: %+v", err) + } + + actualBlockHash, err := tc.DAGTraversalManager().BlockAtDepth(firstChild, sizeOfTheFirstChildSubChainDAG) + if err != nil { + t.Fatalf("Failed in BlockAtDepth: %+v", err) + } + expectedSameHash, err := tc.DAGTraversalManager().BlockAtDepth(secondChild, sizeOfTheSecondChildSubChainDAG) + if err != nil { + t.Fatalf("Failed in BlockAtDepth: %+v", err) + } + + if !actualBlockHash.Equal(expectedSameHash) { + t.Fatalf("Expected block %s but got %s", expectedSameHash, actualBlockHash) + } + expectedDiffHash, err := tc.DAGTraversalManager().BlockAtDepth(secondChild, sizeOfTheSecondChildSubChainDAG-1) + if err != nil { + t.Fatalf("Failed in BlockAtDepth: %+v", err) + } + if actualBlockHash.Equal(expectedDiffHash) { + t.Fatalf("Expected to a differente block") + } + }) +} + +func createADAGWithTwoDifferentChains(genesisHash *externalapi.DomainHash, tc testapi.TestConsensus, + sizeOfTheFirstChildSubChainDAG int, sizeOfTheSecondChildSubChainDAG int) (*externalapi.DomainHash, *externalapi.DomainHash, error) { + + block := genesisHash + var err error + for i := 0; i < commonChainSize; i++ { + block, _, err = tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, nil, err + } + } + firstChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, nil, err + } + secondChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{block}, nil, nil) + if err != nil { + return nil, nil, err + } + + for i := 0; i < sizeOfTheFirstChildSubChainDAG; i++ { + firstChainTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{firstChainTipHash}, nil, nil) + if err != nil { + return nil, nil, err + } + } + + for i := 0; i < sizeOfTheSecondChildSubChainDAG; i++ { + secondChainTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{secondChainTipHash}, nil, nil) + if err != nil { + return nil, nil, err + } + } + return firstChainTipHash, secondChainTipHash, nil +} + func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { params.FinalityDuration = 10 * params.TargetTimePerBlock @@ -18,7 +207,6 @@ func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) { t.Fatalf("NewTestConsensus: %s", err) } defer tearDown(false) - checkExpectedBlock := func(highHash *externalapi.DomainHash, blueScore uint64, expected *externalapi.DomainHash) { blockHash, err := tc.DAGTraversalManager().LowestChainBlockAboveOrEqualToBlueScore(highHash, blueScore) if err != nil { From 1222a555f2f3ccb7bfbfb0bb0c7c77a30cee7d21 Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 10 Feb 2021 16:39:36 +0200 Subject: [PATCH 325/351] Prune blocks below pruning point when moving pruning point during IBD (#1513) * Split deletePastBlocks into sub-routines * Remove SelectedParentIterator, and refactor SelectedChildIterator to support First and Error * Implement PruneAllBlocks * Prune all blocks in the store * Prune only blocks that are below the pruning point * Defer call onEnd of LogAndMeasureExecutionTime * Handle a forgotten error * Minor style fixes --- .../datastructures/blockstore/blockstore.go | 31 ++++ domain/consensus/model/block_heap.go | 1 + domain/consensus/model/blockiterator.go | 3 +- .../interface_datastructures_blockstore.go | 1 + .../interface_processes_dagtopologymanager.go | 1 - ...interface_processes_dagtraversalmanager.go | 3 +- .../interface_processes_pruningmanager.go | 1 + .../validateandinsertimportedpruningpoint.go | 6 + .../import_pruning_utxo_set.go | 2 +- .../dagtopologymanager/dagtopologymanager.go | 5 - .../dagtraversalmanager/block_heap.go | 10 ++ .../dagtraversalmanager.go | 34 ----- .../selected_child_iterator.go | 27 +++- .../ghostdagmanager/ghostdag_test.go | 11 +- .../pruningmanager/pruningmanager.go | 132 +++++++++++++----- .../processes/syncmanager/antipast.go | 14 +- 16 files changed, 186 insertions(+), 96 deletions(-) diff --git a/domain/consensus/datastructures/blockstore/blockstore.go b/domain/consensus/datastructures/blockstore/blockstore.go index b613b150c..eeacf05e7 100644 --- a/domain/consensus/datastructures/blockstore/blockstore.go +++ b/domain/consensus/datastructures/blockstore/blockstore.go @@ -212,3 +212,34 @@ func (bs *blockStore) serializeBlockCount(count uint64) ([]byte, error) { dbBlockCount := &serialization.DbBlockCount{Count: count} return proto.Marshal(dbBlockCount) } + +type allBlockHashesIterator struct { + cursor model.DBCursor +} + +func (a allBlockHashesIterator) First() bool { + return a.cursor.First() +} + +func (a allBlockHashesIterator) Next() bool { + return a.cursor.Next() +} + +func (a allBlockHashesIterator) Get() (*externalapi.DomainHash, error) { + key, err := a.cursor.Key() + if err != nil { + return nil, err + } + + blockHashBytes := key.Suffix() + return externalapi.NewDomainHashFromByteSlice(blockHashBytes) +} + +func (bs *blockStore) AllBlockHashesIterator(dbContext model.DBReader) (model.BlockIterator, error) { + cursor, err := dbContext.Cursor(bucket) + if err != nil { + return nil, err + } + + return &allBlockHashesIterator{cursor: cursor}, nil +} diff --git a/domain/consensus/model/block_heap.go b/domain/consensus/model/block_heap.go index 46643d820..95c51c870 100644 --- a/domain/consensus/model/block_heap.go +++ b/domain/consensus/model/block_heap.go @@ -5,6 +5,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockHeap represents a heap of block hashes, providing a priority-queue functionality type BlockHeap interface { Push(blockHash *externalapi.DomainHash) error + PushSlice(blockHash []*externalapi.DomainHash) error Pop() *externalapi.DomainHash Len() int ToSlice() []*externalapi.DomainHash diff --git a/domain/consensus/model/blockiterator.go b/domain/consensus/model/blockiterator.go index 0b088c997..051103a69 100644 --- a/domain/consensus/model/blockiterator.go +++ b/domain/consensus/model/blockiterator.go @@ -4,6 +4,7 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" // BlockIterator is an iterator over blocks according to some order. type BlockIterator interface { + First() bool Next() bool - Get() *externalapi.DomainHash + Get() (*externalapi.DomainHash, error) } diff --git a/domain/consensus/model/interface_datastructures_blockstore.go b/domain/consensus/model/interface_datastructures_blockstore.go index f2aadb566..d50726a37 100644 --- a/domain/consensus/model/interface_datastructures_blockstore.go +++ b/domain/consensus/model/interface_datastructures_blockstore.go @@ -12,4 +12,5 @@ type BlockStore interface { Blocks(dbContext DBReader, blockHashes []*externalapi.DomainHash) ([]*externalapi.DomainBlock, error) Delete(blockHash *externalapi.DomainHash) Count() uint64 + AllBlockHashesIterator(dbContext DBReader) (BlockIterator, error) } diff --git a/domain/consensus/model/interface_processes_dagtopologymanager.go b/domain/consensus/model/interface_processes_dagtopologymanager.go index bb49f7928..7491cde17 100644 --- a/domain/consensus/model/interface_processes_dagtopologymanager.go +++ b/domain/consensus/model/interface_processes_dagtopologymanager.go @@ -10,7 +10,6 @@ type DAGTopologyManager interface { IsParentOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) IsChildOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) IsAncestorOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) - IsDescendantOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) IsAncestorOfAny(blockHash *externalapi.DomainHash, potentialDescendants []*externalapi.DomainHash) (bool, error) IsInSelectedParentChainOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) ChildInSelectedParentChainOf(context, highHash *externalapi.DomainHash) (*externalapi.DomainHash, error) diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index 9121ba263..1ba115bab 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -7,7 +7,8 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" type DAGTraversalManager interface { BlockAtDepth(highHash *externalapi.DomainHash, depth uint64) (*externalapi.DomainHash, error) LowestChainBlockAboveOrEqualToBlueScore(highHash *externalapi.DomainHash, blueScore uint64) (*externalapi.DomainHash, error) - SelectedParentIterator(highHash *externalapi.DomainHash) BlockIterator + // SelectedChildIterator should return a BlockIterator that iterates + // from lowHash (exclusive) to highHash (inclusive) over highHash's selected parent chain SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error) AnticoneFromContext(context, lowHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) BlueWindow(highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index 75d907f82..41223b010 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -9,4 +9,5 @@ type PruningManager interface { ClearImportedPruningPointData() error AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error UpdatePruningPointUTXOSetIfRequired() error + PruneAllBlocksBelow(pruningPointHash *externalapi.DomainHash) error } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go index 0b5cddf70..f83522db1 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertimportedpruningpoint.go @@ -28,6 +28,12 @@ func (bp *blockProcessor) validateAndInsertImportedPruningPoint(newPruningPoint return err } + log.Info("Deleting block data for all blocks in blockStore") + err = bp.pruningManager.PruneAllBlocksBelow(newPruningPointHash) + if err != nil { + return err + } + log.Infof("Updating consensus state manager according to the new pruning point %s", newPruningPointHash) err = bp.consensusStateManager.ImportPruningPoint(newPruningPoint) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go index 81e9d4a7e..61af1b852 100644 --- a/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/import_pruning_utxo_set.go @@ -61,7 +61,7 @@ func (csm *consensusStateManager) importPruningPoint(newPruningPoint *externalap } log.Debugf("The new pruning point UTXO commitment validation passed") - log.Debugf("Staging the the pruning point as the only DAG tip") + log.Debugf("Staging the pruning point as the only DAG tip") newTips := []*externalapi.DomainHash{newPruningPointHash} csm.consensusStateStore.StageTips(newTips) diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index 73d45ff59..38677bc28 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -71,11 +71,6 @@ func (dtm *dagTopologyManager) IsAncestorOf(blockHashA *externalapi.DomainHash, return dtm.reachabilityManager.IsDAGAncestorOf(blockHashA, blockHashB) } -// IsDescendantOf returns true if blockHashA is a DAG descendant of blockHashB -func (dtm *dagTopologyManager) IsDescendantOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { - return dtm.reachabilityManager.IsDAGAncestorOf(blockHashB, blockHashA) -} - // IsAncestorOfAny returns true if `blockHash` is an ancestor of at least one of `potentialDescendants` func (dtm *dagTopologyManager) IsAncestorOfAny(blockHash *externalapi.DomainHash, potentialDescendants []*externalapi.DomainHash) (bool, error) { for _, potentialDescendant := range potentialDescendants { diff --git a/domain/consensus/processes/dagtraversalmanager/block_heap.go b/domain/consensus/processes/dagtraversalmanager/block_heap.go index 46b099c3b..c5f235f7c 100644 --- a/domain/consensus/processes/dagtraversalmanager/block_heap.go +++ b/domain/consensus/processes/dagtraversalmanager/block_heap.go @@ -109,6 +109,16 @@ func (bh *blockHeap) Push(blockHash *externalapi.DomainHash) error { return nil } +func (bh *blockHeap) PushSlice(blockHashes []*externalapi.DomainHash) error { + for _, blockHash := range blockHashes { + err := bh.Push(blockHash) + if err != nil { + return err + } + } + return nil +} + // Len returns the length of this heap func (bh *blockHeap) Len() int { return bh.impl.Len() diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 316a01ccb..8402e4b27 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -1,7 +1,6 @@ package dagtraversalmanager import ( - "fmt" "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/pkg/errors" @@ -18,29 +17,6 @@ type dagTraversalManager struct { reachabilityDataStore model.ReachabilityDataStore } -// selectedParentIterator implements the `model.BlockIterator` API -type selectedParentIterator struct { - databaseContext model.DBReader - ghostdagDataStore model.GHOSTDAGDataStore - current *externalapi.DomainHash -} - -func (spi *selectedParentIterator) Next() bool { - if spi.current == nil { - return false - } - ghostdagData, err := spi.ghostdagDataStore.Get(spi.databaseContext, spi.current) - if err != nil { - panic(fmt.Sprintf("ghostdagDataStore is missing ghostdagData for: %v. '%s' ", spi.current, err)) - } - spi.current = ghostdagData.SelectedParent() - return spi.current != nil -} - -func (spi *selectedParentIterator) Get() *externalapi.DomainHash { - return spi.current -} - // New instantiates a new DAGTraversalManager func New( databaseContext model.DBReader, @@ -57,16 +33,6 @@ func New( } } -// SelectedParentIterator creates an iterator over the selected -// parent chain of the given highHash -func (dtm *dagTraversalManager) SelectedParentIterator(highHash *externalapi.DomainHash) model.BlockIterator { - return &selectedParentIterator{ - databaseContext: dtm.databaseContext, - ghostdagDataStore: dtm.ghostdagDataStore, - current: highHash, - } -} - // BlockAtDepth returns the hash of the highest block with a blue score // lower than (highHash.blueSore - depth) in the selected-parent-chain // of the block with the given highHash's selected parent chain. diff --git a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go index c5e22bb76..511576a4c 100644 --- a/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go +++ b/domain/consensus/processes/dagtraversalmanager/selected_child_iterator.go @@ -11,20 +11,34 @@ type selectedChildIterator struct { dagTopologyManager model.DAGTopologyManager reachabilityDataStore model.ReachabilityDataStore - highHash *externalapi.DomainHash + highHash, lowHash *externalapi.DomainHash current *externalapi.DomainHash + err error +} + +func (s *selectedChildIterator) First() bool { + s.current = s.lowHash + return s.Next() } func (s *selectedChildIterator) Next() bool { + if s.err != nil { + return true + } + data, err := s.reachabilityDataStore.ReachabilityData(s.databaseContext, s.current) if err != nil { - panic(err) + s.current = nil + s.err = err + return true } for _, child := range data.Children() { isChildInSelectedParentChainOfHighHash, err := s.dagTopologyManager.IsInSelectedParentChainOf(child, s.highHash) if err != nil { - panic(err) + s.current = nil + s.err = err + return true } if isChildInSelectedParentChainOfHighHash { @@ -35,10 +49,12 @@ func (s *selectedChildIterator) Next() bool { return false } -func (s *selectedChildIterator) Get() *externalapi.DomainHash { - return s.current +func (s *selectedChildIterator) Get() (*externalapi.DomainHash, error) { + return s.current, s.err } +// SelectedChildIterator returns a BlockIterator that iterates from lowHash (exclusive) to highHash (inclusive) over +// highHash's selected parent chain func (dtm *dagTraversalManager) SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (model.BlockIterator, error) { isLowHashInSelectedParentChainOfHighHash, err := dtm.dagTopologyManager.IsInSelectedParentChainOf(lowHash, highHash) if err != nil { @@ -53,6 +69,7 @@ func (dtm *dagTraversalManager) SelectedChildIterator(highHash, lowHash *externa dagTopologyManager: dtm.dagTopologyManager, reachabilityDataStore: dtm.reachabilityDataStore, highHash: highHash, + lowHash: lowHash, current: lowHash, }, nil } diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go index ee557cebc..aca8ece08 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag_test.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag_test.go @@ -2,9 +2,6 @@ package ghostdagmanager_test import ( "encoding/json" - "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" - "github.com/kaspanet/kaspad/domain/consensus/utils/constants" - "github.com/kaspanet/kaspad/util/difficulty" "math" "math/big" "os" @@ -12,6 +9,10 @@ import ( "reflect" "testing" + "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/util/difficulty" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2" @@ -386,10 +387,6 @@ func (dt *DAGTopologyManagerImpl) IsAncestorOf(hashBlockA *externalapi.DomainHas } -func (dt *DAGTopologyManagerImpl) IsDescendantOf(blockHashA *externalapi.DomainHash, blockHashB *externalapi.DomainHash) (bool, error) { - panic("unimplemented") -} - func (dt *DAGTopologyManagerImpl) IsAncestorOfAny(blockHash *externalapi.DomainHash, potentialDescendants []*externalapi.DomainHash) (bool, error) { panic("unimplemented") } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 8c231027d..18eb8aa59 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -151,8 +151,11 @@ func (pm *pruningManager) UpdatePruningPointByVirtual() error { newPruningPoint := currentPruningPoint newPruningPointGHOSTDAGData := currentPruningPointGHOSTDAGData - for iterator.Next() { - selectedChild := iterator.Get() + for ok := iterator.First(); ok; ok = iterator.Next() { + selectedChild, err := iterator.Get() + if err != nil { + return err + } selectedChildGHOSTDAGData, err := pm.ghostdagDataStore.Get(pm.databaseContext, selectedChild) if err != nil { return err @@ -221,47 +224,47 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.deletePastBlocks") defer onEnd() - // Go over all P.Past and P.AC that's not in V.Past + // Go over all pruningPoint.Past and pruningPoint.Anticone that's not in virtual.Past queue := pm.dagTraversalManager.NewDownHeap() - - // Find P.AC that's not in V.Past - dagTips, err := pm.consensusStateStore.Tips(pm.databaseContext) - if err != nil { - return err - } - newTips := make([]*externalapi.DomainHash, 0, len(dagTips)) virtualParents, err := pm.dagTopologyManager.Parents(model.VirtualBlockHash) if err != nil { return err } - for _, tip := range dagTips { - isInPruningFutureOrInVirtualPast, err := pm.isInPruningFutureOrInVirtualPast(tip, pruningPoint, virtualParents) - if err != nil { - return err - } - if !isInPruningFutureOrInVirtualPast { - // Add them to the queue so they and their past will be pruned - err := queue.Push(tip) - if err != nil { - return err - } - } else { - newTips = append(newTips, tip) - } + + // Start queue with all tips that are below the pruning point (and on the way remove them from list of tips) + prunedTips, err := pm.pruneTips(pruningPoint, virtualParents) + if err != nil { + return err } - pm.consensusStateStore.StageTips(newTips) - // Add P.Parents + err = queue.PushSlice(prunedTips) + if err != nil { + return err + } + + // Add pruningPoint.Parents to queue parents, err := pm.dagTopologyManager.Parents(pruningPoint) if err != nil { return err } - for _, parent := range parents { - err = queue.Push(parent) - if err != nil { - return err - } + err = queue.PushSlice(parents) + if err != nil { + return err } + err = pm.deleteBlocksDownward(queue) + if err != nil { + return err + } + + err = pm.pruneVirtualDiffParents(pruningPoint, virtualParents) + if err != nil { + return err + } + + return nil +} + +func (pm *pruningManager) deleteBlocksDownward(queue model.BlockHeap) error { visited := map[externalapi.DomainHash]struct{}{} // Prune everything in the queue including its past for queue.Len() > 0 { @@ -280,16 +283,16 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) if err != nil { return err } - for _, parent := range parents { - err = queue.Push(parent) - if err != nil { - return err - } + err = queue.PushSlice(parents) + if err != nil { + return err } } } + return nil +} - // Delete virtual diff parents that are in PruningPoint's Anticone and not in Virtual's Past +func (pm *pruningManager) pruneVirtualDiffParents(pruningPoint *externalapi.DomainHash, virtualParents []*externalapi.DomainHash) error { virtualDiffParents, err := pm.consensusStateStore.VirtualDiffParents(pm.databaseContext) if err != nil { return err @@ -309,6 +312,31 @@ func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) return nil } +func (pm *pruningManager) pruneTips(pruningPoint *externalapi.DomainHash, virtualParents []*externalapi.DomainHash) ( + prunedTips []*externalapi.DomainHash, err error) { + + // Find P.AC that's not in V.Past + dagTips, err := pm.consensusStateStore.Tips(pm.databaseContext) + if err != nil { + return nil, err + } + newTips := make([]*externalapi.DomainHash, 0, len(dagTips)) + for _, tip := range dagTips { + isInPruningFutureOrInVirtualPast, err := pm.isInPruningFutureOrInVirtualPast(tip, pruningPoint, virtualParents) + if err != nil { + return nil, err + } + if !isInPruningFutureOrInVirtualPast { + prunedTips = append(prunedTips, tip) + } else { + newTips = append(newTips, tip) + } + } + pm.consensusStateStore.StageTips(newTips) + + return prunedTips, nil +} + func (pm *pruningManager) savePruningPoint(pruningPointHash *externalapi.DomainHash) error { onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.savePruningPoint") defer onEnd() @@ -551,3 +579,33 @@ func (pm *pruningManager) updatePruningPointUTXOSet() error { log.Debugf("Finishing updating the pruning point UTXO set") return pm.pruningStore.FinishUpdatingPruningPointUTXOSet(pm.databaseContext) } + +func (pm *pruningManager) PruneAllBlocksBelow(pruningPointHash *externalapi.DomainHash) error { + onEnd := logger.LogAndMeasureExecutionTime(log, "PruneAllBlocksBelow") + defer onEnd() + + iterator, err := pm.blocksStore.AllBlockHashesIterator(pm.databaseContext) + if err != nil { + return err + } + + for ok := iterator.First(); ok; ok = iterator.Next() { + blockHash, err := iterator.Get() + if err != nil { + return err + } + isInPastOfPruningPoint, err := pm.dagTopologyManager.IsAncestorOf(pruningPointHash, blockHash) + if err != nil { + return err + } + if !isInPastOfPruningPoint { + continue + } + _, err = pm.deleteBlock(blockHash) + if err != nil { + return err + } + } + + return nil +} diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 82c9b1744..5e433058d 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -39,8 +39,11 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma if err != nil { return nil, err } - for iterator.Next() { - highHash = iterator.Get() + for ok := iterator.First(); ok; ok = iterator.Next() { + highHash, err = iterator.Get() + if err != nil { + return nil, err + } highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHash) if err != nil { return nil, err @@ -112,8 +115,11 @@ func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) lowHash := pruningPoint foundHeaderOnlyBlock := false - for selectedChildIterator.Next() { - selectedChild := selectedChildIterator.Get() + for ok := selectedChildIterator.First(); ok; ok = selectedChildIterator.Next() { + selectedChild, err := selectedChildIterator.Get() + if err != nil { + return nil, err + } hasBlock, err := sm.blockStore.HasBlock(sm.databaseContext, selectedChild) if err != nil { return nil, err From 94cdc7748176eebffabe565e5c8bfc23adb105d1 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Wed, 10 Feb 2021 18:09:25 +0200 Subject: [PATCH 326/351] Send peers the hash of the virtual selected parent once connection is established (#1519) * Send peers the hash of the virtual selected parent once connection is established. * Add a log to SendVirtualSelectedParentInv. * Fix TestIBDWithPruning. * Fix TestIBDWithPruning better and signal from the IBD syncer to the IBD syncee that the DAG is split amongst them. * Fix TestVirtualSelectedParentChain. * Add comments. --- app/appmessage/message.go | 2 + ...p_msgibdblocklocatorhighesthashnotfound.go | 16 + .../blockrelay/handle_ibd_block_locator.go | 8 +- app/protocol/flows/blockrelay/ibd.go | 76 +- .../send_virtual_selected_parent_inv.go | 28 + app/protocol/protocol.go | 7 +- .../grpcserver/protowire/messages.pb.go | 1160 +++++++++-------- .../grpcserver/protowire/messages.proto | 1 + .../server/grpcserver/protowire/p2p.pb.go | 84 +- .../server/grpcserver/protowire/p2p.proto | 3 + ...bd_block_locator_highest_hash_not_found.go | 12 + .../server/grpcserver/protowire/wire.go | 7 + testing/integration/ibd_test.go | 10 +- .../integration/selected_parent_chain_test.go | 14 +- 14 files changed, 805 insertions(+), 623 deletions(-) create mode 100644 app/appmessage/p2p_msgibdblocklocatorhighesthashnotfound.go create mode 100644 app/protocol/flows/blockrelay/send_virtual_selected_parent_inv.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash_not_found.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index 462617757..bf8bd9e03 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -59,6 +59,7 @@ const ( CmdPruningPointHash CmdIBDBlockLocator CmdIBDBlockLocatorHighestHash + CmdIBDBlockLocatorHighestHashNotFound CmdBlockHeaders CmdRequestNextPruningPointUTXOSetChunk CmdDonePruningPointUTXOSetChunks @@ -162,6 +163,7 @@ var ProtocolMessageCommandToString = map[MessageCommand]string{ CmdPruningPointHash: "PruningPointHash", CmdIBDBlockLocator: "IBDBlockLocator", CmdIBDBlockLocatorHighestHash: "IBDBlockLocatorHighestHash", + CmdIBDBlockLocatorHighestHashNotFound: "IBDBlockLocatorHighestHashNotFound", CmdBlockHeaders: "BlockHeaders", CmdRequestNextPruningPointUTXOSetChunk: "RequestNextPruningPointUTXOSetChunk", CmdDonePruningPointUTXOSetChunks: "DonePruningPointUTXOSetChunks", diff --git a/app/appmessage/p2p_msgibdblocklocatorhighesthashnotfound.go b/app/appmessage/p2p_msgibdblocklocatorhighesthashnotfound.go new file mode 100644 index 000000000..dfc2c02e9 --- /dev/null +++ b/app/appmessage/p2p_msgibdblocklocatorhighesthashnotfound.go @@ -0,0 +1,16 @@ +package appmessage + +// MsgIBDBlockLocatorHighestHashNotFound represents a kaspa BlockLocatorHighestHashNotFound message +type MsgIBDBlockLocatorHighestHashNotFound struct { + baseMessage +} + +// Command returns the protocol command string for the message +func (msg *MsgIBDBlockLocatorHighestHashNotFound) Command() MessageCommand { + return CmdIBDBlockLocatorHighestHashNotFound +} + +// NewMsgIBDBlockLocatorHighestHashNotFound returns a new IBDBlockLocatorHighestHashNotFound message +func NewMsgIBDBlockLocatorHighestHashNotFound() *MsgIBDBlockLocatorHighestHashNotFound { + return &MsgIBDBlockLocatorHighestHashNotFound{} +} diff --git a/app/protocol/flows/blockrelay/handle_ibd_block_locator.go b/app/protocol/flows/blockrelay/handle_ibd_block_locator.go index a04d0699e..a1ccc0979 100644 --- a/app/protocol/flows/blockrelay/handle_ibd_block_locator.go +++ b/app/protocol/flows/blockrelay/handle_ibd_block_locator.go @@ -70,8 +70,14 @@ func HandleIBDBlockLocator(context HandleIBDBlockLocatorContext, incomingRoute * } if !foundHighestHashInTheSelectedParentChainOfTargetHash { - return protocolerrors.Errorf(true, "no hash was found in the blockLocator "+ + log.Warnf("no hash was found in the blockLocator "+ "that was in the selected parent chain of targetHash %s", targetHash) + + ibdBlockLocatorHighestHashNotFoundMessage := appmessage.NewMsgIBDBlockLocatorHighestHashNotFound() + err = outgoingRoute.Enqueue(ibdBlockLocatorHighestHashNotFoundMessage) + if err != nil { + return err + } } } } diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index 54e65ed46..f8a4fda65 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -28,10 +28,14 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain log.Debugf("IBD started with peer %s and highHash %s", flow.peer, highHash) log.Debugf("Syncing headers up to %s", highHash) - err := flow.syncHeaders(highHash) + headersSynced, err := flow.syncHeaders(highHash) if err != nil { return err } + if !headersSynced { + log.Debugf("Aborting IBD because the headers failed to sync") + return nil + } log.Debugf("Finished syncing headers up to %s", highHash) log.Debugf("Syncing the current pruning point UTXO set") @@ -55,47 +59,61 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain return nil } -func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) error { +// syncHeaders attempts to sync headers from the peer. This method may fail +// because the peer and us have conflicting pruning points. In that case we +// return (false, nil) so that we may stop IBD gracefully. +func (flow *handleRelayInvsFlow) syncHeaders(highHash *externalapi.DomainHash) (bool, error) { log.Debugf("Trying to find highest shared chain block with peer %s with high hash %s", flow.peer, highHash) - highestSharedBlockHash, err := flow.findHighestSharedBlockHash(highHash) + highestSharedBlockHash, highestSharedBlockFound, err := flow.findHighestSharedBlockHash(highHash) if err != nil { - return err + return false, err + } + if !highestSharedBlockFound { + return false, nil } log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer) err = flow.downloadHeaders(highestSharedBlockHash, highHash) if err != nil { - return err + return false, err } // If the highHash has not been received, the peer is misbehaving highHashBlockInfo, err := flow.Domain().Consensus().GetBlockInfo(highHash) if err != nil { - return err + return false, err } if !highHashBlockInfo.Exists { - return protocolerrors.Errorf(true, "did not receive "+ + return false, protocolerrors.Errorf(true, "did not receive "+ "highHash header %s from peer %s during header download", highHash, flow.peer) } log.Debugf("Headers downloaded from peer %s", flow.peer) - return nil + return true, nil } -func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { +// findHighestSharedBlock attempts to find the highest shared block between the peer +// and this node. This method may fail because the peer and us have conflicting pruning +// points. In that case we return (nil, false, nil) so that we may stop IBD gracefully. +func (flow *handleRelayInvsFlow) findHighestSharedBlockHash( + targetHash *externalapi.DomainHash) (*externalapi.DomainHash, bool, error) { + log.Debugf("Sending a blockLocator to %s between pruning point and headers selected tip", flow.peer) blockLocator, err := flow.Domain().Consensus().CreateFullHeadersSelectedChainBlockLocator() if err != nil { - return nil, err + return nil, false, err } for { - highestHash, err := flow.fetchHighestHash(targetHash, blockLocator) + highestHash, highestHashFound, err := flow.fetchHighestHash(targetHash, blockLocator) if err != nil { - return nil, err + return nil, false, err + } + if !highestHashFound { + return nil, false, nil } highestHashIndex, err := flow.findHighestHashIndex(highestHash, blockLocator) if err != nil { - return nil, err + return nil, false, err } if highestHashIndex == 0 || @@ -104,7 +122,7 @@ func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *external // an endless loop, we explicitly stop the loop in such situation. (len(blockLocator) == 2 && highestHashIndex == 1) { - return highestHash, nil + return highestHash, true, nil } locatorHashAboveHighestHash := highestHash @@ -114,7 +132,7 @@ func (flow *handleRelayInvsFlow) findHighestSharedBlockHash(targetHash *external blockLocator, err = flow.nextBlockLocator(highestHash, locatorHashAboveHighestHash) if err != nil { - return nil, err + return nil, false, err } } } @@ -159,27 +177,35 @@ func (flow *handleRelayInvsFlow) findHighestHashIndex( return highestHashIndex, nil } +// fetchHighestHash attempts to fetch the highest hash the peer knows amongst the given +// blockLocator. This method may fail because the peer and us have conflicting pruning +// points. In that case we return (nil, false, nil) so that we may stop IBD gracefully. func (flow *handleRelayInvsFlow) fetchHighestHash( - targetHash *externalapi.DomainHash, blockLocator externalapi.BlockLocator) (*externalapi.DomainHash, error) { + targetHash *externalapi.DomainHash, blockLocator externalapi.BlockLocator) (*externalapi.DomainHash, bool, error) { ibdBlockLocatorMessage := appmessage.NewMsgIBDBlockLocator(targetHash, blockLocator) err := flow.outgoingRoute.Enqueue(ibdBlockLocatorMessage) if err != nil { - return nil, err + return nil, false, err } message, err := flow.dequeueIncomingMessageAndSkipInvs(common.DefaultTimeout) if err != nil { - return nil, err + return nil, false, err } - ibdBlockLocatorHighestHashMessage, ok := message.(*appmessage.MsgIBDBlockLocatorHighestHash) - if !ok { - return nil, protocolerrors.Errorf(true, "received unexpected message type. "+ + switch message := message.(type) { + case *appmessage.MsgIBDBlockLocatorHighestHash: + highestHash := message.HighestHash + log.Debugf("The highest hash the peer %s knows is %s", flow.peer, highestHash) + + return highestHash, true, nil + case *appmessage.MsgIBDBlockLocatorHighestHashNotFound: + log.Debugf("Peer %s does not know any block within our blockLocator. "+ + "This should only happen if there's a DAG split deeper than the pruning point.", flow.peer) + return nil, false, nil + default: + return nil, false, protocolerrors.Errorf(true, "received unexpected message type. "+ "expected: %s, got: %s", appmessage.CmdIBDBlockLocatorHighestHash, message.Command()) } - highestHash := ibdBlockLocatorHighestHashMessage.HighestHash - log.Debugf("The highest hash the peer %s knows is %s", flow.peer, highestHash) - - return highestHash, nil } func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externalapi.DomainHash, diff --git a/app/protocol/flows/blockrelay/send_virtual_selected_parent_inv.go b/app/protocol/flows/blockrelay/send_virtual_selected_parent_inv.go new file mode 100644 index 000000000..f6b18ac36 --- /dev/null +++ b/app/protocol/flows/blockrelay/send_virtual_selected_parent_inv.go @@ -0,0 +1,28 @@ +package blockrelay + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" + "github.com/kaspanet/kaspad/domain" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// SendVirtualSelectedParentInvContext is the interface for the context needed for the SendVirtualSelectedParentInv flow. +type SendVirtualSelectedParentInvContext interface { + Domain() domain.Domain +} + +// SendVirtualSelectedParentInv sends a peer the selected parent hash of the virtual +func SendVirtualSelectedParentInv(context SendVirtualSelectedParentInvContext, + outgoingRoute *router.Route, peer *peerpkg.Peer) error { + + virtualSelectedParent, err := context.Domain().Consensus().GetVirtualSelectedParent() + if err != nil { + return err + } + + log.Debugf("Sending virtual selected parent hash %s to peer %s", virtualSelectedParent, peer) + + virtualSelectedParentInv := appmessage.NewMsgInvBlock(virtualSelectedParent) + return outgoingRoute.Enqueue(virtualSelectedParentInv) +} diff --git a/app/protocol/protocol.go b/app/protocol/protocol.go index 87875d93e..34257982c 100644 --- a/app/protocol/protocol.go +++ b/app/protocol/protocol.go @@ -136,11 +136,16 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping * outgoingRoute := router.OutgoingRoute() return []*flow{ + m.registerOneTimeFlow("SendVirtualSelectedParentInv", router, []appmessage.MessageCommand{}, + isStopping, errChan, func(route *routerpkg.Route, peer *peerpkg.Peer) error { + return blockrelay.SendVirtualSelectedParentInv(m.context, outgoingRoute, peer) + }), + m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{ appmessage.CmdInvRelayBlock, appmessage.CmdBlock, appmessage.CmdBlockLocator, appmessage.CmdIBDBlock, appmessage.CmdDoneHeaders, appmessage.CmdUnexpectedPruningPoint, appmessage.CmdPruningPointUTXOSetChunk, appmessage.CmdBlockHeaders, appmessage.CmdPruningPointHash, appmessage.CmdIBDBlockLocatorHighestHash, - appmessage.CmdDonePruningPointUTXOSetChunks}, + appmessage.CmdIBDBlockLocatorHighestHashNotFound, appmessage.CmdDonePruningPointUTXOSetChunks}, isStopping, errChan, func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error { return blockrelay.HandleRelayInvs(m.context, incomingRoute, outgoingRoute, peer) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 53b229181..73f4851d5 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -62,6 +62,7 @@ type KaspadMessage struct { // *KaspadMessage_BlockHeaders // *KaspadMessage_RequestNextPruningPointUtxoSetChunk // *KaspadMessage_DonePruningPointUtxoSetChunks + // *KaspadMessage_IbdBlockLocatorHighestHashNotFound // *KaspadMessage_GetCurrentNetworkRequest // *KaspadMessage_GetCurrentNetworkResponse // *KaspadMessage_SubmitBlockRequest @@ -385,6 +386,13 @@ func (x *KaspadMessage) GetDonePruningPointUtxoSetChunks() *DonePruningPointUtxo return nil } +func (x *KaspadMessage) GetIbdBlockLocatorHighestHashNotFound() *IbdBlockLocatorHighestHashNotFoundMessage { + if x, ok := x.GetPayload().(*KaspadMessage_IbdBlockLocatorHighestHashNotFound); ok { + return x.IbdBlockLocatorHighestHashNotFound + } + return nil +} + func (x *KaspadMessage) GetGetCurrentNetworkRequest() *GetCurrentNetworkRequestMessage { if x, ok := x.GetPayload().(*KaspadMessage_GetCurrentNetworkRequest); ok { return x.GetCurrentNetworkRequest @@ -961,6 +969,10 @@ type KaspadMessage_DonePruningPointUtxoSetChunks struct { DonePruningPointUtxoSetChunks *DonePruningPointUtxoSetChunksMessage `protobuf:"bytes,34,opt,name=donePruningPointUtxoSetChunks,proto3,oneof"` } +type KaspadMessage_IbdBlockLocatorHighestHashNotFound struct { + IbdBlockLocatorHighestHashNotFound *IbdBlockLocatorHighestHashNotFoundMessage `protobuf:"bytes,35,opt,name=ibdBlockLocatorHighestHashNotFound,proto3,oneof"` +} + type KaspadMessage_GetCurrentNetworkRequest struct { GetCurrentNetworkRequest *GetCurrentNetworkRequestMessage `protobuf:"bytes,1001,opt,name=getCurrentNetworkRequest,proto3,oneof"` } @@ -1279,6 +1291,8 @@ func (*KaspadMessage_RequestNextPruningPointUtxoSetChunk) isKaspadMessage_Payloa func (*KaspadMessage_DonePruningPointUtxoSetChunks) isKaspadMessage_Payload() {} +func (*KaspadMessage_IbdBlockLocatorHighestHashNotFound) isKaspadMessage_Payload() {} + func (*KaspadMessage_GetCurrentNetworkRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetCurrentNetworkResponse) isKaspadMessage_Payload() {} @@ -1413,7 +1427,7 @@ var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xd7, 0x4b, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x6f, 0x22, 0xe0, 0x4c, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, @@ -1571,467 +1585,476 @@ var file_messages_proto_rawDesc = []byte{ 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1d, 0x64, 0x6f, 0x6e, 0x65, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x53, 0x65, 0x74, 0x43, 0x68, 0x75, 0x6e, - 0x6b, 0x73, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, - 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x6b, 0x73, 0x12, 0x86, 0x01, 0x0a, 0x22, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, + 0x68, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x34, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x62, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, + 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x22, 0x69, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x69, 0x0a, 0x18, 0x67, + 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, - 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x12, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, + 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, - 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xee, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xef, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, - 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, - 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, - 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0xf0, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, + 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x63, 0x0a, 0x16, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xf1, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x41, 0x64, 0x64, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0xf2, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, - 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, - 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, - 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, - 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, - 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, - 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, - 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, - 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, - 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, - 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x69, 0x0a, 0x18, + 0x67, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf3, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, + 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0xf4, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xf5, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x54, 0x69, 0x70, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xf6, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, + 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x4d, + 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0xf8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x75, 0x0a, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xf9, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, + 0x52, 0x1c, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x65, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, + 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0xfa, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x64, 0x64, + 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x61, + 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xfb, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x50, + 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x73, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfc, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x73, 0x75, + 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xfd, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x73, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xfe, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xff, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x2d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, + 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, + 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x18, 0x82, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 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, 0x48, - 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, - 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x84, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, + 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0xa8, 0x01, 0x0a, 0x2d, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, - 0x65, 0x6e, 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, - 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x85, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 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, 0x48, 0x00, 0x52, 0x2d, + 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, + 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xab, 0x01, + 0x0a, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, + 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x86, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x2e, 0x67, 0x65, 0x74, + 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x67, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x87, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, + 0x0a, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x88, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x89, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x14, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, - 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, - 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 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, 0x48, 0x00, - 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, + 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x15, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8a, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x15, + 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x8b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, + 0x48, 0x00, 0x52, 0x16, 0x67, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x17, 0x67, 0x65, + 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x8c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x17, 0x67, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1e, 0x72, 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, 0x18, 0x8d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x72, 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, 0x12, 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x1e, 0x72, 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, 0x12, + 0x7e, 0x0a, 0x1f, 0x72, 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, 0x18, 0x8e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, + 0x72, 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, 0x12, + 0x7b, 0x0a, 0x1e, 0x6e, 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, 0x18, 0x8f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x12, 0x7e, 0x0a, 0x1f, 0x6e, 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, 0x18, 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1e, 0x6e, 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, 0x12, 0x7e, 0x0a, 0x1f, + 0x6e, 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, 0x18, + 0x90, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, + 0x66, 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, 0x18, 0x91, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, - 0x48, 0x00, 0x52, 0x1f, 0x6e, 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, 0x12, 0x75, 0x0a, 0x1c, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x18, 0x91, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x1c, 0x66, 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, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, + 0x69, 0x6f, 0x6e, 0x12, 0x8d, 0x01, 0x0a, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x18, 0x92, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x24, 0x66, 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, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, - 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, - 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, - 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, - 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, - 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, - 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, - 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, - 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x69, 0x0a, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, + 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x93, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6c, + 0x0a, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x94, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, + 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x00, 0x52, 0x19, 0x67, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x45, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0f, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x95, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x68, 0x75, + 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x10, + 0x73, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x18, 0x96, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x73, + 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x97, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x00, 0x52, 0x11, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x67, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x98, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 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, 0x48, 0x00, 0x52, 0x12, 0x67, 0x65, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, + 0x0a, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x99, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x19, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1a, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x1a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, + 0x18, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x9b, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x18, + 0x75, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6f, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9c, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, + 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x67, + 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x0a, 0x1b, 0x67, 0x65, 0x74, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9d, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, + 0x52, 0x1b, 0x67, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x99, 0x01, + 0x0a, 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x9e, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x28, 0x67, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9c, 0x01, 0x0a, 0x29, 0x67, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x9f, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, + 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x29, 0x67, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0xb7, 0x01, 0x0a, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa0, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x44, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x32, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xba, 0x01, 0x0a, 0x33, 0x6e, 0x6f, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0xa1, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, - 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x33, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xb4, 0x01, 0x0a, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xa2, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, - 0x0a, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa3, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, - 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x00, 0x52, 0x0a, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, - 0x0a, 0x0b, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa4, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0xa5, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x75, 0x6e, 0x62, - 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x0d, 0x75, 0x6e, 0x62, - 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa6, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, - 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa7, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, - 0x52, 0x0e, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0xa8, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, - 0x0f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x48, 0x00, 0x52, 0x31, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0a, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0xa3, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x61, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0b, 0x62, 0x61, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa4, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0b, + 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x75, + 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa5, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, + 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x48, 0x0a, 0x0d, 0x75, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xa6, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x75, + 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, + 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa7, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x67, 0x65, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x0f, 0x67, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0xa8, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 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, 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 ( @@ -2079,70 +2102,71 @@ var file_messages_proto_goTypes = []interface{}{ (*BlockHeadersMessage)(nil), // 28: protowire.BlockHeadersMessage (*RequestNextPruningPointUtxoSetChunkMessage)(nil), // 29: protowire.RequestNextPruningPointUtxoSetChunkMessage (*DonePruningPointUtxoSetChunksMessage)(nil), // 30: protowire.DonePruningPointUtxoSetChunksMessage - (*GetCurrentNetworkRequestMessage)(nil), // 31: protowire.GetCurrentNetworkRequestMessage - (*GetCurrentNetworkResponseMessage)(nil), // 32: protowire.GetCurrentNetworkResponseMessage - (*SubmitBlockRequestMessage)(nil), // 33: protowire.SubmitBlockRequestMessage - (*SubmitBlockResponseMessage)(nil), // 34: protowire.SubmitBlockResponseMessage - (*GetBlockTemplateRequestMessage)(nil), // 35: protowire.GetBlockTemplateRequestMessage - (*GetBlockTemplateResponseMessage)(nil), // 36: protowire.GetBlockTemplateResponseMessage - (*NotifyBlockAddedRequestMessage)(nil), // 37: protowire.NotifyBlockAddedRequestMessage - (*NotifyBlockAddedResponseMessage)(nil), // 38: protowire.NotifyBlockAddedResponseMessage - (*BlockAddedNotificationMessage)(nil), // 39: protowire.BlockAddedNotificationMessage - (*GetPeerAddressesRequestMessage)(nil), // 40: protowire.GetPeerAddressesRequestMessage - (*GetPeerAddressesResponseMessage)(nil), // 41: protowire.GetPeerAddressesResponseMessage - (*GetSelectedTipHashRequestMessage)(nil), // 42: protowire.GetSelectedTipHashRequestMessage - (*GetSelectedTipHashResponseMessage)(nil), // 43: protowire.GetSelectedTipHashResponseMessage - (*GetMempoolEntryRequestMessage)(nil), // 44: protowire.GetMempoolEntryRequestMessage - (*GetMempoolEntryResponseMessage)(nil), // 45: protowire.GetMempoolEntryResponseMessage - (*GetConnectedPeerInfoRequestMessage)(nil), // 46: protowire.GetConnectedPeerInfoRequestMessage - (*GetConnectedPeerInfoResponseMessage)(nil), // 47: protowire.GetConnectedPeerInfoResponseMessage - (*AddPeerRequestMessage)(nil), // 48: protowire.AddPeerRequestMessage - (*AddPeerResponseMessage)(nil), // 49: protowire.AddPeerResponseMessage - (*SubmitTransactionRequestMessage)(nil), // 50: protowire.SubmitTransactionRequestMessage - (*SubmitTransactionResponseMessage)(nil), // 51: protowire.SubmitTransactionResponseMessage - (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 52: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 53: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 54: protowire.VirtualSelectedParentChainChangedNotificationMessage - (*GetBlockRequestMessage)(nil), // 55: protowire.GetBlockRequestMessage - (*GetBlockResponseMessage)(nil), // 56: protowire.GetBlockResponseMessage - (*GetSubnetworkRequestMessage)(nil), // 57: protowire.GetSubnetworkRequestMessage - (*GetSubnetworkResponseMessage)(nil), // 58: protowire.GetSubnetworkResponseMessage - (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 59: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 60: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - (*GetBlocksRequestMessage)(nil), // 61: protowire.GetBlocksRequestMessage - (*GetBlocksResponseMessage)(nil), // 62: protowire.GetBlocksResponseMessage - (*GetBlockCountRequestMessage)(nil), // 63: protowire.GetBlockCountRequestMessage - (*GetBlockCountResponseMessage)(nil), // 64: protowire.GetBlockCountResponseMessage - (*GetBlockDagInfoRequestMessage)(nil), // 65: protowire.GetBlockDagInfoRequestMessage - (*GetBlockDagInfoResponseMessage)(nil), // 66: protowire.GetBlockDagInfoResponseMessage - (*ResolveFinalityConflictRequestMessage)(nil), // 67: protowire.ResolveFinalityConflictRequestMessage - (*ResolveFinalityConflictResponseMessage)(nil), // 68: protowire.ResolveFinalityConflictResponseMessage - (*NotifyFinalityConflictsRequestMessage)(nil), // 69: protowire.NotifyFinalityConflictsRequestMessage - (*NotifyFinalityConflictsResponseMessage)(nil), // 70: protowire.NotifyFinalityConflictsResponseMessage - (*FinalityConflictNotificationMessage)(nil), // 71: protowire.FinalityConflictNotificationMessage - (*FinalityConflictResolvedNotificationMessage)(nil), // 72: protowire.FinalityConflictResolvedNotificationMessage - (*GetMempoolEntriesRequestMessage)(nil), // 73: protowire.GetMempoolEntriesRequestMessage - (*GetMempoolEntriesResponseMessage)(nil), // 74: protowire.GetMempoolEntriesResponseMessage - (*ShutDownRequestMessage)(nil), // 75: protowire.ShutDownRequestMessage - (*ShutDownResponseMessage)(nil), // 76: protowire.ShutDownResponseMessage - (*GetHeadersRequestMessage)(nil), // 77: protowire.GetHeadersRequestMessage - (*GetHeadersResponseMessage)(nil), // 78: protowire.GetHeadersResponseMessage - (*NotifyUtxosChangedRequestMessage)(nil), // 79: protowire.NotifyUtxosChangedRequestMessage - (*NotifyUtxosChangedResponseMessage)(nil), // 80: protowire.NotifyUtxosChangedResponseMessage - (*UtxosChangedNotificationMessage)(nil), // 81: protowire.UtxosChangedNotificationMessage - (*GetUtxosByAddressesRequestMessage)(nil), // 82: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 83: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 84: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 85: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 86: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 87: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 88: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - (*BanRequestMessage)(nil), // 89: protowire.BanRequestMessage - (*BanResponseMessage)(nil), // 90: protowire.BanResponseMessage - (*UnbanRequestMessage)(nil), // 91: protowire.UnbanRequestMessage - (*UnbanResponseMessage)(nil), // 92: protowire.UnbanResponseMessage - (*GetInfoRequestMessage)(nil), // 93: protowire.GetInfoRequestMessage - (*GetInfoResponseMessage)(nil), // 94: protowire.GetInfoResponseMessage + (*IbdBlockLocatorHighestHashNotFoundMessage)(nil), // 31: protowire.IbdBlockLocatorHighestHashNotFoundMessage + (*GetCurrentNetworkRequestMessage)(nil), // 32: protowire.GetCurrentNetworkRequestMessage + (*GetCurrentNetworkResponseMessage)(nil), // 33: protowire.GetCurrentNetworkResponseMessage + (*SubmitBlockRequestMessage)(nil), // 34: protowire.SubmitBlockRequestMessage + (*SubmitBlockResponseMessage)(nil), // 35: protowire.SubmitBlockResponseMessage + (*GetBlockTemplateRequestMessage)(nil), // 36: protowire.GetBlockTemplateRequestMessage + (*GetBlockTemplateResponseMessage)(nil), // 37: protowire.GetBlockTemplateResponseMessage + (*NotifyBlockAddedRequestMessage)(nil), // 38: protowire.NotifyBlockAddedRequestMessage + (*NotifyBlockAddedResponseMessage)(nil), // 39: protowire.NotifyBlockAddedResponseMessage + (*BlockAddedNotificationMessage)(nil), // 40: protowire.BlockAddedNotificationMessage + (*GetPeerAddressesRequestMessage)(nil), // 41: protowire.GetPeerAddressesRequestMessage + (*GetPeerAddressesResponseMessage)(nil), // 42: protowire.GetPeerAddressesResponseMessage + (*GetSelectedTipHashRequestMessage)(nil), // 43: protowire.GetSelectedTipHashRequestMessage + (*GetSelectedTipHashResponseMessage)(nil), // 44: protowire.GetSelectedTipHashResponseMessage + (*GetMempoolEntryRequestMessage)(nil), // 45: protowire.GetMempoolEntryRequestMessage + (*GetMempoolEntryResponseMessage)(nil), // 46: protowire.GetMempoolEntryResponseMessage + (*GetConnectedPeerInfoRequestMessage)(nil), // 47: protowire.GetConnectedPeerInfoRequestMessage + (*GetConnectedPeerInfoResponseMessage)(nil), // 48: protowire.GetConnectedPeerInfoResponseMessage + (*AddPeerRequestMessage)(nil), // 49: protowire.AddPeerRequestMessage + (*AddPeerResponseMessage)(nil), // 50: protowire.AddPeerResponseMessage + (*SubmitTransactionRequestMessage)(nil), // 51: protowire.SubmitTransactionRequestMessage + (*SubmitTransactionResponseMessage)(nil), // 52: protowire.SubmitTransactionResponseMessage + (*NotifyVirtualSelectedParentChainChangedRequestMessage)(nil), // 53: protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + (*NotifyVirtualSelectedParentChainChangedResponseMessage)(nil), // 54: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + (*VirtualSelectedParentChainChangedNotificationMessage)(nil), // 55: protowire.VirtualSelectedParentChainChangedNotificationMessage + (*GetBlockRequestMessage)(nil), // 56: protowire.GetBlockRequestMessage + (*GetBlockResponseMessage)(nil), // 57: protowire.GetBlockResponseMessage + (*GetSubnetworkRequestMessage)(nil), // 58: protowire.GetSubnetworkRequestMessage + (*GetSubnetworkResponseMessage)(nil), // 59: protowire.GetSubnetworkResponseMessage + (*GetVirtualSelectedParentChainFromBlockRequestMessage)(nil), // 60: protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + (*GetVirtualSelectedParentChainFromBlockResponseMessage)(nil), // 61: protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + (*GetBlocksRequestMessage)(nil), // 62: protowire.GetBlocksRequestMessage + (*GetBlocksResponseMessage)(nil), // 63: protowire.GetBlocksResponseMessage + (*GetBlockCountRequestMessage)(nil), // 64: protowire.GetBlockCountRequestMessage + (*GetBlockCountResponseMessage)(nil), // 65: protowire.GetBlockCountResponseMessage + (*GetBlockDagInfoRequestMessage)(nil), // 66: protowire.GetBlockDagInfoRequestMessage + (*GetBlockDagInfoResponseMessage)(nil), // 67: protowire.GetBlockDagInfoResponseMessage + (*ResolveFinalityConflictRequestMessage)(nil), // 68: protowire.ResolveFinalityConflictRequestMessage + (*ResolveFinalityConflictResponseMessage)(nil), // 69: protowire.ResolveFinalityConflictResponseMessage + (*NotifyFinalityConflictsRequestMessage)(nil), // 70: protowire.NotifyFinalityConflictsRequestMessage + (*NotifyFinalityConflictsResponseMessage)(nil), // 71: protowire.NotifyFinalityConflictsResponseMessage + (*FinalityConflictNotificationMessage)(nil), // 72: protowire.FinalityConflictNotificationMessage + (*FinalityConflictResolvedNotificationMessage)(nil), // 73: protowire.FinalityConflictResolvedNotificationMessage + (*GetMempoolEntriesRequestMessage)(nil), // 74: protowire.GetMempoolEntriesRequestMessage + (*GetMempoolEntriesResponseMessage)(nil), // 75: protowire.GetMempoolEntriesResponseMessage + (*ShutDownRequestMessage)(nil), // 76: protowire.ShutDownRequestMessage + (*ShutDownResponseMessage)(nil), // 77: protowire.ShutDownResponseMessage + (*GetHeadersRequestMessage)(nil), // 78: protowire.GetHeadersRequestMessage + (*GetHeadersResponseMessage)(nil), // 79: protowire.GetHeadersResponseMessage + (*NotifyUtxosChangedRequestMessage)(nil), // 80: protowire.NotifyUtxosChangedRequestMessage + (*NotifyUtxosChangedResponseMessage)(nil), // 81: protowire.NotifyUtxosChangedResponseMessage + (*UtxosChangedNotificationMessage)(nil), // 82: protowire.UtxosChangedNotificationMessage + (*GetUtxosByAddressesRequestMessage)(nil), // 83: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 84: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 85: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 86: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 87: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 88: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 89: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*BanRequestMessage)(nil), // 90: protowire.BanRequestMessage + (*BanResponseMessage)(nil), // 91: protowire.BanResponseMessage + (*UnbanRequestMessage)(nil), // 92: protowire.UnbanRequestMessage + (*UnbanResponseMessage)(nil), // 93: protowire.UnbanResponseMessage + (*GetInfoRequestMessage)(nil), // 94: protowire.GetInfoRequestMessage + (*GetInfoResponseMessage)(nil), // 95: protowire.GetInfoResponseMessage } var file_messages_proto_depIdxs = []int32{ 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage @@ -2176,79 +2200,80 @@ var file_messages_proto_depIdxs = []int32{ 28, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage 29, // 29: protowire.KaspadMessage.requestNextPruningPointUtxoSetChunk:type_name -> protowire.RequestNextPruningPointUtxoSetChunkMessage 30, // 30: protowire.KaspadMessage.donePruningPointUtxoSetChunks:type_name -> protowire.DonePruningPointUtxoSetChunksMessage - 31, // 31: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 32, // 32: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 33, // 33: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 34, // 34: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 35, // 35: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 36, // 36: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 37, // 37: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 38, // 38: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 39, // 39: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 40, // 40: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 41, // 41: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 42, // 42: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 43, // 43: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 44, // 44: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 45, // 45: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 46, // 46: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 47, // 47: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 48, // 48: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 49, // 49: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 50, // 50: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 51, // 51: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 52, // 52: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 53, // 53: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 54, // 54: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 55, // 55: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 56, // 56: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 57, // 57: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 58, // 58: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 59, // 59: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 60, // 60: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 61, // 61: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 62, // 62: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 63, // 63: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 64, // 64: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 65, // 65: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 66, // 66: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 67, // 67: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 68, // 68: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 69, // 69: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 70, // 70: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 71, // 71: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 72, // 72: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 73, // 73: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 74, // 74: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 75, // 75: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 76, // 76: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 77, // 77: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 78, // 78: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 79, // 79: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 80, // 80: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 81, // 81: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 82, // 82: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 83, // 83: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 84, // 84: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 85, // 85: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 86, // 86: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 87, // 87: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 88, // 88: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 89, // 89: protowire.KaspadMessage.banRequest:type_name -> protowire.BanRequestMessage - 90, // 90: protowire.KaspadMessage.banResponse:type_name -> protowire.BanResponseMessage - 91, // 91: protowire.KaspadMessage.unbanRequest:type_name -> protowire.UnbanRequestMessage - 92, // 92: protowire.KaspadMessage.unbanResponse:type_name -> protowire.UnbanResponseMessage - 93, // 93: protowire.KaspadMessage.getInfoRequest:type_name -> protowire.GetInfoRequestMessage - 94, // 94: protowire.KaspadMessage.getInfoResponse:type_name -> protowire.GetInfoResponseMessage - 0, // 95: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 96: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 97: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 98: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 97, // [97:99] is the sub-list for method output_type - 95, // [95:97] is the sub-list for method input_type - 95, // [95:95] is the sub-list for extension type_name - 95, // [95:95] is the sub-list for extension extendee - 0, // [0:95] is the sub-list for field type_name + 31, // 31: protowire.KaspadMessage.ibdBlockLocatorHighestHashNotFound:type_name -> protowire.IbdBlockLocatorHighestHashNotFoundMessage + 32, // 32: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 33, // 33: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 34, // 34: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 35, // 35: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 36, // 36: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 37, // 37: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 38, // 38: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 39, // 39: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 40, // 40: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 41, // 41: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 42, // 42: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 43, // 43: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 44, // 44: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 45, // 45: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 46, // 46: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 47, // 47: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 48, // 48: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 49, // 49: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 50, // 50: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 51, // 51: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 52, // 52: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 53, // 53: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 54, // 54: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 55, // 55: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 56, // 56: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 57, // 57: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 58, // 58: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 59, // 59: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 60, // 60: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 61, // 61: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 62, // 62: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 63, // 63: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 64, // 64: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 65, // 65: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 66, // 66: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 67, // 67: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 68, // 68: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 69, // 69: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 70, // 70: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 71, // 71: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 72, // 72: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 73, // 73: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 74, // 74: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 75, // 75: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 76, // 76: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 77, // 77: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 78, // 78: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 79, // 79: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 80, // 80: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 81, // 81: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 82, // 82: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 83, // 83: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 84, // 84: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 85, // 85: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 86, // 86: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 87, // 87: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 88, // 88: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 89, // 89: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 90, // 90: protowire.KaspadMessage.banRequest:type_name -> protowire.BanRequestMessage + 91, // 91: protowire.KaspadMessage.banResponse:type_name -> protowire.BanResponseMessage + 92, // 92: protowire.KaspadMessage.unbanRequest:type_name -> protowire.UnbanRequestMessage + 93, // 93: protowire.KaspadMessage.unbanResponse:type_name -> protowire.UnbanResponseMessage + 94, // 94: protowire.KaspadMessage.getInfoRequest:type_name -> protowire.GetInfoRequestMessage + 95, // 95: protowire.KaspadMessage.getInfoResponse:type_name -> protowire.GetInfoResponseMessage + 0, // 96: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 97: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 98: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 99: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 98, // [98:100] is the sub-list for method output_type + 96, // [96:98] is the sub-list for method input_type + 96, // [96:96] is the sub-list for extension type_name + 96, // [96:96] is the sub-list for extension extendee + 0, // [0:96] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2304,6 +2329,7 @@ func file_messages_proto_init() { (*KaspadMessage_BlockHeaders)(nil), (*KaspadMessage_RequestNextPruningPointUtxoSetChunk)(nil), (*KaspadMessage_DonePruningPointUtxoSetChunks)(nil), + (*KaspadMessage_IbdBlockLocatorHighestHashNotFound)(nil), (*KaspadMessage_GetCurrentNetworkRequest)(nil), (*KaspadMessage_GetCurrentNetworkResponse)(nil), (*KaspadMessage_SubmitBlockRequest)(nil), diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index 903dfa7cc..af9b87550 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -39,6 +39,7 @@ message KaspadMessage { BlockHeadersMessage blockHeaders = 32; RequestNextPruningPointUtxoSetChunkMessage requestNextPruningPointUtxoSetChunk = 33; DonePruningPointUtxoSetChunksMessage donePruningPointUtxoSetChunks = 34; + IbdBlockLocatorHighestHashNotFoundMessage ibdBlockLocatorHighestHashNotFound = 35; GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go index 6a74c6316..f5ff5a7ed 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.pb.go @@ -2162,6 +2162,44 @@ func (x *IbdBlockLocatorHighestHashMessage) GetHighestHash() *Hash { return nil } +type IbdBlockLocatorHighestHashNotFoundMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *IbdBlockLocatorHighestHashNotFoundMessage) Reset() { + *x = IbdBlockLocatorHighestHashNotFoundMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_p2p_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IbdBlockLocatorHighestHashNotFoundMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IbdBlockLocatorHighestHashNotFoundMessage) ProtoMessage() {} + +func (x *IbdBlockLocatorHighestHashNotFoundMessage) ProtoReflect() protoreflect.Message { + mi := &file_p2p_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IbdBlockLocatorHighestHashNotFoundMessage.ProtoReflect.Descriptor instead. +func (*IbdBlockLocatorHighestHashNotFoundMessage) Descriptor() ([]byte, []int) { + return file_p2p_proto_rawDescGZIP(), []int{40} +} + type BlockHeadersMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2173,7 +2211,7 @@ type BlockHeadersMessage struct { func (x *BlockHeadersMessage) Reset() { *x = BlockHeadersMessage{} if protoimpl.UnsafeEnabled { - mi := &file_p2p_proto_msgTypes[40] + mi := &file_p2p_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2186,7 +2224,7 @@ func (x *BlockHeadersMessage) String() string { func (*BlockHeadersMessage) ProtoMessage() {} func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { - mi := &file_p2p_proto_msgTypes[40] + mi := &file_p2p_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2199,7 +2237,7 @@ func (x *BlockHeadersMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BlockHeadersMessage.ProtoReflect.Descriptor instead. func (*BlockHeadersMessage) Descriptor() ([]byte, []int) { - return file_p2p_proto_rawDescGZIP(), []int{40} + return file_p2p_proto_rawDescGZIP(), []int{41} } func (x *BlockHeadersMessage) GetBlockHeaders() []*BlockHeaderMessage { @@ -2461,15 +2499,18 @@ var file_p2p_proto_rawDesc = []byte{ 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x22, 0x58, 0x0a, 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 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, + 0x22, 0x2b, 0x0a, 0x29, 0x49, 0x62, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x6f, 0x72, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x4e, 0x6f, + 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x58, 0x0a, + 0x13, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 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 ( @@ -2484,7 +2525,7 @@ func file_p2p_proto_rawDescGZIP() []byte { return file_p2p_proto_rawDescData } -var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 41) +var file_p2p_proto_msgTypes = make([]protoimpl.MessageInfo, 42) var file_p2p_proto_goTypes = []interface{}{ (*RequestAddressesMessage)(nil), // 0: protowire.RequestAddressesMessage (*AddressesMessage)(nil), // 1: protowire.AddressesMessage @@ -2526,7 +2567,8 @@ var file_p2p_proto_goTypes = []interface{}{ (*PruningPointHashMessage)(nil), // 37: protowire.PruningPointHashMessage (*IbdBlockLocatorMessage)(nil), // 38: protowire.IbdBlockLocatorMessage (*IbdBlockLocatorHighestHashMessage)(nil), // 39: protowire.IbdBlockLocatorHighestHashMessage - (*BlockHeadersMessage)(nil), // 40: protowire.BlockHeadersMessage + (*IbdBlockLocatorHighestHashNotFoundMessage)(nil), // 40: protowire.IbdBlockLocatorHighestHashNotFoundMessage + (*BlockHeadersMessage)(nil), // 41: protowire.BlockHeadersMessage } var file_p2p_proto_depIdxs = []int32{ 3, // 0: protowire.RequestAddressesMessage.subnetworkId:type_name -> protowire.SubnetworkId @@ -3061,6 +3103,18 @@ func file_p2p_proto_init() { } } file_p2p_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IbdBlockLocatorHighestHashNotFoundMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_p2p_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlockHeadersMessage); i { case 0: return &v.state @@ -3079,7 +3133,7 @@ func file_p2p_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_p2p_proto_rawDesc, NumEnums: 0, - NumMessages: 41, + NumMessages: 42, NumExtensions: 0, NumServices: 0, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto index 1e729793c..0b890b338 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto @@ -195,6 +195,9 @@ message IbdBlockLocatorHighestHashMessage { Hash highestHash = 1; } +message IbdBlockLocatorHighestHashNotFoundMessage { +} + message BlockHeadersMessage { repeated BlockHeaderMessage blockHeaders = 1; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash_not_found.go b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash_not_found.go new file mode 100644 index 000000000..494b48f81 --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/p2p_ibd_block_locator_highest_hash_not_found.go @@ -0,0 +1,12 @@ +package protowire + +import "github.com/kaspanet/kaspad/app/appmessage" + +func (x *KaspadMessage_IbdBlockLocatorHighestHashNotFound) toAppMessage() (appmessage.Message, error) { + return &appmessage.MsgIBDBlockLocatorHighestHashNotFound{}, nil +} + +func (x *KaspadMessage_IbdBlockLocatorHighestHashNotFound) fromAppMessage(message *appmessage.MsgIBDBlockLocatorHighestHashNotFound) error { + x.IbdBlockLocatorHighestHashNotFound = &IbdBlockLocatorHighestHashNotFoundMessage{} + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index 9d4107379..89fad67ae 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -251,6 +251,13 @@ func toP2PPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.MsgIBDBlockLocatorHighestHashNotFound: + payload := new(KaspadMessage_IbdBlockLocatorHighestHashNotFound) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil case *appmessage.BlockHeadersMessage: payload := new(KaspadMessage_BlockHeaders) err := payload.fromAppMessage(message) diff --git a/testing/integration/ibd_test.go b/testing/integration/ibd_test.go index 04e8a8000..2dcb8f681 100644 --- a/testing/integration/ibd_test.go +++ b/testing/integration/ibd_test.go @@ -16,7 +16,7 @@ func TestIBD(t *testing.T) { syncer, syncee, _, teardown := standardSetup(t) defer teardown() - for i := 0; i < numBlocks-1; i++ { + for i := 0; i < numBlocks; i++ { mineNextBlock(t, syncer) } @@ -28,10 +28,8 @@ func TestIBD(t *testing.T) { blockAddedWG.Done() }) - connect(t, syncer, syncee) - // We expect this to trigger IBD - mineNextBlock(t, syncer) + connect(t, syncer, syncee) select { case <-time.After(defaultTimeout): @@ -97,10 +95,8 @@ func TestIBDWithPruning(t *testing.T) { mineNextBlock(t, syncer) } - connect(t, syncer, syncee) - // We expect this to trigger IBD - mineNextBlock(t, syncer) + connect(t, syncer, syncee) syncerBlockCountResponse, err := syncer.rpcClient.GetBlockCount() if err != nil { diff --git a/testing/integration/selected_parent_chain_test.go b/testing/integration/selected_parent_chain_test.go index 9c3c9937e..0e1e6487d 100644 --- a/testing/integration/selected_parent_chain_test.go +++ b/testing/integration/selected_parent_chain_test.go @@ -1,6 +1,7 @@ package integration import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "testing" "github.com/kaspanet/kaspad/app/appmessage" @@ -48,18 +49,17 @@ func TestVirtualSelectedParentChain(t *testing.T) { chain1TipHashString = minedBlockHashString } - // In kaspad2, mine a different chain of `blockAmountToMine` + // In kaspad2, mine a different chain of `blockAmountToMine` + 1 // blocks over the genesis - for i := 0; i < blockAmountToMine; i++ { - mineNextBlock(t, kaspad2) + var chain2Tip *externalapi.DomainBlock + for i := 0; i < blockAmountToMine+1; i++ { + chain2Tip = mineNextBlock(t, kaspad2) } - // Connect the two kaspads + // Connect the two kaspads. This should trigger sync + // between the two nodes connect(t, kaspad1, kaspad2) - // In kaspad2, mine another block. This should trigger sync - // between the two nodes - chain2Tip := mineNextBlock(t, kaspad2) chain2TipHash := consensushashing.BlockHash(chain2Tip) chain2TipHashString := chain2TipHash.String() From 171deded4ef56a38be66abcd752479565dbe781a Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 10 Feb 2021 18:27:04 +0200 Subject: [PATCH 327/351] Implement GetBlocks RPC command (#1514) * Remove BlockHexes from GetBlocks request and response * Add GetBlocks RPC * Include the selectedTip's anticone in GetBlocks * Add Anticone to fakeRelayInvsContext * Include verbose data only if it was requested + Add comments to HandleGetBlocks * Allow antiPastHashesBetween to receive unrelated low and high hashes * Convert to/from protowire GetBlocksResponse with no verbose data correctly * Removed NextLowHash * Update GetBlocks in rpc_client * Validate in consensus.Anticone that blockHash exists Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/appmessage/rpc_get_blocks.go | 17 +- .../flows/testing/handle_relay_invs_test.go | 11 +- app/rpc/rpchandlers/get_blocks.go | 76 ++- domain/consensus/consensus.go | 12 + domain/consensus/factory.go | 6 +- .../consensus/model/externalapi/consensus.go | 1 + ...interface_processes_dagtraversalmanager.go | 2 +- .../processes/dagtraversalmanager/anticone.go | 12 +- .../dagtraversalmanager.go | 5 +- .../processes/syncmanager/antipast.go | 29 +- .../server/grpcserver/protowire/rpc.md | 1 - .../server/grpcserver/protowire/rpc.pb.go | 529 +++++++++--------- .../server/grpcserver/protowire/rpc.proto | 8 +- .../grpcserver/protowire/rpc_get_blocks.go | 66 +-- .../network/rpcclient/rpc_get_blocks.go | 7 +- 15 files changed, 442 insertions(+), 340 deletions(-) diff --git a/app/appmessage/rpc_get_blocks.go b/app/appmessage/rpc_get_blocks.go index 3a2866406..9379a7482 100644 --- a/app/appmessage/rpc_get_blocks.go +++ b/app/appmessage/rpc_get_blocks.go @@ -4,9 +4,9 @@ package appmessage // its respective RPC message type GetBlocksRequestMessage struct { baseMessage - LowHash string - IncludeBlockHexes bool - IncludeBlockVerboseData bool + LowHash string + IncludeBlockVerboseData bool + IncludeTransactionVerboseData bool } // Command returns the protocol command string for the message @@ -15,11 +15,12 @@ func (msg *GetBlocksRequestMessage) Command() MessageCommand { } // NewGetBlocksRequestMessage returns a instance of the message -func NewGetBlocksRequestMessage(lowHash string, includeBlockHexes bool, includeBlockVerboseData bool) *GetBlocksRequestMessage { +func NewGetBlocksRequestMessage(lowHash string, includeBlockVerboseData bool, + includeTransactionVerboseData bool) *GetBlocksRequestMessage { return &GetBlocksRequestMessage{ - LowHash: lowHash, - IncludeBlockHexes: includeBlockHexes, - IncludeBlockVerboseData: includeBlockVerboseData, + LowHash: lowHash, + IncludeBlockVerboseData: includeBlockVerboseData, + IncludeTransactionVerboseData: includeTransactionVerboseData, } } @@ -28,7 +29,6 @@ func NewGetBlocksRequestMessage(lowHash string, includeBlockHexes bool, includeB type GetBlocksResponseMessage struct { baseMessage BlockHashes []string - BlockHexes []string BlockVerboseData []*BlockVerboseData Error *RPCError @@ -45,7 +45,6 @@ func NewGetBlocksResponseMessage(blockHashes []string, blockHexes []string, return &GetBlocksResponseMessage{ BlockHashes: blockHashes, - BlockHexes: blockHexes, BlockVerboseData: blockVerboseData, } } diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 9708db895..36f28db13 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -2,6 +2,10 @@ package testing import ( "fmt" + "sync" + "testing" + "time" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/protocol/flows/blockrelay" peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" @@ -18,9 +22,6 @@ import ( "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" "github.com/kaspanet/kaspad/util/mstime" "github.com/pkg/errors" - "sync" - "testing" - "time" ) var orphanBlock = &externalapi.DomainBlock{ @@ -109,6 +110,10 @@ type fakeRelayInvsContext struct { rwLock sync.RWMutex } +func (f *fakeRelayInvsContext) Anticone(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) +} + func (f *fakeRelayInvsContext) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) { panic(errors.Errorf("called unimplemented function from test '%s'", f.testName)) } diff --git a/app/rpc/rpchandlers/get_blocks.go b/app/rpc/rpchandlers/get_blocks.go index 8fa42245b..d775c693f 100644 --- a/app/rpc/rpchandlers/get_blocks.go +++ b/app/rpc/rpchandlers/get_blocks.go @@ -3,6 +3,8 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" ) @@ -14,7 +16,77 @@ const ( // HandleGetBlocks handles the respectively named RPC command func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) { - response := &appmessage.GetBlocksResponseMessage{} - response.Error = appmessage.RPCErrorf("not implemented") + getBlocksRequest := request.(*appmessage.GetBlocksRequestMessage) + + // Validate that user didn't set IncludeTransactionVerboseData without setting IncludeBlockVerboseData + if !getBlocksRequest.IncludeBlockVerboseData && getBlocksRequest.IncludeTransactionVerboseData { + return &appmessage.GetBlocksResponseMessage{ + Error: appmessage.RPCErrorf( + "If includeTransactionVerboseData is set, then includeBlockVerboseData must be set as well"), + }, nil + } + + // Decode lowHash + // If lowHash is empty - use genesis instead. + lowHash := context.Config.ActiveNetParams.GenesisHash + if getBlocksRequest.LowHash != "" { + var err error + lowHash, err = externalapi.NewDomainHashFromString(getBlocksRequest.LowHash) + if err != nil { + return &appmessage.GetBlocksResponseMessage{ + Error: appmessage.RPCErrorf("Could not decode lowHash %s: %s", getBlocksRequest.LowHash, err), + }, nil + } + } + + // Get hashes between lowHash and virtualSelectedParent + virtualSelectedParent, err := context.Domain.Consensus().GetVirtualSelectedParent() + if err != nil { + return nil, err + } + blockHashes, err := context.Domain.Consensus().GetHashesBetween( + lowHash, virtualSelectedParent, maxBlocksInGetBlocksResponse) + if err != nil { + return nil, err + } + + // If there are no maxBlocksInGetBlocksResponse between lowHash and virtualSelectedParent - + // add virtualSelectedParent's anticone + if len(blockHashes) < maxBlocksInGetBlocksResponse { + virtualSelectedParentAnticone, err := context.Domain.Consensus().Anticone(virtualSelectedParent) + if err != nil { + return nil, err + } + blockHashes = append(blockHashes, virtualSelectedParentAnticone...) + } + + // Both GetHashesBetween and Anticone might return more then the allowed number of blocks, so + // trim any extra blocks. + if len(blockHashes) > maxBlocksInGetBlocksResponse { + blockHashes = blockHashes[:maxBlocksInGetBlocksResponse] + } + + // Prepare the response + response := &appmessage.GetBlocksResponseMessage{ + BlockHashes: hashes.ToStrings(blockHashes), + } + + // Retrieve all block data in case BlockVerboseData was requested + if getBlocksRequest.IncludeBlockVerboseData { + response.BlockVerboseData = make([]*appmessage.BlockVerboseData, len(blockHashes)) + for i, blockHash := range blockHashes { + blockHeader, err := context.Domain.Consensus().GetBlockHeader(blockHash) + if err != nil { + return nil, err + } + blockVerboseData, err := context.BuildBlockVerboseData(blockHeader, nil, + getBlocksRequest.IncludeTransactionVerboseData) + if err != nil { + return nil, err + } + + response.BlockVerboseData[i] = blockVerboseData + } + } return response, nil } diff --git a/domain/consensus/consensus.go b/domain/consensus/consensus.go index 77dc480ec..c61bbb840 100644 --- a/domain/consensus/consensus.go +++ b/domain/consensus/consensus.go @@ -403,3 +403,15 @@ func (s *consensus) GetHeadersSelectedTip() (*externalapi.DomainHash, error) { return s.headersSelectedTipStore.HeadersSelectedTip(s.databaseContext) } + +func (s *consensus) Anticone(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + s.lock.Lock() + defer s.lock.Unlock() + + err := s.validateBlockHashExists(blockHash) + if err != nil { + return nil, err + } + + return s.dagTraversalManager.Anticone(blockHash) +} diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 14688bf13..52c999e4c 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -1,11 +1,12 @@ package consensus import ( - "github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedchainstore" "io/ioutil" "os" "sync" + "github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedchainstore" + "github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager" "github.com/kaspanet/kaspad/domain/consensus/processes/finalitymanager" @@ -141,7 +142,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dagTopologyManager, ghostdagDataStore, reachabilityDataStore, - ghostdagManager) + ghostdagManager, + consensusStateStore) pastMedianTimeManager := pastmediantimemanager.New( dagParams.TimestampDeviationTolerance, dbManager, diff --git a/domain/consensus/model/externalapi/consensus.go b/domain/consensus/model/externalapi/consensus.go index 88927f288..a391a4bb6 100644 --- a/domain/consensus/model/externalapi/consensus.go +++ b/domain/consensus/model/externalapi/consensus.go @@ -29,4 +29,5 @@ type Consensus interface { GetVirtualSelectedParentChainFromBlock(blockHash *DomainHash) (*SelectedChainPath, error) IsInSelectedParentChainOf(blockHashA *DomainHash, blockHashB *DomainHash) (bool, error) GetHeadersSelectedTip() (*DomainHash, error) + Anticone(blockHash *DomainHash) ([]*DomainHash, error) } diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index 1ba115bab..9f06135d8 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -10,7 +10,7 @@ type DAGTraversalManager interface { // SelectedChildIterator should return a BlockIterator that iterates // from lowHash (exclusive) to highHash (inclusive) over highHash's selected parent chain SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error) - AnticoneFromContext(context, lowHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) + Anticone(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) BlueWindow(highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) NewDownHeap() BlockHeap NewUpHeap() BlockHeap diff --git a/domain/consensus/processes/dagtraversalmanager/anticone.go b/domain/consensus/processes/dagtraversalmanager/anticone.go index 372b4fd63..96d0810d5 100644 --- a/domain/consensus/processes/dagtraversalmanager/anticone.go +++ b/domain/consensus/processes/dagtraversalmanager/anticone.go @@ -5,10 +5,12 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/hashset" ) -// AnticoneFromContext returns blocks in (context.Past ⋂ block.Anticone) -func (dtm *dagTraversalManager) AnticoneFromContext(context, block *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { +func (dtm *dagTraversalManager) Anticone(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { anticone := []*externalapi.DomainHash{} - queue := []*externalapi.DomainHash{context} + queue, err := dtm.consensusStateStore.Tips(dtm.databaseContext) + if err != nil { + return nil, err + } visited := hashset.New() for len(queue) > 0 { @@ -21,7 +23,7 @@ func (dtm *dagTraversalManager) AnticoneFromContext(context, block *externalapi. visited.Add(current) - currentIsAncestorOfBlock, err := dtm.dagTopologyManager.IsAncestorOf(current, block) + currentIsAncestorOfBlock, err := dtm.dagTopologyManager.IsAncestorOf(current, blockHash) if err != nil { return nil, err } @@ -30,7 +32,7 @@ func (dtm *dagTraversalManager) AnticoneFromContext(context, block *externalapi. continue } - blockIsAncestorOfCurrent, err := dtm.dagTopologyManager.IsAncestorOf(block, current) + blockIsAncestorOfCurrent, err := dtm.dagTopologyManager.IsAncestorOf(blockHash, current) if err != nil { return nil, err } diff --git a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go index 8402e4b27..d77dfebca 100644 --- a/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go +++ b/domain/consensus/processes/dagtraversalmanager/dagtraversalmanager.go @@ -15,6 +15,7 @@ type dagTraversalManager struct { ghostdagManager model.GHOSTDAGManager ghostdagDataStore model.GHOSTDAGDataStore reachabilityDataStore model.ReachabilityDataStore + consensusStateStore model.ConsensusStateStore } // New instantiates a new DAGTraversalManager @@ -23,13 +24,15 @@ func New( dagTopologyManager model.DAGTopologyManager, ghostdagDataStore model.GHOSTDAGDataStore, reachabilityDataStore model.ReachabilityDataStore, - ghostdagManager model.GHOSTDAGManager) model.DAGTraversalManager { + ghostdagManager model.GHOSTDAGManager, + conssensusStateStore model.ConsensusStateStore) model.DAGTraversalManager { return &dagTraversalManager{ databaseContext: databaseContext, dagTopologyManager: dagTopologyManager, ghostdagDataStore: ghostdagDataStore, reachabilityDataStore: reachabilityDataStore, ghostdagManager: ghostdagManager, + consensusStateStore: conssensusStateStore, } } diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 5e433058d..4449c1aba 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -12,6 +12,26 @@ import ( func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { + // If lowHash is not in the selectedParentChain of highHash - SelectedChildIterator will fail. + // Therefore, we traverse down lowHash's selectedParentChain until we reach a block that is in + // highHash's selectedParentChain. + // We keep originalLowHash to filter out blocks in it's past later down the road + originalLowHash := lowHash + for { + isInSelectedParentChain, err := sm.dagTopologyManager.IsInSelectedParentChainOf(lowHash, highHash) + if err != nil { + return nil, err + } + if isInSelectedParentChain { + break + } + lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) + if err != nil { + return nil, err + } + lowHash = lowBlockGHOSTDAGData.SelectedParent() + } + lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) if err != nil { return nil, err @@ -83,10 +103,17 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma if isCurrentAncestorOfLowHash { continue } - err = hashesUpHeap.Push(current) + // Push current to hashesUpHeap if it's not in the past of originalLowHash + isInPastOfOriginalLowHash, err := sm.dagTopologyManager.IsAncestorOf(current, originalLowHash) if err != nil { return nil, err } + if !isInPastOfOriginalLowHash { + err = hashesUpHeap.Push(current) + if err != nil { + return nil, err + } + } parents, err := sm.dagTopologyManager.Parents(current) if err != nil { return nil, err diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md index e1e0fd91a..0b99f9ba0 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -840,7 +840,6 @@ kaspad's current virtual. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | lowHash | [string](#string) | | | -| includeBlockHexes | [bool](#bool) | | | | includeBlockVerboseData | [bool](#bool) | | | | includeTransactionVerboseData | [bool](#bool) | | | diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index 7b37e4056..a028b571a 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -2707,9 +2707,8 @@ type GetBlocksRequestMessage struct { unknownFields protoimpl.UnknownFields LowHash string `protobuf:"bytes,1,opt,name=lowHash,proto3" json:"lowHash,omitempty"` - IncludeBlockHexes bool `protobuf:"varint,2,opt,name=includeBlockHexes,proto3" json:"includeBlockHexes,omitempty"` - IncludeBlockVerboseData bool `protobuf:"varint,3,opt,name=includeBlockVerboseData,proto3" json:"includeBlockVerboseData,omitempty"` - IncludeTransactionVerboseData bool `protobuf:"varint,4,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` + IncludeBlockVerboseData bool `protobuf:"varint,2,opt,name=includeBlockVerboseData,proto3" json:"includeBlockVerboseData,omitempty"` + IncludeTransactionVerboseData bool `protobuf:"varint,3,opt,name=includeTransactionVerboseData,proto3" json:"includeTransactionVerboseData,omitempty"` } func (x *GetBlocksRequestMessage) Reset() { @@ -2751,13 +2750,6 @@ func (x *GetBlocksRequestMessage) GetLowHash() string { return "" } -func (x *GetBlocksRequestMessage) GetIncludeBlockHexes() bool { - if x != nil { - return x.IncludeBlockHexes - } - return false -} - func (x *GetBlocksRequestMessage) GetIncludeBlockVerboseData() bool { if x != nil { return x.IncludeBlockVerboseData @@ -2778,8 +2770,7 @@ type GetBlocksResponseMessage struct { unknownFields protoimpl.UnknownFields BlockHashes []string `protobuf:"bytes,1,rep,name=blockHashes,proto3" json:"blockHashes,omitempty"` - BlockHexes []string `protobuf:"bytes,2,rep,name=blockHexes,proto3" json:"blockHexes,omitempty"` - BlockVerboseData []*BlockVerboseData `protobuf:"bytes,3,rep,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` + BlockVerboseData []*BlockVerboseData `protobuf:"bytes,2,rep,name=blockVerboseData,proto3" json:"blockVerboseData,omitempty"` Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` } @@ -2822,13 +2813,6 @@ func (x *GetBlocksResponseMessage) GetBlockHashes() []string { return nil } -func (x *GetBlocksResponseMessage) GetBlockHexes() []string { - if x != nil { - return x.BlockHexes - } - return nil -} - func (x *GetBlocksResponseMessage) GetBlockVerboseData() []*BlockVerboseData { if x != nil { return x.BlockVerboseData @@ -5180,271 +5164,266 @@ var file_rpc_proto_rawDesc = []byte{ 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0xe1, 0x01, 0x0a, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xb3, 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, + 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, 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, 0xb1, 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, 0x47, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, + 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 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, 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, 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, 0x78, 0x6f, - 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x61, - 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, - 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x22, - 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, - 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, - 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xab, - 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, - 0x07, 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, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, 0x01, 0x0a, - 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, - 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, - 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, - 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, 0x63, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, - 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, 0x01, 0x0a, - 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, - 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, - 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, - 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, - 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, 0x47, 0x65, - 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, 0x74, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, 0x30, 0x47, - 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 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, + 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, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 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, 0x22, 0x40, 0x0a, 0x20, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x21, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x95, 0x01, 0x0a, 0x1f, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, + 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x64, 0x22, 0x9c, 0x01, 0x0a, 0x15, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, + 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x09, 0x75, 0x74, 0x78, + 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, + 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, + 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, + 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, + 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, + 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, + 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, + 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, + 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, + 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, + 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, + 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, + 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, + 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, - 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, + 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, 0x12, 0x42, 0x61, - 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, 0x25, 0x0a, 0x13, - 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 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, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x32, - 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, - 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, 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, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, + 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, 0x12, + 0x42, 0x61, 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, 0x25, + 0x0a, 0x13, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 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, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x70, 0x32, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, 0x70, + 0x49, 0x64, 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, 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 ( diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index 8991b90c4..8e074ddeb 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -341,15 +341,13 @@ message GetVirtualSelectedParentChainFromBlockResponseMessage{ // kaspad's current virtual. message GetBlocksRequestMessage{ string lowHash = 1; - bool includeBlockHexes = 2; - bool includeBlockVerboseData = 3; - bool includeTransactionVerboseData = 4; + bool includeBlockVerboseData = 2; + bool includeTransactionVerboseData = 3; } message GetBlocksResponseMessage{ repeated string blockHashes = 1; - repeated string blockHexes = 2; - repeated BlockVerboseData blockVerboseData = 3; + repeated BlockVerboseData blockVerboseData = 2; RPCError error = 1000; } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_blocks.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_blocks.go index 79bff1d06..ba13d6226 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_blocks.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_get_blocks.go @@ -4,17 +4,17 @@ import "github.com/kaspanet/kaspad/app/appmessage" func (x *KaspadMessage_GetBlocksRequest) toAppMessage() (appmessage.Message, error) { return &appmessage.GetBlocksRequestMessage{ - LowHash: x.GetBlocksRequest.LowHash, - IncludeBlockHexes: x.GetBlocksRequest.IncludeBlockHexes, - IncludeBlockVerboseData: x.GetBlocksRequest.IncludeBlockVerboseData, + LowHash: x.GetBlocksRequest.LowHash, + IncludeBlockVerboseData: x.GetBlocksRequest.IncludeBlockVerboseData, + IncludeTransactionVerboseData: x.GetBlocksRequest.IncludeTransactionVerboseData, }, nil } func (x *KaspadMessage_GetBlocksRequest) fromAppMessage(message *appmessage.GetBlocksRequestMessage) error { x.GetBlocksRequest = &GetBlocksRequestMessage{ - LowHash: message.LowHash, - IncludeBlockHexes: message.IncludeBlockHexes, - IncludeBlockVerboseData: message.IncludeBlockVerboseData, + LowHash: message.LowHash, + IncludeBlockVerboseData: message.IncludeBlockVerboseData, + IncludeTransactionVerboseData: message.IncludeTransactionVerboseData, } return nil } @@ -24,20 +24,22 @@ func (x *KaspadMessage_GetBlocksResponse) toAppMessage() (appmessage.Message, er if x.GetBlocksResponse.Error != nil { err = &appmessage.RPCError{Message: x.GetBlocksResponse.Error.Message} } - blockVerboseData := make([]*appmessage.BlockVerboseData, len(x.GetBlocksResponse.BlockVerboseData)) - for i, blockVerboseDatum := range x.GetBlocksResponse.BlockVerboseData { - appBlockVerboseDatum, err := blockVerboseDatum.toAppMessage() - if err != nil { - return nil, err - } - blockVerboseData[i] = appBlockVerboseDatum + appMessage := &appmessage.GetBlocksResponseMessage{ + BlockHashes: x.GetBlocksResponse.BlockHashes, + Error: err, } - return &appmessage.GetBlocksResponseMessage{ - BlockHashes: x.GetBlocksResponse.BlockHashes, - BlockHexes: x.GetBlocksResponse.BlockHexes, - BlockVerboseData: blockVerboseData, - Error: err, - }, nil + if x.GetBlocksResponse.BlockVerboseData != nil { + appMessage.BlockVerboseData = make([]*appmessage.BlockVerboseData, len(x.GetBlocksResponse.BlockVerboseData)) + for i, blockVerboseDatum := range x.GetBlocksResponse.BlockVerboseData { + appBlockVerboseDatum, err := blockVerboseDatum.toAppMessage() + if err != nil { + return nil, err + } + appMessage.BlockVerboseData[i] = appBlockVerboseDatum + } + } + + return appMessage, nil } func (x *KaspadMessage_GetBlocksResponse) fromAppMessage(message *appmessage.GetBlocksResponseMessage) error { @@ -45,20 +47,20 @@ func (x *KaspadMessage_GetBlocksResponse) fromAppMessage(message *appmessage.Get if message.Error != nil { err = &RPCError{Message: message.Error.Message} } - blockVerboseData := make([]*BlockVerboseData, len(message.BlockVerboseData)) - for i, blockVerboseDatum := range message.BlockVerboseData { - protoBlockVerboseDatum := &BlockVerboseData{} - err := protoBlockVerboseDatum.fromAppMessage(blockVerboseDatum) - if err != nil { - return err - } - blockVerboseData[i] = protoBlockVerboseDatum - } x.GetBlocksResponse = &GetBlocksResponseMessage{ - BlockHashes: message.BlockHashes, - BlockHexes: message.BlockHexes, - BlockVerboseData: blockVerboseData, - Error: err, + BlockHashes: message.BlockHashes, + Error: err, + } + if message.BlockVerboseData != nil { + x.GetBlocksResponse.BlockVerboseData = make([]*BlockVerboseData, len(message.BlockVerboseData)) + for i, blockVerboseDatum := range message.BlockVerboseData { + protoBlockVerboseDatum := &BlockVerboseData{} + err := protoBlockVerboseDatum.fromAppMessage(blockVerboseDatum) + if err != nil { + return err + } + x.GetBlocksResponse.BlockVerboseData[i] = protoBlockVerboseDatum + } } return nil } diff --git a/infrastructure/network/rpcclient/rpc_get_blocks.go b/infrastructure/network/rpcclient/rpc_get_blocks.go index a5b853019..db3c87a0b 100644 --- a/infrastructure/network/rpcclient/rpc_get_blocks.go +++ b/infrastructure/network/rpcclient/rpc_get_blocks.go @@ -3,10 +3,11 @@ package rpcclient import "github.com/kaspanet/kaspad/app/appmessage" // GetBlocks sends an RPC request respective to the function's name and returns the RPC server's response -func (c *RPCClient) GetBlocks(lowHash string, includeBlockHexes bool, - includeBlockVerboseData bool) (*appmessage.GetBlocksResponseMessage, error) { +func (c *RPCClient) GetBlocks(lowHash string, includeBlockVerboseData bool, + includeTransactionVerboseData bool) (*appmessage.GetBlocksResponseMessage, error) { - err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetBlocksRequestMessage(lowHash, includeBlockHexes, includeBlockVerboseData)) + err := c.rpcRouter.outgoingRoute().Enqueue( + appmessage.NewGetBlocksRequestMessage(lowHash, includeBlockVerboseData, includeTransactionVerboseData)) if err != nil { return nil, err } From 7c3beb526ea4b96d28507f8c256d85eb6e0381de Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 10 Feb 2021 18:35:13 +0200 Subject: [PATCH 328/351] Limit stdout log level to info (#1518) * Rename debuglevel to loglevel * Limit stdout level to info by default Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Co-authored-by: Svarog --- infrastructure/config/config.go | 8 +++---- infrastructure/config/sample-kaspad.conf | 4 ++-- infrastructure/config/sample_config.go | 4 ++-- infrastructure/logger/logger.go | 14 ++++++------ infrastructure/logger/logs.go | 27 ++++++++++++++---------- 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/infrastructure/config/config.go b/infrastructure/config/config.go index 09dc35925..268d0937b 100644 --- a/infrastructure/config/config.go +++ b/infrastructure/config/config.go @@ -102,7 +102,7 @@ type Flags struct { ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"` DbType string `long:"dbtype" description:"Database backend to use for the Block DAG"` Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` - DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify =,=,... to set the log level for individual subsystems -- Use show to list available subsystems"` + LogLevel string `short:"d" long:"loglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify =,=,... to set the log level for individual subsystems -- Use show to list available subsystems"` Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"` MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in KAS/kB to be considered a non-zero fee."` MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"` @@ -166,7 +166,7 @@ func newConfigParser(cfgFlags *Flags, options flags.Options) *flags.Parser { func defaultFlags() *Flags { return &Flags{ ConfigFile: defaultConfigFile, - DebugLevel: defaultLogLevel, + LogLevel: defaultLogLevel, TargetOutboundPeers: defaultTargetOutboundPeers, MaxInboundPeers: defaultMaxInboundPeers, BanDuration: defaultBanDuration, @@ -326,7 +326,7 @@ func LoadConfig() (*Config, error) { cfg.LogDir = filepath.Join(cfg.LogDir, cfg.NetParams().Name) // Special show command to list supported subsystems and exit. - if cfg.DebugLevel == "show" { + if cfg.LogLevel == "show" { fmt.Println("Supported subsystems", logger.SupportedSubsystems()) os.Exit(0) } @@ -336,7 +336,7 @@ func LoadConfig() (*Config, error) { logger.InitLog(filepath.Join(cfg.LogDir, defaultLogFilename), filepath.Join(cfg.LogDir, defaultErrLogFilename)) // Parse, validate, and set debug log level(s). - if err := logger.ParseAndSetDebugLevels(cfg.DebugLevel); err != nil { + if err := logger.ParseAndSetLogLevels(cfg.LogLevel); err != nil { err := errors.Errorf("%s: %s", funcName, err.Error()) fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, usageMessage) diff --git a/infrastructure/config/sample-kaspad.conf b/infrastructure/config/sample-kaspad.conf index b0116484f..589da2039 100644 --- a/infrastructure/config/sample-kaspad.conf +++ b/infrastructure/config/sample-kaspad.conf @@ -223,9 +223,9 @@ ; Debug logging level. ; Valid levels are {trace, debug, info, warn, error, critical} ; You may also specify =,=,... to set -; log level for individual subsystems. Use kaspad --debuglevel=show to list +; log level for individual subsystems. Use kaspad --loglevel=show to list ; available subsystems. -; debuglevel=info +; loglevel=info ; The port used to listen for HTTP profile requests. The profile server will ; be disabled if this option is not specified. The profile information can be diff --git a/infrastructure/config/sample_config.go b/infrastructure/config/sample_config.go index a3c0b0ff6..19dfe17ed 100644 --- a/infrastructure/config/sample_config.go +++ b/infrastructure/config/sample_config.go @@ -227,9 +227,9 @@ var sampleConfig = `[Application Options] ; Debug logging level. ; Valid levels are {trace, debug, info, warn, error, critical} ; You may also specify =,=,... to set -; log level for individual subsystems. Use kaspad --debuglevel=show to list +; log level for individual subsystems. Use kaspad --loglevel=show to list ; available subsystems. -; debuglevel=info +; loglevel=info ; The port used to listen for HTTP profile requests. The profile server will ; be disabled if this option is not specified. The profile information can be diff --git a/infrastructure/logger/logger.go b/infrastructure/logger/logger.go index fc5c4a8ed..dc17a76ad 100644 --- a/infrastructure/logger/logger.go +++ b/infrastructure/logger/logger.go @@ -236,28 +236,28 @@ func Get(tag string) (logger *Logger, ok bool) { return } -// ParseAndSetDebugLevels attempts to parse the specified debug level and set +// ParseAndSetLogLevels attempts to parse the specified debug level and set // the levels accordingly. An appropriate error is returned if anything is // invalid. -func ParseAndSetDebugLevels(debugLevel string) error { +func ParseAndSetLogLevels(logLevel string) error { // When the specified string doesn't have any delimters, treat it as // the log level for all subsystems. - if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") { + if !strings.Contains(logLevel, ",") && !strings.Contains(logLevel, "=") { // Validate debug log level. - if !validLogLevel(debugLevel) { + if !validLogLevel(logLevel) { str := "The specified debug level [%s] is invalid" - return errors.Errorf(str, debugLevel) + return errors.Errorf(str, logLevel) } // Change the logging level for all subsystems. - SetLogLevels(debugLevel) + SetLogLevels(logLevel) return nil } // Split the specified string into subsystem/level pairs while detecting // issues and update the log levels accordingly. - for _, logLevelPair := range strings.Split(debugLevel, ",") { + for _, logLevelPair := range strings.Split(logLevel, ",") { if !strings.Contains(logLevelPair, "=") { str := "The specified debug level contains an invalid " + "subsystem/level pair [%s]" diff --git a/infrastructure/logger/logs.go b/infrastructure/logger/logs.go index a8bf4801d..ca6409522 100644 --- a/infrastructure/logger/logs.go +++ b/infrastructure/logger/logs.go @@ -129,7 +129,7 @@ func (l Level) String() string { // NewBackend creates a new logger backend. func NewBackend(opts ...BackendOption) *Backend { - b := &Backend{flag: defaultFlags, toStdout: true} + b := &Backend{flag: defaultFlags, stdoutLevel: LevelInfo} for _, o := range opts { o(b) } @@ -145,10 +145,10 @@ type backendLogRotator struct { // the backend's Writer. Backend provides atomic writes to the Writer from all // subsystems. type Backend struct { - rotators []*backendLogRotator - mu sync.Mutex // ensures atomic writes - flag uint32 - toStdout bool + rotators []*backendLogRotator + mu sync.Mutex // ensures atomic writes + flag uint32 + stdoutLevel Level } // BackendOption is a function used to modify the behavior of a Backend. @@ -352,7 +352,7 @@ func (b *Backend) printf(lvl Level, tag string, format string, args ...interface func (b *Backend) write(lvl Level, bytesToWrite []byte) { b.mu.Lock() defer b.mu.Unlock() - if b.toStdout { + if lvl >= b.StdoutLevel() { os.Stdout.Write(bytesToWrite) } @@ -363,6 +363,16 @@ func (b *Backend) write(lvl Level, bytesToWrite []byte) { } } +// StdoutLevel returns the current stdout logging level +func (b *Backend) StdoutLevel() Level { + return Level(atomic.LoadUint32((*uint32)(&b.stdoutLevel))) +} + +// SetStdoutLevel changes the logging level to the passed level. +func (b *Backend) SetStdoutLevel(level Level) { + atomic.StoreUint32((*uint32)(&b.stdoutLevel), uint32(level)) +} + // Close finalizes all log rotators for this backend func (b *Backend) Close() { for _, r := range b.rotators { @@ -370,11 +380,6 @@ func (b *Backend) Close() { } } -// WriteToStdout sets if the backend will print to stdout or not (default: true) -func (b *Backend) WriteToStdout(stdout bool) { - b.toStdout = stdout -} - // Logger returns a new logger for a particular subsystem that writes to the // Backend b. A tag describes the subsystem and is included in all log // messages. The logger uses the info verbosity level by default. From fea83e5c6cdf867f914170dec26126603c86d345 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 11 Feb 2021 15:00:21 +0200 Subject: [PATCH 329/351] Change Testnet name to kaspad-testnet-2 (#1521) * Change Testnet name to kaspad-testnet-2 * Fix tests that hardcoded network names --- .../processes/dagtraversalmanager/window_test.go | 8 ++++---- .../difficultymanager/difficultymanager_test.go | 7 ++++--- .../processes/pruningmanager/pruning_test.go | 16 ++++++++-------- domain/consensus/pruning_test.go | 11 ++++++----- domain/dagconfig/params.go | 2 +- util/difficulty/difficulty_test.go | 15 ++++++++------- 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 188129bb6..399e434a7 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -19,7 +19,7 @@ func TestBlueBlockWindow(t *testing.T) { id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash expectedWindowWithGenesisPadding []string }{ - "kaspa-mainnet": { + dagconfig.MainnetParams.Name: { { parents: []string{"A"}, id: "B", @@ -91,7 +91,7 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"}, }, }, - "kaspa-testnet": { + dagconfig.TestnetParams.Name: { { parents: []string{"A"}, id: "B", @@ -163,7 +163,7 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"}, }, }, - "kaspa-devnet": { + dagconfig.DevnetParams.Name: { { parents: []string{"A"}, id: "B", @@ -235,7 +235,7 @@ func TestBlueBlockWindow(t *testing.T) { expectedWindowWithGenesisPadding: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"}, }, }, - "kaspa-simnet": { + dagconfig.SimnetParams.Name: { { parents: []string{"A"}, id: "B", diff --git a/domain/consensus/processes/difficultymanager/difficultymanager_test.go b/domain/consensus/processes/difficultymanager/difficultymanager_test.go index 1b921f59c..4bd2a4be9 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager_test.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager_test.go @@ -1,10 +1,11 @@ package difficultymanager_test import ( - "github.com/kaspanet/kaspad/util/difficulty" "testing" "time" + "github.com/kaspanet/kaspad/util/difficulty" + "github.com/kaspanet/kaspad/util/mstime" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" @@ -132,9 +133,9 @@ func TestDifficulty(t *testing.T) { var expectedBits uint32 switch params.Name { - case "kaspa-testnet", "kaspa-devnet": + case dagconfig.TestnetParams.Name, dagconfig.DevnetParams.Name: expectedBits = uint32(0x1e7f83df) - case "kaspa-mainnet": + case dagconfig.MainnetParams.Name: expectedBits = uint32(0x207f83df) } diff --git a/domain/consensus/processes/pruningmanager/pruning_test.go b/domain/consensus/processes/pruningmanager/pruning_test.go index 94071618a..d0057f359 100644 --- a/domain/consensus/processes/pruningmanager/pruning_test.go +++ b/domain/consensus/processes/pruningmanager/pruning_test.go @@ -27,16 +27,16 @@ type testJSON struct { func TestPruning(t *testing.T) { expectedPruningPointByNet := map[string]map[string]string{ "chain-for-test-pruning.json": { - "kaspa-mainnet": "1582", - "kaspa-simnet": "1582", - "kaspa-devnet": "1582", - "kaspa-testnet": "1582", + dagconfig.MainnetParams.Name: "1582", + dagconfig.TestnetParams.Name: "1582", + dagconfig.DevnetParams.Name: "1582", + dagconfig.SimnetParams.Name: "1582", }, "dag-for-test-pruning.json": { - "kaspa-mainnet": "503", - "kaspa-simnet": "502", - "kaspa-devnet": "503", - "kaspa-testnet": "503", + dagconfig.MainnetParams.Name: "503", + dagconfig.TestnetParams.Name: "503", + dagconfig.DevnetParams.Name: "503", + dagconfig.SimnetParams.Name: "502", }, } diff --git a/domain/consensus/pruning_test.go b/domain/consensus/pruning_test.go index 8ca354d82..bd574ee1c 100644 --- a/domain/consensus/pruning_test.go +++ b/domain/consensus/pruning_test.go @@ -1,17 +1,18 @@ package consensus import ( + "testing" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" - "testing" ) func TestPruningDepth(t *testing.T) { expectedResult := map[string]uint64{ - "kaspa-mainnet": 244838, - "kaspa-testnet": 244838, - "kaspa-devnet": 244838, - "kaspa-simnet": 192038, + dagconfig.MainnetParams.Name: 244838, + dagconfig.TestnetParams.Name: 244838, + dagconfig.DevnetParams.Name: 244838, + dagconfig.SimnetParams.Name: 192038, } testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { expected, found := expectedResult[params.Name] diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 6c794b21f..20bdcbe1e 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -256,7 +256,7 @@ var MainnetParams = Params{ // TestnetParams defines the network parameters for the test Kaspa network. var TestnetParams = Params{ K: defaultGHOSTDAGK, - Name: "kaspa-testnet", + Name: "kaspa-testnet-2", Net: appmessage.Testnet, RPCPort: "16210", DefaultPort: "16211", diff --git a/util/difficulty/difficulty_test.go b/util/difficulty/difficulty_test.go index 2abd922f0..ed563b80e 100644 --- a/util/difficulty/difficulty_test.go +++ b/util/difficulty/difficulty_test.go @@ -2,20 +2,21 @@ package difficulty_test import ( "fmt" - "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" - "github.com/kaspanet/kaspad/domain/dagconfig" - "github.com/kaspanet/kaspad/util/difficulty" "math" "math/big" "testing" + + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/util/difficulty" ) func TestGetHashrateString(t *testing.T) { var results = map[string]string{ - "kaspa-mainnet": "2 H/s", - "kaspa-testnet": "131.07 KH/s", - "kaspa-devnet": "131.07 KH/s", - "kaspa-simnet": "2.00 KH/s", + dagconfig.MainnetParams.Name: "2 H/s", + dagconfig.TestnetParams.Name: "131.07 KH/s", + dagconfig.DevnetParams.Name: "131.07 KH/s", + dagconfig.SimnetParams.Name: "2.00 KH/s", } testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) { targetGenesis := difficulty.CompactToBig(params.GenesisBlock.Header.Bits()) From 1ed6c4c086b55dea834ee2f35441b9143da05283 Mon Sep 17 00:00:00 2001 From: hashdag <31767204+hashdag@users.noreply.github.com> Date: Thu, 4 Feb 2021 14:29:30 +0200 Subject: [PATCH 330/351] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36beb180a..be2213baf 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ is used for this project. ## Documentation -The documentation is a work-in-progress. +The [documentation](https://github.com/kaspanet/docs) is a work-in-progress ## License From 0a579e7f78b5d34039b2f56ec7f25972944475f8 Mon Sep 17 00:00:00 2001 From: Svarog Date: Thu, 11 Feb 2021 16:59:31 +0200 Subject: [PATCH 331/351] DownloadHeaders: Instead of using doneChan - close blockHeadersMessageChan. (#1523) --- app/protocol/flows/blockrelay/ibd.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index f8a4fda65..e4851aed2 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -221,7 +221,6 @@ func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externa // headers blockHeadersMessageChan := make(chan *appmessage.BlockHeadersMessage, 2) errChan := make(chan error) - doneChan := make(chan interface{}) spawn("handleRelayInvsFlow-downloadHeaders", func() { for { blockHeadersMessage, doneIBD, err := flow.receiveHeaders() @@ -230,7 +229,7 @@ func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externa return } if doneIBD { - doneChan <- struct{}{} + close(blockHeadersMessageChan) return } @@ -246,7 +245,10 @@ func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externa for { select { - case blockHeadersMessage := <-blockHeadersMessageChan: + case blockHeadersMessage, ok := <-blockHeadersMessageChan: + if !ok { + return nil + } for _, header := range blockHeadersMessage.BlockHeaders { err = flow.processHeader(header) if err != nil { @@ -255,8 +257,6 @@ func (flow *handleRelayInvsFlow) downloadHeaders(highestSharedBlockHash *externa } case err := <-errChan: return err - case <-doneChan: - return nil } } } From 0e2061d838f3dc84212feb7f464d63c5dce2e776 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 11 Feb 2021 18:13:46 +0200 Subject: [PATCH 332/351] Make RPC command GetBlocks prepend lowHash to return value and fix error when lowHash=highHash (#1520) * Don't error out if antiPastHashesBetween have 2 blocks with the same blue score * Prepend lowHash to RPC GetBlocks request * Add a test for GetHashesBetween * Add a test for GetBlocks RPC call * Update antipast.go Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- app/rpc/rpchandlers/get_blocks.go | 3 + app/rpc/rpchandlers/get_blocks_test.go | 130 ++++++++++++++++++ .../processes/syncmanager/antipast.go | 4 +- .../processes/syncmanager/syncmanager_test.go | 64 +++++++++ 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 app/rpc/rpchandlers/get_blocks_test.go create mode 100644 domain/consensus/processes/syncmanager/syncmanager_test.go diff --git a/app/rpc/rpchandlers/get_blocks.go b/app/rpc/rpchandlers/get_blocks.go index d775c693f..49c93ee84 100644 --- a/app/rpc/rpchandlers/get_blocks.go +++ b/app/rpc/rpchandlers/get_blocks.go @@ -50,6 +50,9 @@ func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appm return nil, err } + // prepend low hash to make it inclusive + blockHashes = append([]*externalapi.DomainHash{lowHash}, blockHashes...) + // If there are no maxBlocksInGetBlocksResponse between lowHash and virtualSelectedParent - // add virtualSelectedParent's anticone if len(blockHashes) < maxBlocksInGetBlocksResponse { diff --git a/app/rpc/rpchandlers/get_blocks_test.go b/app/rpc/rpchandlers/get_blocks_test.go new file mode 100644 index 000000000..b01320b22 --- /dev/null +++ b/app/rpc/rpchandlers/get_blocks_test.go @@ -0,0 +1,130 @@ +package rpchandlers_test + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/app/rpc/rpchandlers" + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/domain/miningmanager" + "github.com/kaspanet/kaspad/infrastructure/config" + "reflect" + "sort" + "testing" +) + +type fakeDomain struct { + testapi.TestConsensus +} + +func (d fakeDomain) Consensus() externalapi.Consensus { return d } +func (d fakeDomain) MiningManager() miningmanager.MiningManager { return nil } + +func TestHandleGetBlocks(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestHandleGetBlocks") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + fakeContext := rpccontext.Context{ + Config: &config.Config{Flags: &config.Flags{NetworkFlags: config.NetworkFlags{ActiveNetParams: params}}}, + Domain: fakeDomain{tc}, + } + + getBlocks := func(lowHash *externalapi.DomainHash) *appmessage.GetBlocksResponseMessage { + request := appmessage.GetBlocksRequestMessage{} + if lowHash != nil { + request.LowHash = lowHash.String() + } + response, err := rpchandlers.HandleGetBlocks(&fakeContext, nil, &request) + if err != nil { + t.Fatalf("Expected empty request to not fail, instead: '%v'", err) + } + return response.(*appmessage.GetBlocksResponseMessage) + } + + filterAntiPast := func(povBlock *externalapi.DomainHash, slice []*externalapi.DomainHash) []*externalapi.DomainHash { + antipast := make([]*externalapi.DomainHash, 0, len(slice)) + + for _, blockHash := range slice { + isInPastOfPovBlock, err := tc.DAGTopologyManager().IsAncestorOf(blockHash, povBlock) + if err != nil { + t.Fatalf("Failed doing reachability check: '%v'", err) + } + if !isInPastOfPovBlock { + antipast = append(antipast, blockHash) + } + } + return antipast + } + + upBfsOrder := make([]*externalapi.DomainHash, 0, 30) + selectedParent := params.GenesisHash + upBfsOrder = append(upBfsOrder, selectedParent) + for i := 0; i < 10; i++ { + parents := make([]*externalapi.DomainHash, 0, 3) + for j := 0; j < 4; j++ { + blockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{selectedParent}, nil, nil) + if err != nil { + t.Fatalf("Failed adding block: %v", err) + } + parents = append(parents, blockHash) + upBfsOrder = append(upBfsOrder, blockHash) + } + selectedParent, _, err = tc.AddBlock(parents, nil, nil) + if err != nil { + t.Fatalf("Failed adding block: %v", err) + } + upBfsOrder = append(upBfsOrder, selectedParent) + } + + virtualSelectedParent, err := tc.GetVirtualSelectedParent() + if err != nil { + t.Fatalf("Failed getting SelectedParent: %v", err) + } + if !virtualSelectedParent.Equal(upBfsOrder[len(upBfsOrder)-1]) { + t.Fatalf("Expected %s to be selectedParent, instead found: %s", upBfsOrder[len(upBfsOrder)-1], virtualSelectedParent) + } + + requestSelectedParent := getBlocks(virtualSelectedParent) + if !reflect.DeepEqual(requestSelectedParent.BlockHashes, hashes.ToStrings([]*externalapi.DomainHash{virtualSelectedParent})) { + t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", requestSelectedParent.BlockHashes, virtualSelectedParent) + } + + for i, blockHash := range upBfsOrder { + expectedBlocks := filterAntiPast(blockHash, upBfsOrder) + // sort the slice in the order GetBlocks is returning them + sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(expectedBlocks, tc, t))) + expectedBlocks = append([]*externalapi.DomainHash{blockHash}, expectedBlocks...) + + blocks := getBlocks(blockHash) + if !reflect.DeepEqual(blocks.BlockHashes, hashes.ToStrings(expectedBlocks)) { + t.Fatalf("TestSyncManager_GetHashesBetween %d expected %s\n == \n%s", i, blocks.BlockHashes, hashes.ToStrings(expectedBlocks)) + } + } + + // Make explitly sure that if lowHash==highHash we get a slice with a single hash. + blocks := getBlocks(virtualSelectedParent) + if !reflect.DeepEqual(blocks.BlockHashes, []string{virtualSelectedParent.String()}) { + t.Fatalf("TestSyncManager_GetHashesBetween expected blocks to contain just '%s', instead got: \n%s", virtualSelectedParent, blocks.BlockHashes) + } + + sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(upBfsOrder, tc, t))) + requestAllViaNil := getBlocks(nil) + if !reflect.DeepEqual(requestAllViaNil.BlockHashes, hashes.ToStrings(upBfsOrder)) { + t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", requestAllViaNil.BlockHashes, upBfsOrder) + } + + requestAllExplictly := getBlocks(params.GenesisHash) + if !reflect.DeepEqual(requestAllExplictly.BlockHashes, hashes.ToStrings(upBfsOrder)) { + t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", requestAllExplictly.BlockHashes, upBfsOrder) + } + }) +} diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index 4449c1aba..e6cce28e3 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -40,8 +40,8 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma if err != nil { return nil, err } - if lowBlockGHOSTDAGData.BlueScore() >= highBlockGHOSTDAGData.BlueScore() { - return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)", + if lowBlockGHOSTDAGData.BlueScore() > highBlockGHOSTDAGData.BlueScore() { + return nil, errors.Errorf("low hash blueScore > high hash blueScore (%d > %d)", lowBlockGHOSTDAGData.BlueScore(), highBlockGHOSTDAGData.BlueScore()) } diff --git a/domain/consensus/processes/syncmanager/syncmanager_test.go b/domain/consensus/processes/syncmanager/syncmanager_test.go new file mode 100644 index 000000000..d01adaa1b --- /dev/null +++ b/domain/consensus/processes/syncmanager/syncmanager_test.go @@ -0,0 +1,64 @@ +package syncmanager_test + +import ( + "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" + "math" + "reflect" + "sort" + "testing" +) + +func TestSyncManager_GetHashesBetween(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestSyncManager_GetHashesBetween") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + upBfsOrder := make([]*externalapi.DomainHash, 0, 30) + selectedParent := params.GenesisHash + upBfsOrder = append(upBfsOrder, selectedParent) + for i := 0; i < 10; i++ { + parents := make([]*externalapi.DomainHash, 0, 3) + for j := 0; j < 4; j++ { + blockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{selectedParent}, nil, nil) + if err != nil { + t.Fatalf("Failed adding block: %v", err) + } + parents = append(parents, blockHash) + upBfsOrder = append(upBfsOrder, blockHash) + } + selectedParent, _, err = tc.AddBlock(parents, nil, nil) + if err != nil { + t.Fatalf("Failed adding block: %v", err) + } + upBfsOrder = append(upBfsOrder, selectedParent) + } + + for i, blockHash := range upBfsOrder { + empty, err := tc.SyncManager().GetHashesBetween(blockHash, blockHash, math.MaxUint64) + if err != nil { + t.Fatalf("TestSyncManager_GetHashesBetween failed returning 0 hashes on the %d'th block: %v", i, err) + } + if len(empty) != 0 { + t.Fatalf("Expected lowHash=highHash to return empty on the %d'th block, instead found: %v", i, empty) + } + } + + allHashes, err := tc.SyncManager().GetHashesBetween(upBfsOrder[0], upBfsOrder[len(upBfsOrder)-1], math.MaxUint64) + if err != nil { + t.Fatalf("TestSyncManager_GetHashesBetween failed returning allHashes: %v", err) + } + + sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(upBfsOrder, tc, t))) + upBfsOrderExcludingGenesis := upBfsOrder[1:] + if !reflect.DeepEqual(allHashes, upBfsOrderExcludingGenesis) { + t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", allHashes, upBfsOrder) + } + }) +} From 7b4b5668e2585e157afcef6069b44f6c1ad2c8f9 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 14 Feb 2021 12:58:29 +0200 Subject: [PATCH 333/351] Enhance UTXOsChanged notifications (#1522) * In PropagateUTXOsChangedNotifications, add the given addresses to the address list instead of replacing them. * Add StopNotifyingUtxosChangedRequestMessage to rpc.proto. * Implement StopNotifyingUTXOsChanged. * Optimize convertUTXOChangesToUTXOsChangedNotification. --- app/appmessage/message.go | 4 + .../rpc_stop_notifying_utxos_changed.go | 37 ++ app/rpc/rpc.go | 1 + app/rpc/rpccontext/notificationmanager.go | 72 +- app/rpc/rpccontext/utxos_by_addresses.go | 43 ++ app/rpc/rpchandlers/notify_utxos_changed.go | 28 +- .../stop_notifying_utxos_changed.go | 33 + .../grpcserver/protowire/messages.pb.go | 293 +++++---- .../grpcserver/protowire/messages.proto | 2 + .../server/grpcserver/protowire/rpc.md | 65 +- .../server/grpcserver/protowire/rpc.pb.go | 617 +++++++++++------- .../server/grpcserver/protowire/rpc.proto | 14 + .../rpc_stop_notifying_utxos_changed.go | 39 ++ .../server/grpcserver/protowire/wire.go | 14 + 14 files changed, 835 insertions(+), 427 deletions(-) create mode 100644 app/appmessage/rpc_stop_notifying_utxos_changed.go create mode 100644 app/rpc/rpchandlers/stop_notifying_utxos_changed.go create mode 100644 infrastructure/network/netadapter/server/grpcserver/protowire/rpc_stop_notifying_utxos_changed.go diff --git a/app/appmessage/message.go b/app/appmessage/message.go index bf8bd9e03..f3cd332d6 100644 --- a/app/appmessage/message.go +++ b/app/appmessage/message.go @@ -117,6 +117,8 @@ const ( CmdNotifyUTXOsChangedRequestMessage CmdNotifyUTXOsChangedResponseMessage CmdUTXOsChangedNotificationMessage + CmdStopNotifyingUTXOsChangedRequestMessage + CmdStopNotifyingUTXOsChangedResponseMessage CmdGetUTXOsByAddressesRequestMessage CmdGetUTXOsByAddressesResponseMessage CmdGetVirtualSelectedParentBlueScoreRequestMessage @@ -221,6 +223,8 @@ var RPCMessageCommandToString = map[MessageCommand]string{ CmdNotifyUTXOsChangedRequestMessage: "NotifyUTXOsChangedRequest", CmdNotifyUTXOsChangedResponseMessage: "NotifyUTXOsChangedResponse", CmdUTXOsChangedNotificationMessage: "UTXOsChangedNotification", + CmdStopNotifyingUTXOsChangedRequestMessage: "StopNotifyingUTXOsChangedRequest", + CmdStopNotifyingUTXOsChangedResponseMessage: "StopNotifyingUTXOsChangedResponse", CmdGetUTXOsByAddressesRequestMessage: "GetUTXOsByAddressesRequest", CmdGetUTXOsByAddressesResponseMessage: "GetUTXOsByAddressesResponse", CmdGetVirtualSelectedParentBlueScoreRequestMessage: "GetVirtualSelectedParentBlueScoreRequest", diff --git a/app/appmessage/rpc_stop_notifying_utxos_changed.go b/app/appmessage/rpc_stop_notifying_utxos_changed.go new file mode 100644 index 000000000..16e0e34e8 --- /dev/null +++ b/app/appmessage/rpc_stop_notifying_utxos_changed.go @@ -0,0 +1,37 @@ +package appmessage + +// StopNotifyingUTXOsChangedRequestMessage is an appmessage corresponding to +// its respective RPC message +type StopNotifyingUTXOsChangedRequestMessage struct { + baseMessage + Addresses []string +} + +// Command returns the protocol command string for the message +func (msg *StopNotifyingUTXOsChangedRequestMessage) Command() MessageCommand { + return CmdStopNotifyingUTXOsChangedRequestMessage +} + +// NewStopNotifyingUTXOsChangedRequestMessage returns a instance of the message +func NewStopNotifyingUTXOsChangedRequestMessage(addresses []string) *StopNotifyingUTXOsChangedRequestMessage { + return &StopNotifyingUTXOsChangedRequestMessage{ + Addresses: addresses, + } +} + +// StopNotifyingUTXOsChangedResponseMessage is an appmessage corresponding to +// its respective RPC message +type StopNotifyingUTXOsChangedResponseMessage struct { + baseMessage + Error *RPCError +} + +// Command returns the protocol command string for the message +func (msg *StopNotifyingUTXOsChangedResponseMessage) Command() MessageCommand { + return CmdStopNotifyingUTXOsChangedResponseMessage +} + +// NewStopNotifyingUTXOsChangedResponseMessage returns a instance of the message +func NewStopNotifyingUTXOsChangedResponseMessage() *StopNotifyingUTXOsChangedResponseMessage { + return &StopNotifyingUTXOsChangedResponseMessage{} +} diff --git a/app/rpc/rpc.go b/app/rpc/rpc.go index 57e6a4f0c..f9e25050e 100644 --- a/app/rpc/rpc.go +++ b/app/rpc/rpc.go @@ -35,6 +35,7 @@ var handlers = map[appmessage.MessageCommand]handler{ appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown, appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders, appmessage.CmdNotifyUTXOsChangedRequestMessage: rpchandlers.HandleNotifyUTXOsChanged, + appmessage.CmdStopNotifyingUTXOsChangedRequestMessage: rpchandlers.HandleStopNotifyingUTXOsChanged, appmessage.CmdGetUTXOsByAddressesRequestMessage: rpchandlers.HandleGetUTXOsByAddresses, appmessage.CmdGetVirtualSelectedParentBlueScoreRequestMessage: rpchandlers.HandleGetVirtualSelectedParentBlueScore, appmessage.CmdNotifyVirtualSelectedParentBlueScoreChangedRequestMessage: rpchandlers.HandleNotifyVirtualSelectedParentBlueScoreChanged, diff --git a/app/rpc/rpccontext/notificationmanager.go b/app/rpc/rpccontext/notificationmanager.go index 119d31fef..c88189f4d 100644 --- a/app/rpc/rpccontext/notificationmanager.go +++ b/app/rpc/rpccontext/notificationmanager.go @@ -31,7 +31,7 @@ type NotificationListener struct { propagateUTXOsChangedNotifications bool propagateVirtualSelectedParentBlueScoreChangedNotifications bool - propagateUTXOsChangedNotificationAddresses []*UTXOsChangedNotificationAddress + propagateUTXOsChangedNotificationAddresses map[utxoindex.ScriptPublicKeyString]*UTXOsChangedNotificationAddress } // NewNotificationManager creates a new NotificationManager @@ -216,34 +216,70 @@ func (nl *NotificationListener) PropagateFinalityConflictResolvedNotifications() } // PropagateUTXOsChangedNotifications instructs the listener to send UTXOs changed notifications -// to the remote listener +// to the remote listener for the given addresses. Subsequent calls instruct the listener to +// send UTXOs changed notifications for those addresses along with the old ones. Duplicate addresses +// are ignored. func (nl *NotificationListener) PropagateUTXOsChangedNotifications(addresses []*UTXOsChangedNotificationAddress) { - nl.propagateUTXOsChangedNotifications = true - nl.propagateUTXOsChangedNotificationAddresses = addresses + if !nl.propagateUTXOsChangedNotifications { + nl.propagateUTXOsChangedNotifications = true + nl.propagateUTXOsChangedNotificationAddresses = + make(map[utxoindex.ScriptPublicKeyString]*UTXOsChangedNotificationAddress, len(addresses)) + } + + for _, address := range addresses { + nl.propagateUTXOsChangedNotificationAddresses[address.ScriptPublicKeyString] = address + } +} + +// StopPropagatingUTXOsChangedNotifications instructs the listener to stop sending UTXOs +// changed notifications to the remote listener for the given addresses. Addresses for which +// notifications are not currently sent are ignored. +func (nl *NotificationListener) StopPropagatingUTXOsChangedNotifications(addresses []*UTXOsChangedNotificationAddress) { + if !nl.propagateUTXOsChangedNotifications { + return + } + + for _, address := range addresses { + delete(nl.propagateUTXOsChangedNotificationAddresses, address.ScriptPublicKeyString) + } } func (nl *NotificationListener) convertUTXOChangesToUTXOsChangedNotification( utxoChanges *utxoindex.UTXOChanges) *appmessage.UTXOsChangedNotificationMessage { + // As an optimization, we iterate over the smaller set (O(n)) among the two below + // and check existence over the larger set (O(1)) + utxoChangesSize := len(utxoChanges.Added) + len(utxoChanges.Removed) + addressesSize := len(nl.propagateUTXOsChangedNotificationAddresses) + notification := &appmessage.UTXOsChangedNotificationMessage{} - for _, listenerAddress := range nl.propagateUTXOsChangedNotificationAddresses { - listenerScriptPublicKeyString := listenerAddress.ScriptPublicKeyString - if addedPairs, ok := utxoChanges.Added[listenerScriptPublicKeyString]; ok { - notification.Added = append(notification.Added, - ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs)...) + if utxoChangesSize < addressesSize { + for scriptPublicKeyString, addedPairs := range utxoChanges.Added { + if listenerAddress, ok := nl.propagateUTXOsChangedNotificationAddresses[scriptPublicKeyString]; ok { + utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs) + notification.Added = append(notification.Added, utxosByAddressesEntries...) + } } - if removedOutpoints, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok { - for outpoint := range removedOutpoints { - notification.Removed = append(notification.Removed, &appmessage.UTXOsByAddressesEntry{ - Address: listenerAddress.Address, - Outpoint: &appmessage.RPCOutpoint{ - TransactionID: outpoint.TransactionID.String(), - Index: outpoint.Index, - }, - }) + for scriptPublicKeyString, removedOutpoints := range utxoChanges.Removed { + if listenerAddress, ok := nl.propagateUTXOsChangedNotificationAddresses[scriptPublicKeyString]; ok { + utxosByAddressesEntries := convertUTXOOutpointsToUTXOsByAddressesEntries(listenerAddress.Address, removedOutpoints) + notification.Removed = append(notification.Removed, utxosByAddressesEntries...) + } + } + } else { + for _, listenerAddress := range nl.propagateUTXOsChangedNotificationAddresses { + listenerScriptPublicKeyString := listenerAddress.ScriptPublicKeyString + if addedPairs, ok := utxoChanges.Added[listenerScriptPublicKeyString]; ok { + utxosByAddressesEntries := ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(listenerAddress.Address, addedPairs) + notification.Added = append(notification.Added, utxosByAddressesEntries...) + } + if removedOutpoints, ok := utxoChanges.Removed[listenerScriptPublicKeyString]; ok { + utxosByAddressesEntries := convertUTXOOutpointsToUTXOsByAddressesEntries(listenerAddress.Address, removedOutpoints) + notification.Removed = append(notification.Removed, utxosByAddressesEntries...) } } } + return notification } diff --git a/app/rpc/rpccontext/utxos_by_addresses.go b/app/rpc/rpccontext/utxos_by_addresses.go index cea7db747..ff73d9862 100644 --- a/app/rpc/rpccontext/utxos_by_addresses.go +++ b/app/rpc/rpccontext/utxos_by_addresses.go @@ -2,6 +2,9 @@ package rpccontext import ( "encoding/hex" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/util" + "github.com/pkg/errors" "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/utxoindex" @@ -28,3 +31,43 @@ func ConvertUTXOOutpointEntryPairsToUTXOsByAddressesEntries(address string, pair } return utxosByAddressesEntries } + +// convertUTXOOutpointsToUTXOsByAddressesEntries converts +// UTXOOutpoints to a slice of UTXOsByAddressesEntry +func convertUTXOOutpointsToUTXOsByAddressesEntries(address string, outpoints utxoindex.UTXOOutpoints) []*appmessage.UTXOsByAddressesEntry { + utxosByAddressesEntries := make([]*appmessage.UTXOsByAddressesEntry, 0, len(outpoints)) + for outpoint := range outpoints { + utxosByAddressesEntries = append(utxosByAddressesEntries, &appmessage.UTXOsByAddressesEntry{ + Address: address, + Outpoint: &appmessage.RPCOutpoint{ + TransactionID: outpoint.TransactionID.String(), + Index: outpoint.Index, + }, + }) + } + return utxosByAddressesEntries +} + +// ConvertAddressStringsToUTXOsChangedNotificationAddresses converts address strings +// to UTXOsChangedNotificationAddresses +func (ctx *Context) ConvertAddressStringsToUTXOsChangedNotificationAddresses( + addressStrings []string) ([]*UTXOsChangedNotificationAddress, error) { + + addresses := make([]*UTXOsChangedNotificationAddress, len(addressStrings)) + for i, addressString := range addressStrings { + address, err := util.DecodeAddress(addressString, ctx.Config.ActiveNetParams.Prefix) + if err != nil { + return nil, errors.Errorf("Could not decode address '%s': %s", addressString, err) + } + scriptPublicKey, err := txscript.PayToAddrScript(address) + if err != nil { + return nil, errors.Errorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err) + } + scriptPublicKeyString := utxoindex.ConvertScriptPublicKeyToString(scriptPublicKey) + addresses[i] = &UTXOsChangedNotificationAddress{ + Address: addressString, + ScriptPublicKeyString: scriptPublicKeyString, + } + } + return addresses, nil +} diff --git a/app/rpc/rpchandlers/notify_utxos_changed.go b/app/rpc/rpchandlers/notify_utxos_changed.go index e3acb31dd..41ffe0dd3 100644 --- a/app/rpc/rpchandlers/notify_utxos_changed.go +++ b/app/rpc/rpchandlers/notify_utxos_changed.go @@ -3,10 +3,7 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" - "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" - "github.com/kaspanet/kaspad/domain/utxoindex" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" - "github.com/kaspanet/kaspad/util" ) // HandleNotifyUTXOsChanged handles the respectively named RPC command @@ -18,26 +15,11 @@ func HandleNotifyUTXOsChanged(context *rpccontext.Context, router *router.Router } notifyUTXOsChangedRequest := request.(*appmessage.NotifyUTXOsChangedRequestMessage) - - addresses := make([]*rpccontext.UTXOsChangedNotificationAddress, len(notifyUTXOsChangedRequest.Addresses)) - for i, addressString := range notifyUTXOsChangedRequest.Addresses { - address, err := util.DecodeAddress(addressString, context.Config.ActiveNetParams.Prefix) - if err != nil { - errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() - errorMessage.Error = appmessage.RPCErrorf("Could not decode address '%s': %s", addressString, err) - return errorMessage, nil - } - scriptPublicKey, err := txscript.PayToAddrScript(address) - if err != nil { - errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() - errorMessage.Error = appmessage.RPCErrorf("Could not create a scriptPublicKey for address '%s': %s", addressString, err) - return errorMessage, nil - } - scriptPublicKeyString := utxoindex.ConvertScriptPublicKeyToString(scriptPublicKey) - addresses[i] = &rpccontext.UTXOsChangedNotificationAddress{ - Address: addressString, - ScriptPublicKeyString: scriptPublicKeyString, - } + addresses, err := context.ConvertAddressStringsToUTXOsChangedNotificationAddresses(notifyUTXOsChangedRequest.Addresses) + if err != nil { + errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() + errorMessage.Error = appmessage.RPCErrorf("Parsing error: %s", err) + return errorMessage, nil } listener, err := context.NotificationManager.Listener(router) diff --git a/app/rpc/rpchandlers/stop_notifying_utxos_changed.go b/app/rpc/rpchandlers/stop_notifying_utxos_changed.go new file mode 100644 index 000000000..0da89a9bf --- /dev/null +++ b/app/rpc/rpchandlers/stop_notifying_utxos_changed.go @@ -0,0 +1,33 @@ +package rpchandlers + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/rpc/rpccontext" + "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" +) + +// HandleStopNotifyingUTXOsChanged handles the respectively named RPC command +func HandleStopNotifyingUTXOsChanged(context *rpccontext.Context, router *router.Router, request appmessage.Message) (appmessage.Message, error) { + if !context.Config.UTXOIndex { + errorMessage := appmessage.NewStopNotifyingUTXOsChangedResponseMessage() + errorMessage.Error = appmessage.RPCErrorf("Method unavailable when kaspad is run without --utxoindex") + return errorMessage, nil + } + + stopNotifyingUTXOsChangedRequest := request.(*appmessage.StopNotifyingUTXOsChangedRequestMessage) + addresses, err := context.ConvertAddressStringsToUTXOsChangedNotificationAddresses(stopNotifyingUTXOsChangedRequest.Addresses) + if err != nil { + errorMessage := appmessage.NewNotifyUTXOsChangedResponseMessage() + errorMessage.Error = appmessage.RPCErrorf("Parsing error: %s", err) + return errorMessage, nil + } + + listener, err := context.NotificationManager.Listener(router) + if err != nil { + return nil, err + } + listener.StopPropagatingUTXOsChangedNotifications(addresses) + + response := appmessage.NewStopNotifyingUTXOsChangedResponseMessage() + return response, nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go index 73f4851d5..351cb942b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.pb.go @@ -127,6 +127,8 @@ type KaspadMessage struct { // *KaspadMessage_UnbanResponse // *KaspadMessage_GetInfoRequest // *KaspadMessage_GetInfoResponse + // *KaspadMessage_StopNotifyingUtxosChangedRequest + // *KaspadMessage_StopNotifyingUtxosChangedResponse Payload isKaspadMessage_Payload `protobuf_oneof:"payload"` } @@ -841,6 +843,20 @@ func (x *KaspadMessage) GetGetInfoResponse() *GetInfoResponseMessage { return nil } +func (x *KaspadMessage) GetStopNotifyingUtxosChangedRequest() *StopNotifyingUtxosChangedRequestMessage { + if x, ok := x.GetPayload().(*KaspadMessage_StopNotifyingUtxosChangedRequest); ok { + return x.StopNotifyingUtxosChangedRequest + } + return nil +} + +func (x *KaspadMessage) GetStopNotifyingUtxosChangedResponse() *StopNotifyingUtxosChangedResponseMessage { + if x, ok := x.GetPayload().(*KaspadMessage_StopNotifyingUtxosChangedResponse); ok { + return x.StopNotifyingUtxosChangedResponse + } + return nil +} + type isKaspadMessage_Payload interface { isKaspadMessage_Payload() } @@ -1229,6 +1245,14 @@ type KaspadMessage_GetInfoResponse struct { GetInfoResponse *GetInfoResponseMessage `protobuf:"bytes,1064,opt,name=getInfoResponse,proto3,oneof"` } +type KaspadMessage_StopNotifyingUtxosChangedRequest struct { + StopNotifyingUtxosChangedRequest *StopNotifyingUtxosChangedRequestMessage `protobuf:"bytes,1065,opt,name=stopNotifyingUtxosChangedRequest,proto3,oneof"` +} + +type KaspadMessage_StopNotifyingUtxosChangedResponse struct { + StopNotifyingUtxosChangedResponse *StopNotifyingUtxosChangedResponseMessage `protobuf:"bytes,1066,opt,name=stopNotifyingUtxosChangedResponse,proto3,oneof"` +} + func (*KaspadMessage_Addresses) isKaspadMessage_Payload() {} func (*KaspadMessage_Block) isKaspadMessage_Payload() {} @@ -1421,13 +1445,17 @@ func (*KaspadMessage_GetInfoRequest) isKaspadMessage_Payload() {} func (*KaspadMessage_GetInfoResponse) isKaspadMessage_Payload() {} +func (*KaspadMessage_StopNotifyingUtxosChangedRequest) isKaspadMessage_Payload() {} + +func (*KaspadMessage_StopNotifyingUtxosChangedResponse) isKaspadMessage_Payload() {} + var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x1a, 0x09, 0x70, 0x32, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xe0, 0x4c, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, + 0x6f, 0x22, 0xeb, 0x4e, 0x0a, 0x0d, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x4d, 0x65, 0x73, 0x73, @@ -2040,21 +2068,38 @@ var file_messages_proto_rawDesc = []byte{ 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 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, 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, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x20, 0x73, 0x74, + 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0xa9, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x20, 0x73, 0x74, 0x6f, + 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x84, 0x01, + 0x0a, 0x21, 0x73, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0xaa, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x21, 0x73, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 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, 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 ( @@ -2167,113 +2212,117 @@ var file_messages_proto_goTypes = []interface{}{ (*UnbanResponseMessage)(nil), // 93: protowire.UnbanResponseMessage (*GetInfoRequestMessage)(nil), // 94: protowire.GetInfoRequestMessage (*GetInfoResponseMessage)(nil), // 95: protowire.GetInfoResponseMessage + (*StopNotifyingUtxosChangedRequestMessage)(nil), // 96: protowire.StopNotifyingUtxosChangedRequestMessage + (*StopNotifyingUtxosChangedResponseMessage)(nil), // 97: protowire.StopNotifyingUtxosChangedResponseMessage } var file_messages_proto_depIdxs = []int32{ - 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage - 2, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage - 3, // 2: protowire.KaspadMessage.transaction:type_name -> protowire.TransactionMessage - 4, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage - 5, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage - 6, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage - 7, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage - 8, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage - 9, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage - 10, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage - 11, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage - 2, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage - 12, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage - 13, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage - 14, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage - 15, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage - 16, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage - 17, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage - 18, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage - 19, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage - 20, // 20: protowire.KaspadMessage.requestPruningPointUTXOSetAndBlock:type_name -> protowire.RequestPruningPointUTXOSetAndBlockMessage - 21, // 21: protowire.KaspadMessage.pruningPointUtxoSetChunk:type_name -> protowire.PruningPointUtxoSetChunkMessage - 22, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage - 23, // 23: protowire.KaspadMessage.unexpectedPruningPoint:type_name -> protowire.UnexpectedPruningPointMessage - 24, // 24: protowire.KaspadMessage.requestPruningPointHash:type_name -> protowire.RequestPruningPointHashMessage - 25, // 25: protowire.KaspadMessage.pruningPointHash:type_name -> protowire.PruningPointHashMessage - 26, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage - 27, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage - 28, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage - 29, // 29: protowire.KaspadMessage.requestNextPruningPointUtxoSetChunk:type_name -> protowire.RequestNextPruningPointUtxoSetChunkMessage - 30, // 30: protowire.KaspadMessage.donePruningPointUtxoSetChunks:type_name -> protowire.DonePruningPointUtxoSetChunksMessage - 31, // 31: protowire.KaspadMessage.ibdBlockLocatorHighestHashNotFound:type_name -> protowire.IbdBlockLocatorHighestHashNotFoundMessage - 32, // 32: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage - 33, // 33: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage - 34, // 34: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage - 35, // 35: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage - 36, // 36: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage - 37, // 37: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage - 38, // 38: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage - 39, // 39: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage - 40, // 40: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage - 41, // 41: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage - 42, // 42: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage - 43, // 43: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage - 44, // 44: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage - 45, // 45: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage - 46, // 46: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage - 47, // 47: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage - 48, // 48: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage - 49, // 49: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage - 50, // 50: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage - 51, // 51: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage - 52, // 52: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage - 53, // 53: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage - 54, // 54: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage - 55, // 55: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage - 56, // 56: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage - 57, // 57: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage - 58, // 58: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage - 59, // 59: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage - 60, // 60: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage - 61, // 61: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage - 62, // 62: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage - 63, // 63: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage - 64, // 64: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage - 65, // 65: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage - 66, // 66: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage - 67, // 67: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage - 68, // 68: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage - 69, // 69: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage - 70, // 70: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage - 71, // 71: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage - 72, // 72: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage - 73, // 73: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage - 74, // 74: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage - 75, // 75: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage - 76, // 76: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage - 77, // 77: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage - 78, // 78: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage - 79, // 79: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage - 80, // 80: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage - 81, // 81: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage - 82, // 82: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage - 83, // 83: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage - 84, // 84: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage - 85, // 85: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage - 86, // 86: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage - 87, // 87: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - 88, // 88: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - 89, // 89: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - 90, // 90: protowire.KaspadMessage.banRequest:type_name -> protowire.BanRequestMessage - 91, // 91: protowire.KaspadMessage.banResponse:type_name -> protowire.BanResponseMessage - 92, // 92: protowire.KaspadMessage.unbanRequest:type_name -> protowire.UnbanRequestMessage - 93, // 93: protowire.KaspadMessage.unbanResponse:type_name -> protowire.UnbanResponseMessage - 94, // 94: protowire.KaspadMessage.getInfoRequest:type_name -> protowire.GetInfoRequestMessage - 95, // 95: protowire.KaspadMessage.getInfoResponse:type_name -> protowire.GetInfoResponseMessage - 0, // 96: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage - 0, // 97: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage - 0, // 98: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage - 0, // 99: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage - 98, // [98:100] is the sub-list for method output_type - 96, // [96:98] is the sub-list for method input_type - 96, // [96:96] is the sub-list for extension type_name - 96, // [96:96] is the sub-list for extension extendee - 0, // [0:96] is the sub-list for field type_name + 1, // 0: protowire.KaspadMessage.addresses:type_name -> protowire.AddressesMessage + 2, // 1: protowire.KaspadMessage.block:type_name -> protowire.BlockMessage + 3, // 2: protowire.KaspadMessage.transaction:type_name -> protowire.TransactionMessage + 4, // 3: protowire.KaspadMessage.requestBlockLocator:type_name -> protowire.RequestBlockLocatorMessage + 5, // 4: protowire.KaspadMessage.blockLocator:type_name -> protowire.BlockLocatorMessage + 6, // 5: protowire.KaspadMessage.requestAddresses:type_name -> protowire.RequestAddressesMessage + 7, // 6: protowire.KaspadMessage.requestHeaders:type_name -> protowire.RequestHeadersMessage + 8, // 7: protowire.KaspadMessage.requestNextHeaders:type_name -> protowire.RequestNextHeadersMessage + 9, // 8: protowire.KaspadMessage.DoneHeaders:type_name -> protowire.DoneHeadersMessage + 10, // 9: protowire.KaspadMessage.requestRelayBlocks:type_name -> protowire.RequestRelayBlocksMessage + 11, // 10: protowire.KaspadMessage.requestTransactions:type_name -> protowire.RequestTransactionsMessage + 2, // 11: protowire.KaspadMessage.ibdBlock:type_name -> protowire.BlockMessage + 12, // 12: protowire.KaspadMessage.invRelayBlock:type_name -> protowire.InvRelayBlockMessage + 13, // 13: protowire.KaspadMessage.invTransactions:type_name -> protowire.InvTransactionsMessage + 14, // 14: protowire.KaspadMessage.ping:type_name -> protowire.PingMessage + 15, // 15: protowire.KaspadMessage.pong:type_name -> protowire.PongMessage + 16, // 16: protowire.KaspadMessage.verack:type_name -> protowire.VerackMessage + 17, // 17: protowire.KaspadMessage.version:type_name -> protowire.VersionMessage + 18, // 18: protowire.KaspadMessage.transactionNotFound:type_name -> protowire.TransactionNotFoundMessage + 19, // 19: protowire.KaspadMessage.reject:type_name -> protowire.RejectMessage + 20, // 20: protowire.KaspadMessage.requestPruningPointUTXOSetAndBlock:type_name -> protowire.RequestPruningPointUTXOSetAndBlockMessage + 21, // 21: protowire.KaspadMessage.pruningPointUtxoSetChunk:type_name -> protowire.PruningPointUtxoSetChunkMessage + 22, // 22: protowire.KaspadMessage.requestIBDBlocks:type_name -> protowire.RequestIBDBlocksMessage + 23, // 23: protowire.KaspadMessage.unexpectedPruningPoint:type_name -> protowire.UnexpectedPruningPointMessage + 24, // 24: protowire.KaspadMessage.requestPruningPointHash:type_name -> protowire.RequestPruningPointHashMessage + 25, // 25: protowire.KaspadMessage.pruningPointHash:type_name -> protowire.PruningPointHashMessage + 26, // 26: protowire.KaspadMessage.ibdBlockLocator:type_name -> protowire.IbdBlockLocatorMessage + 27, // 27: protowire.KaspadMessage.ibdBlockLocatorHighestHash:type_name -> protowire.IbdBlockLocatorHighestHashMessage + 28, // 28: protowire.KaspadMessage.blockHeaders:type_name -> protowire.BlockHeadersMessage + 29, // 29: protowire.KaspadMessage.requestNextPruningPointUtxoSetChunk:type_name -> protowire.RequestNextPruningPointUtxoSetChunkMessage + 30, // 30: protowire.KaspadMessage.donePruningPointUtxoSetChunks:type_name -> protowire.DonePruningPointUtxoSetChunksMessage + 31, // 31: protowire.KaspadMessage.ibdBlockLocatorHighestHashNotFound:type_name -> protowire.IbdBlockLocatorHighestHashNotFoundMessage + 32, // 32: protowire.KaspadMessage.getCurrentNetworkRequest:type_name -> protowire.GetCurrentNetworkRequestMessage + 33, // 33: protowire.KaspadMessage.getCurrentNetworkResponse:type_name -> protowire.GetCurrentNetworkResponseMessage + 34, // 34: protowire.KaspadMessage.submitBlockRequest:type_name -> protowire.SubmitBlockRequestMessage + 35, // 35: protowire.KaspadMessage.submitBlockResponse:type_name -> protowire.SubmitBlockResponseMessage + 36, // 36: protowire.KaspadMessage.getBlockTemplateRequest:type_name -> protowire.GetBlockTemplateRequestMessage + 37, // 37: protowire.KaspadMessage.getBlockTemplateResponse:type_name -> protowire.GetBlockTemplateResponseMessage + 38, // 38: protowire.KaspadMessage.notifyBlockAddedRequest:type_name -> protowire.NotifyBlockAddedRequestMessage + 39, // 39: protowire.KaspadMessage.notifyBlockAddedResponse:type_name -> protowire.NotifyBlockAddedResponseMessage + 40, // 40: protowire.KaspadMessage.blockAddedNotification:type_name -> protowire.BlockAddedNotificationMessage + 41, // 41: protowire.KaspadMessage.getPeerAddressesRequest:type_name -> protowire.GetPeerAddressesRequestMessage + 42, // 42: protowire.KaspadMessage.getPeerAddressesResponse:type_name -> protowire.GetPeerAddressesResponseMessage + 43, // 43: protowire.KaspadMessage.getSelectedTipHashRequest:type_name -> protowire.GetSelectedTipHashRequestMessage + 44, // 44: protowire.KaspadMessage.getSelectedTipHashResponse:type_name -> protowire.GetSelectedTipHashResponseMessage + 45, // 45: protowire.KaspadMessage.getMempoolEntryRequest:type_name -> protowire.GetMempoolEntryRequestMessage + 46, // 46: protowire.KaspadMessage.getMempoolEntryResponse:type_name -> protowire.GetMempoolEntryResponseMessage + 47, // 47: protowire.KaspadMessage.getConnectedPeerInfoRequest:type_name -> protowire.GetConnectedPeerInfoRequestMessage + 48, // 48: protowire.KaspadMessage.getConnectedPeerInfoResponse:type_name -> protowire.GetConnectedPeerInfoResponseMessage + 49, // 49: protowire.KaspadMessage.addPeerRequest:type_name -> protowire.AddPeerRequestMessage + 50, // 50: protowire.KaspadMessage.addPeerResponse:type_name -> protowire.AddPeerResponseMessage + 51, // 51: protowire.KaspadMessage.submitTransactionRequest:type_name -> protowire.SubmitTransactionRequestMessage + 52, // 52: protowire.KaspadMessage.submitTransactionResponse:type_name -> protowire.SubmitTransactionResponseMessage + 53, // 53: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentChainChangedRequestMessage + 54, // 54: protowire.KaspadMessage.notifyVirtualSelectedParentChainChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentChainChangedResponseMessage + 55, // 55: protowire.KaspadMessage.virtualSelectedParentChainChangedNotification:type_name -> protowire.VirtualSelectedParentChainChangedNotificationMessage + 56, // 56: protowire.KaspadMessage.getBlockRequest:type_name -> protowire.GetBlockRequestMessage + 57, // 57: protowire.KaspadMessage.getBlockResponse:type_name -> protowire.GetBlockResponseMessage + 58, // 58: protowire.KaspadMessage.getSubnetworkRequest:type_name -> protowire.GetSubnetworkRequestMessage + 59, // 59: protowire.KaspadMessage.getSubnetworkResponse:type_name -> protowire.GetSubnetworkResponseMessage + 60, // 60: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockRequest:type_name -> protowire.GetVirtualSelectedParentChainFromBlockRequestMessage + 61, // 61: protowire.KaspadMessage.getVirtualSelectedParentChainFromBlockResponse:type_name -> protowire.GetVirtualSelectedParentChainFromBlockResponseMessage + 62, // 62: protowire.KaspadMessage.getBlocksRequest:type_name -> protowire.GetBlocksRequestMessage + 63, // 63: protowire.KaspadMessage.getBlocksResponse:type_name -> protowire.GetBlocksResponseMessage + 64, // 64: protowire.KaspadMessage.getBlockCountRequest:type_name -> protowire.GetBlockCountRequestMessage + 65, // 65: protowire.KaspadMessage.getBlockCountResponse:type_name -> protowire.GetBlockCountResponseMessage + 66, // 66: protowire.KaspadMessage.getBlockDagInfoRequest:type_name -> protowire.GetBlockDagInfoRequestMessage + 67, // 67: protowire.KaspadMessage.getBlockDagInfoResponse:type_name -> protowire.GetBlockDagInfoResponseMessage + 68, // 68: protowire.KaspadMessage.resolveFinalityConflictRequest:type_name -> protowire.ResolveFinalityConflictRequestMessage + 69, // 69: protowire.KaspadMessage.resolveFinalityConflictResponse:type_name -> protowire.ResolveFinalityConflictResponseMessage + 70, // 70: protowire.KaspadMessage.notifyFinalityConflictsRequest:type_name -> protowire.NotifyFinalityConflictsRequestMessage + 71, // 71: protowire.KaspadMessage.notifyFinalityConflictsResponse:type_name -> protowire.NotifyFinalityConflictsResponseMessage + 72, // 72: protowire.KaspadMessage.finalityConflictNotification:type_name -> protowire.FinalityConflictNotificationMessage + 73, // 73: protowire.KaspadMessage.finalityConflictResolvedNotification:type_name -> protowire.FinalityConflictResolvedNotificationMessage + 74, // 74: protowire.KaspadMessage.getMempoolEntriesRequest:type_name -> protowire.GetMempoolEntriesRequestMessage + 75, // 75: protowire.KaspadMessage.getMempoolEntriesResponse:type_name -> protowire.GetMempoolEntriesResponseMessage + 76, // 76: protowire.KaspadMessage.shutDownRequest:type_name -> protowire.ShutDownRequestMessage + 77, // 77: protowire.KaspadMessage.shutDownResponse:type_name -> protowire.ShutDownResponseMessage + 78, // 78: protowire.KaspadMessage.getHeadersRequest:type_name -> protowire.GetHeadersRequestMessage + 79, // 79: protowire.KaspadMessage.getHeadersResponse:type_name -> protowire.GetHeadersResponseMessage + 80, // 80: protowire.KaspadMessage.notifyUtxosChangedRequest:type_name -> protowire.NotifyUtxosChangedRequestMessage + 81, // 81: protowire.KaspadMessage.notifyUtxosChangedResponse:type_name -> protowire.NotifyUtxosChangedResponseMessage + 82, // 82: protowire.KaspadMessage.utxosChangedNotification:type_name -> protowire.UtxosChangedNotificationMessage + 83, // 83: protowire.KaspadMessage.getUtxosByAddressesRequest:type_name -> protowire.GetUtxosByAddressesRequestMessage + 84, // 84: protowire.KaspadMessage.getUtxosByAddressesResponse:type_name -> protowire.GetUtxosByAddressesResponseMessage + 85, // 85: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreRequest:type_name -> protowire.GetVirtualSelectedParentBlueScoreRequestMessage + 86, // 86: protowire.KaspadMessage.getVirtualSelectedParentBlueScoreResponse:type_name -> protowire.GetVirtualSelectedParentBlueScoreResponseMessage + 87, // 87: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedRequest:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + 88, // 88: protowire.KaspadMessage.notifyVirtualSelectedParentBlueScoreChangedResponse:type_name -> protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + 89, // 89: protowire.KaspadMessage.virtualSelectedParentBlueScoreChangedNotification:type_name -> protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + 90, // 90: protowire.KaspadMessage.banRequest:type_name -> protowire.BanRequestMessage + 91, // 91: protowire.KaspadMessage.banResponse:type_name -> protowire.BanResponseMessage + 92, // 92: protowire.KaspadMessage.unbanRequest:type_name -> protowire.UnbanRequestMessage + 93, // 93: protowire.KaspadMessage.unbanResponse:type_name -> protowire.UnbanResponseMessage + 94, // 94: protowire.KaspadMessage.getInfoRequest:type_name -> protowire.GetInfoRequestMessage + 95, // 95: protowire.KaspadMessage.getInfoResponse:type_name -> protowire.GetInfoResponseMessage + 96, // 96: protowire.KaspadMessage.stopNotifyingUtxosChangedRequest:type_name -> protowire.StopNotifyingUtxosChangedRequestMessage + 97, // 97: protowire.KaspadMessage.stopNotifyingUtxosChangedResponse:type_name -> protowire.StopNotifyingUtxosChangedResponseMessage + 0, // 98: protowire.P2P.MessageStream:input_type -> protowire.KaspadMessage + 0, // 99: protowire.RPC.MessageStream:input_type -> protowire.KaspadMessage + 0, // 100: protowire.P2P.MessageStream:output_type -> protowire.KaspadMessage + 0, // 101: protowire.RPC.MessageStream:output_type -> protowire.KaspadMessage + 100, // [100:102] is the sub-list for method output_type + 98, // [98:100] is the sub-list for method input_type + 98, // [98:98] is the sub-list for extension type_name + 98, // [98:98] is the sub-list for extension extendee + 0, // [0:98] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2394,6 +2443,8 @@ func file_messages_proto_init() { (*KaspadMessage_UnbanResponse)(nil), (*KaspadMessage_GetInfoRequest)(nil), (*KaspadMessage_GetInfoResponse)(nil), + (*KaspadMessage_StopNotifyingUtxosChangedRequest)(nil), + (*KaspadMessage_StopNotifyingUtxosChangedResponse)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto index af9b87550..9ebe9db6b 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto @@ -105,6 +105,8 @@ message KaspadMessage { UnbanResponseMessage unbanResponse = 1062; GetInfoRequestMessage getInfoRequest = 1063; GetInfoResponseMessage getInfoResponse = 1064; + StopNotifyingUtxosChangedRequestMessage stopNotifyingUtxosChangedRequest = 1065; + StopNotifyingUtxosChangedResponseMessage stopNotifyingUtxosChangedResponse = 1066; } } diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md index 0b99f9ba0..c729ca6e7 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.md @@ -58,26 +58,28 @@ - [ResolveFinalityConflictResponseMessage](#protowire.ResolveFinalityConflictResponseMessage) - [NotifyFinalityConflictsRequestMessage](#protowire.NotifyFinalityConflictsRequestMessage) - [NotifyFinalityConflictsResponseMessage](#protowire.NotifyFinalityConflictsResponseMessage) - - [FinalityConflictNotificationMessage](#protowire.FinalityConflictNotificationMessage) - - [FinalityConflictResolvedNotificationMessage](#protowire.FinalityConflictResolvedNotificationMessage) - - [ShutDownRequestMessage](#protowire.ShutDownRequestMessage) - - [ShutDownResponseMessage](#protowire.ShutDownResponseMessage) - - [GetHeadersRequestMessage](#protowire.GetHeadersRequestMessage) - - [GetHeadersResponseMessage](#protowire.GetHeadersResponseMessage) - - [NotifyUtxosChangedRequestMessage](#protowire.NotifyUtxosChangedRequestMessage) - - [NotifyUtxosChangedResponseMessage](#protowire.NotifyUtxosChangedResponseMessage) - - [UtxosChangedNotificationMessage](#protowire.UtxosChangedNotificationMessage) - - [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) - - [RpcTransaction](#protowire.RpcTransaction) - - [RpcTransactionInput](#protowire.RpcTransactionInput) - - [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) - - [RpcTransactionOutput](#protowire.RpcTransactionOutput) - - [RpcOutpoint](#protowire.RpcOutpoint) - - [RpcUtxoEntry](#protowire.RpcUtxoEntry) - - [GetUtxosByAddressesRequestMessage](#protowire.GetUtxosByAddressesRequestMessage) - - [GetUtxosByAddressesResponseMessage](#protowire.GetUtxosByAddressesResponseMessage) - - [GetVirtualSelectedParentBlueScoreRequestMessage](#protowire.GetVirtualSelectedParentBlueScoreRequestMessage) - - [GetVirtualSelectedParentBlueScoreResponseMessage](#protowire.GetVirtualSelectedParentBlueScoreResponseMessage) + - [FinalityConflictNotificationMessage](#protowire.FinalityConflictNotificationMessage) + - [FinalityConflictResolvedNotificationMessage](#protowire.FinalityConflictResolvedNotificationMessage) + - [ShutDownRequestMessage](#protowire.ShutDownRequestMessage) + - [ShutDownResponseMessage](#protowire.ShutDownResponseMessage) + - [GetHeadersRequestMessage](#protowire.GetHeadersRequestMessage) + - [GetHeadersResponseMessage](#protowire.GetHeadersResponseMessage) + - [NotifyUtxosChangedRequestMessage](#protowire.NotifyUtxosChangedRequestMessage) + - [NotifyUtxosChangedResponseMessage](#protowire.NotifyUtxosChangedResponseMessage) + - [UtxosChangedNotificationMessage](#protowire.UtxosChangedNotificationMessage) + - [UtxosByAddressesEntry](#protowire.UtxosByAddressesEntry) + - [StopNotifyingUtxosChangedRequestMessage](#protowire.StopNotifyingUtxosChangedRequestMessage) + - [StopNotifyingUtxosChangedResponseMessage](#protowire.StopNotifyingUtxosChangedResponseMessage) + - [RpcTransaction](#protowire.RpcTransaction) + - [RpcTransactionInput](#protowire.RpcTransactionInput) + - [RpcScriptPublicKey](#protowire.RpcScriptPublicKey) + - [RpcTransactionOutput](#protowire.RpcTransactionOutput) + - [RpcOutpoint](#protowire.RpcOutpoint) + - [RpcUtxoEntry](#protowire.RpcUtxoEntry) + - [GetUtxosByAddressesRequestMessage](#protowire.GetUtxosByAddressesRequestMessage) + - [GetUtxosByAddressesResponseMessage](#protowire.GetUtxosByAddressesResponseMessage) + - [GetVirtualSelectedParentBlueScoreRequestMessage](#protowire.GetVirtualSelectedParentBlueScoreRequestMessage) + - [GetVirtualSelectedParentBlueScoreResponseMessage](#protowire.GetVirtualSelectedParentBlueScoreResponseMessage) - [NotifyVirtualSelectedParentBlueScoreChangedRequestMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) - [NotifyVirtualSelectedParentBlueScoreChangedResponseMessage](#protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) - [VirtualSelectedParentBlueScoreChangedNotificationMessage](#protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage) @@ -857,7 +859,6 @@ kaspad's current virtual. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | blockHashes | [string](#string) | repeated | | -| blockHexes | [string](#string) | repeated | | | blockVerboseData | [BlockVerboseData](#protowire.BlockVerboseData) | repeated | | | error | [RPCError](#protowire.RPCError) | | | @@ -1128,25 +1129,39 @@ See: NotifyUtxosChangedRequestMessage ### UtxosByAddressesEntry - - | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | address | [string](#string) | | | | outpoint | [RpcOutpoint](#protowire.RpcOutpoint) | | | | utxoEntry | [RpcUtxoEntry](#protowire.RpcUtxoEntry) | | | + +### StopNotifyingUtxosChangedRequestMessage +StopNotifyingUtxosChangedRequestMessage unregisters this connection for utxoChanged notifications for the given +addresses. +This call is only available when this kaspad was started with `--utxoindex` +See: UtxosChangedNotificationMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| addresses | [string](#string) | repeated | | + + + +### StopNotifyingUtxosChangedResponseMessage + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [RPCError](#protowire.RPCError) | | | ### RpcTransaction - - | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | version | [uint32](#uint32) | | | diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go index a028b571a..e6c32338d 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.pb.go @@ -3773,6 +3773,106 @@ func (x *UtxosByAddressesEntry) GetUtxoEntry() *RpcUtxoEntry { return nil } +// StopNotifyingUtxosChangedRequestMessage unregisters this connection for utxoChanged notifications +// for the given addresses. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: UtxosChangedNotificationMessage +type StopNotifyingUtxosChangedRequestMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Addresses []string `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (x *StopNotifyingUtxosChangedRequestMessage) Reset() { + *x = StopNotifyingUtxosChangedRequestMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopNotifyingUtxosChangedRequestMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopNotifyingUtxosChangedRequestMessage) ProtoMessage() {} + +func (x *StopNotifyingUtxosChangedRequestMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[64] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StopNotifyingUtxosChangedRequestMessage.ProtoReflect.Descriptor instead. +func (*StopNotifyingUtxosChangedRequestMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{64} +} + +func (x *StopNotifyingUtxosChangedRequestMessage) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +type StopNotifyingUtxosChangedResponseMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error *RPCError `protobuf:"bytes,1000,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *StopNotifyingUtxosChangedResponseMessage) Reset() { + *x = StopNotifyingUtxosChangedResponseMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopNotifyingUtxosChangedResponseMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopNotifyingUtxosChangedResponseMessage) ProtoMessage() {} + +func (x *StopNotifyingUtxosChangedResponseMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_proto_msgTypes[65] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StopNotifyingUtxosChangedResponseMessage.ProtoReflect.Descriptor instead. +func (*StopNotifyingUtxosChangedResponseMessage) Descriptor() ([]byte, []int) { + return file_rpc_proto_rawDescGZIP(), []int{65} +} + +func (x *StopNotifyingUtxosChangedResponseMessage) GetError() *RPCError { + if x != nil { + return x.Error + } + return nil +} + type RpcTransaction struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3791,7 +3891,7 @@ type RpcTransaction struct { func (x *RpcTransaction) Reset() { *x = RpcTransaction{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[64] + mi := &file_rpc_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3804,7 +3904,7 @@ func (x *RpcTransaction) String() string { func (*RpcTransaction) ProtoMessage() {} func (x *RpcTransaction) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[64] + mi := &file_rpc_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3817,7 +3917,7 @@ func (x *RpcTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransaction.ProtoReflect.Descriptor instead. func (*RpcTransaction) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{64} + return file_rpc_proto_rawDescGZIP(), []int{66} } func (x *RpcTransaction) GetVersion() uint32 { @@ -3889,7 +3989,7 @@ type RpcTransactionInput struct { func (x *RpcTransactionInput) Reset() { *x = RpcTransactionInput{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[65] + mi := &file_rpc_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3902,7 +4002,7 @@ func (x *RpcTransactionInput) String() string { func (*RpcTransactionInput) ProtoMessage() {} func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[65] + mi := &file_rpc_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3915,7 +4015,7 @@ func (x *RpcTransactionInput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionInput.ProtoReflect.Descriptor instead. func (*RpcTransactionInput) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{65} + return file_rpc_proto_rawDescGZIP(), []int{67} } func (x *RpcTransactionInput) GetPreviousOutpoint() *RpcOutpoint { @@ -3951,7 +4051,7 @@ type RpcScriptPublicKey struct { func (x *RpcScriptPublicKey) Reset() { *x = RpcScriptPublicKey{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[66] + mi := &file_rpc_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3964,7 +4064,7 @@ func (x *RpcScriptPublicKey) String() string { func (*RpcScriptPublicKey) ProtoMessage() {} func (x *RpcScriptPublicKey) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[66] + mi := &file_rpc_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3977,7 +4077,7 @@ func (x *RpcScriptPublicKey) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcScriptPublicKey.ProtoReflect.Descriptor instead. func (*RpcScriptPublicKey) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{66} + return file_rpc_proto_rawDescGZIP(), []int{68} } func (x *RpcScriptPublicKey) GetVersion() uint32 { @@ -4006,7 +4106,7 @@ type RpcTransactionOutput struct { func (x *RpcTransactionOutput) Reset() { *x = RpcTransactionOutput{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[67] + mi := &file_rpc_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4019,7 +4119,7 @@ func (x *RpcTransactionOutput) String() string { func (*RpcTransactionOutput) ProtoMessage() {} func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[67] + mi := &file_rpc_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4032,7 +4132,7 @@ func (x *RpcTransactionOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcTransactionOutput.ProtoReflect.Descriptor instead. func (*RpcTransactionOutput) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{67} + return file_rpc_proto_rawDescGZIP(), []int{69} } func (x *RpcTransactionOutput) GetAmount() uint64 { @@ -4061,7 +4161,7 @@ type RpcOutpoint struct { func (x *RpcOutpoint) Reset() { *x = RpcOutpoint{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[68] + mi := &file_rpc_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4074,7 +4174,7 @@ func (x *RpcOutpoint) String() string { func (*RpcOutpoint) ProtoMessage() {} func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[68] + mi := &file_rpc_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4087,7 +4187,7 @@ func (x *RpcOutpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcOutpoint.ProtoReflect.Descriptor instead. func (*RpcOutpoint) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{68} + return file_rpc_proto_rawDescGZIP(), []int{70} } func (x *RpcOutpoint) GetTransactionId() string { @@ -4118,7 +4218,7 @@ type RpcUtxoEntry struct { func (x *RpcUtxoEntry) Reset() { *x = RpcUtxoEntry{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[69] + mi := &file_rpc_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4131,7 +4231,7 @@ func (x *RpcUtxoEntry) String() string { func (*RpcUtxoEntry) ProtoMessage() {} func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[69] + mi := &file_rpc_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4144,7 +4244,7 @@ func (x *RpcUtxoEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use RpcUtxoEntry.ProtoReflect.Descriptor instead. func (*RpcUtxoEntry) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{69} + return file_rpc_proto_rawDescGZIP(), []int{71} } func (x *RpcUtxoEntry) GetAmount() uint64 { @@ -4189,7 +4289,7 @@ type GetUtxosByAddressesRequestMessage struct { func (x *GetUtxosByAddressesRequestMessage) Reset() { *x = GetUtxosByAddressesRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[70] + mi := &file_rpc_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4202,7 +4302,7 @@ func (x *GetUtxosByAddressesRequestMessage) String() string { func (*GetUtxosByAddressesRequestMessage) ProtoMessage() {} func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[70] + mi := &file_rpc_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4215,7 +4315,7 @@ func (x *GetUtxosByAddressesRequestMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesRequestMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesRequestMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{70} + return file_rpc_proto_rawDescGZIP(), []int{72} } func (x *GetUtxosByAddressesRequestMessage) GetAddresses() []string { @@ -4237,7 +4337,7 @@ type GetUtxosByAddressesResponseMessage struct { func (x *GetUtxosByAddressesResponseMessage) Reset() { *x = GetUtxosByAddressesResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[71] + mi := &file_rpc_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4250,7 +4350,7 @@ func (x *GetUtxosByAddressesResponseMessage) String() string { func (*GetUtxosByAddressesResponseMessage) ProtoMessage() {} func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[71] + mi := &file_rpc_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4263,7 +4363,7 @@ func (x *GetUtxosByAddressesResponseMessage) ProtoReflect() protoreflect.Message // Deprecated: Use GetUtxosByAddressesResponseMessage.ProtoReflect.Descriptor instead. func (*GetUtxosByAddressesResponseMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{71} + return file_rpc_proto_rawDescGZIP(), []int{73} } func (x *GetUtxosByAddressesResponseMessage) GetEntries() []*UtxosByAddressesEntry { @@ -4291,7 +4391,7 @@ type GetVirtualSelectedParentBlueScoreRequestMessage struct { func (x *GetVirtualSelectedParentBlueScoreRequestMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[72] + mi := &file_rpc_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4304,7 +4404,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) String() string { func (*GetVirtualSelectedParentBlueScoreRequestMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[72] + mi := &file_rpc_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4317,7 +4417,7 @@ func (x *GetVirtualSelectedParentBlueScoreRequestMessage) ProtoReflect() protore // Deprecated: Use GetVirtualSelectedParentBlueScoreRequestMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreRequestMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{72} + return file_rpc_proto_rawDescGZIP(), []int{74} } type GetVirtualSelectedParentBlueScoreResponseMessage struct { @@ -4332,7 +4432,7 @@ type GetVirtualSelectedParentBlueScoreResponseMessage struct { func (x *GetVirtualSelectedParentBlueScoreResponseMessage) Reset() { *x = GetVirtualSelectedParentBlueScoreResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[73] + mi := &file_rpc_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4345,7 +4445,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) String() string { func (*GetVirtualSelectedParentBlueScoreResponseMessage) ProtoMessage() {} func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[73] + mi := &file_rpc_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4358,7 +4458,7 @@ func (x *GetVirtualSelectedParentBlueScoreResponseMessage) ProtoReflect() protor // Deprecated: Use GetVirtualSelectedParentBlueScoreResponseMessage.ProtoReflect.Descriptor instead. func (*GetVirtualSelectedParentBlueScoreResponseMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{73} + return file_rpc_proto_rawDescGZIP(), []int{75} } func (x *GetVirtualSelectedParentBlueScoreResponseMessage) GetBlueScore() uint64 { @@ -4388,7 +4488,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedRequestMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[74] + mi := &file_rpc_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4401,7 +4501,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) String() str func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[74] + mi := &file_rpc_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4414,7 +4514,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) ProtoReflect // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{74} + return file_rpc_proto_rawDescGZIP(), []int{76} } type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { @@ -4428,7 +4528,7 @@ type NotifyVirtualSelectedParentBlueScoreChangedResponseMessage struct { func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Reset() { *x = NotifyVirtualSelectedParentBlueScoreChangedResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[75] + mi := &file_rpc_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4441,7 +4541,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) String() st func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoMessage() {} func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[75] + mi := &file_rpc_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4454,7 +4554,7 @@ func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) ProtoReflec // Deprecated: Use NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.ProtoReflect.Descriptor instead. func (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{75} + return file_rpc_proto_rawDescGZIP(), []int{77} } func (x *NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) GetError() *RPCError { @@ -4479,7 +4579,7 @@ type VirtualSelectedParentBlueScoreChangedNotificationMessage struct { func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) Reset() { *x = VirtualSelectedParentBlueScoreChangedNotificationMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[76] + mi := &file_rpc_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4492,7 +4592,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) String() stri func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoMessage() {} func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[76] + mi := &file_rpc_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4505,7 +4605,7 @@ func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) ProtoReflect( // Deprecated: Use VirtualSelectedParentBlueScoreChangedNotificationMessage.ProtoReflect.Descriptor instead. func (*VirtualSelectedParentBlueScoreChangedNotificationMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{76} + return file_rpc_proto_rawDescGZIP(), []int{78} } func (x *VirtualSelectedParentBlueScoreChangedNotificationMessage) GetVirtualSelectedParentBlueScore() uint64 { @@ -4527,7 +4627,7 @@ type BanRequestMessage struct { func (x *BanRequestMessage) Reset() { *x = BanRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[77] + mi := &file_rpc_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4540,7 +4640,7 @@ func (x *BanRequestMessage) String() string { func (*BanRequestMessage) ProtoMessage() {} func (x *BanRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[77] + mi := &file_rpc_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4553,7 +4653,7 @@ func (x *BanRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BanRequestMessage.ProtoReflect.Descriptor instead. func (*BanRequestMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{77} + return file_rpc_proto_rawDescGZIP(), []int{79} } func (x *BanRequestMessage) GetIp() string { @@ -4574,7 +4674,7 @@ type BanResponseMessage struct { func (x *BanResponseMessage) Reset() { *x = BanResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[78] + mi := &file_rpc_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4587,7 +4687,7 @@ func (x *BanResponseMessage) String() string { func (*BanResponseMessage) ProtoMessage() {} func (x *BanResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[78] + mi := &file_rpc_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4600,7 +4700,7 @@ func (x *BanResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use BanResponseMessage.ProtoReflect.Descriptor instead. func (*BanResponseMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{78} + return file_rpc_proto_rawDescGZIP(), []int{80} } func (x *BanResponseMessage) GetError() *RPCError { @@ -4622,7 +4722,7 @@ type UnbanRequestMessage struct { func (x *UnbanRequestMessage) Reset() { *x = UnbanRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[79] + mi := &file_rpc_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4635,7 +4735,7 @@ func (x *UnbanRequestMessage) String() string { func (*UnbanRequestMessage) ProtoMessage() {} func (x *UnbanRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[79] + mi := &file_rpc_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4648,7 +4748,7 @@ func (x *UnbanRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbanRequestMessage.ProtoReflect.Descriptor instead. func (*UnbanRequestMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{79} + return file_rpc_proto_rawDescGZIP(), []int{81} } func (x *UnbanRequestMessage) GetIp() string { @@ -4669,7 +4769,7 @@ type UnbanResponseMessage struct { func (x *UnbanResponseMessage) Reset() { *x = UnbanResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[80] + mi := &file_rpc_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4682,7 +4782,7 @@ func (x *UnbanResponseMessage) String() string { func (*UnbanResponseMessage) ProtoMessage() {} func (x *UnbanResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[80] + mi := &file_rpc_proto_msgTypes[82] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4695,7 +4795,7 @@ func (x *UnbanResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbanResponseMessage.ProtoReflect.Descriptor instead. func (*UnbanResponseMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{80} + return file_rpc_proto_rawDescGZIP(), []int{82} } func (x *UnbanResponseMessage) GetError() *RPCError { @@ -4715,7 +4815,7 @@ type GetInfoRequestMessage struct { func (x *GetInfoRequestMessage) Reset() { *x = GetInfoRequestMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[81] + mi := &file_rpc_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4728,7 +4828,7 @@ func (x *GetInfoRequestMessage) String() string { func (*GetInfoRequestMessage) ProtoMessage() {} func (x *GetInfoRequestMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[81] + mi := &file_rpc_proto_msgTypes[83] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4741,7 +4841,7 @@ func (x *GetInfoRequestMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoRequestMessage.ProtoReflect.Descriptor instead. func (*GetInfoRequestMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{81} + return file_rpc_proto_rawDescGZIP(), []int{83} } type GetInfoResponseMessage struct { @@ -4756,7 +4856,7 @@ type GetInfoResponseMessage struct { func (x *GetInfoResponseMessage) Reset() { *x = GetInfoResponseMessage{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_proto_msgTypes[82] + mi := &file_rpc_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4769,7 +4869,7 @@ func (x *GetInfoResponseMessage) String() string { func (*GetInfoResponseMessage) ProtoMessage() {} func (x *GetInfoResponseMessage) ProtoReflect() protoreflect.Message { - mi := &file_rpc_proto_msgTypes[82] + mi := &file_rpc_proto_msgTypes[84] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4782,7 +4882,7 @@ func (x *GetInfoResponseMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoResponseMessage.ProtoReflect.Descriptor instead. func (*GetInfoResponseMessage) Descriptor() ([]byte, []int) { - return file_rpc_proto_rawDescGZIP(), []int{82} + return file_rpc_proto_rawDescGZIP(), []int{84} } func (x *GetInfoResponseMessage) GetP2PId() string { @@ -5299,131 +5399,141 @@ var file_rpc_proto_rawDesc = []byte{ 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x75, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x22, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, - 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, - 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x9f, - 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, - 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, - 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, - 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, 0x70, - 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, - 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xb7, - 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, - 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, - 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, 0x6f, - 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, - 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x22, - 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, + 0x22, 0x47, 0x0a, 0x27, 0x53, 0x74, 0x6f, 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, + 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x28, 0x53, 0x74, 0x6f, + 0x70, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0xab, 0x02, 0x0a, 0x0e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, + 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, + 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 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, 0x05, 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, 0x06, 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, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, + 0x9f, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, + 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, + 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x22, 0x58, 0x0a, 0x12, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x77, 0x0a, 0x14, 0x52, + 0x70, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x52, 0x70, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x0b, 0x52, 0x70, 0x63, 0x4f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, + 0xb7, 0x01, 0x0a, 0x0c, 0x52, 0x70, 0x63, 0x55, 0x74, 0x78, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0f, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x70, + 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x52, 0x0f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x43, + 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, + 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x21, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x31, 0x0a, 0x2f, 0x47, 0x65, - 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, 0x0a, - 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, - 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, + 0x22, 0x47, 0x65, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, + 0x2e, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x42, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 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, 0x3b, 0x0a, 0x39, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x31, 0x0a, 0x2f, 0x47, + 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x7c, + 0x0a, 0x30, 0x47, 0x65, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 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, 0x3b, 0x0a, 0x39, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x3a, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, - 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, 0x12, - 0x42, 0x61, 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, 0x25, - 0x0a, 0x13, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 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, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x70, 0x32, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, 0x70, - 0x49, 0x64, 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, 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, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 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, 0x82, 0x01, 0x0a, 0x38, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, + 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x46, 0x0a, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, + 0x6c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, + 0x6c, 0x75, 0x65, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x42, 0x61, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x40, 0x0a, + 0x12, 0x42, 0x61, 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, + 0x25, 0x0a, 0x13, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x62, 0x61, 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, 0x17, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x5a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x70, 0x32, 0x70, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x32, + 0x70, 0x49, 0x64, 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, 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 ( @@ -5439,7 +5549,7 @@ func file_rpc_proto_rawDescGZIP() []byte { } var file_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 83) +var file_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 85) var file_rpc_proto_goTypes = []interface{}{ (SubmitBlockResponseMessage_RejectReason)(0), // 0: protowire.SubmitBlockResponseMessage.RejectReason (*RPCError)(nil), // 1: protowire.RPCError @@ -5506,36 +5616,38 @@ var file_rpc_proto_goTypes = []interface{}{ (*NotifyUtxosChangedResponseMessage)(nil), // 62: protowire.NotifyUtxosChangedResponseMessage (*UtxosChangedNotificationMessage)(nil), // 63: protowire.UtxosChangedNotificationMessage (*UtxosByAddressesEntry)(nil), // 64: protowire.UtxosByAddressesEntry - (*RpcTransaction)(nil), // 65: protowire.RpcTransaction - (*RpcTransactionInput)(nil), // 66: protowire.RpcTransactionInput - (*RpcScriptPublicKey)(nil), // 67: protowire.RpcScriptPublicKey - (*RpcTransactionOutput)(nil), // 68: protowire.RpcTransactionOutput - (*RpcOutpoint)(nil), // 69: protowire.RpcOutpoint - (*RpcUtxoEntry)(nil), // 70: protowire.RpcUtxoEntry - (*GetUtxosByAddressesRequestMessage)(nil), // 71: protowire.GetUtxosByAddressesRequestMessage - (*GetUtxosByAddressesResponseMessage)(nil), // 72: protowire.GetUtxosByAddressesResponseMessage - (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 73: protowire.GetVirtualSelectedParentBlueScoreRequestMessage - (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 74: protowire.GetVirtualSelectedParentBlueScoreResponseMessage - (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 75: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage - (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 76: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage - (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 77: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage - (*BanRequestMessage)(nil), // 78: protowire.BanRequestMessage - (*BanResponseMessage)(nil), // 79: protowire.BanResponseMessage - (*UnbanRequestMessage)(nil), // 80: protowire.UnbanRequestMessage - (*UnbanResponseMessage)(nil), // 81: protowire.UnbanResponseMessage - (*GetInfoRequestMessage)(nil), // 82: protowire.GetInfoRequestMessage - (*GetInfoResponseMessage)(nil), // 83: protowire.GetInfoResponseMessage - (*BlockMessage)(nil), // 84: protowire.BlockMessage + (*StopNotifyingUtxosChangedRequestMessage)(nil), // 65: protowire.StopNotifyingUtxosChangedRequestMessage + (*StopNotifyingUtxosChangedResponseMessage)(nil), // 66: protowire.StopNotifyingUtxosChangedResponseMessage + (*RpcTransaction)(nil), // 67: protowire.RpcTransaction + (*RpcTransactionInput)(nil), // 68: protowire.RpcTransactionInput + (*RpcScriptPublicKey)(nil), // 69: protowire.RpcScriptPublicKey + (*RpcTransactionOutput)(nil), // 70: protowire.RpcTransactionOutput + (*RpcOutpoint)(nil), // 71: protowire.RpcOutpoint + (*RpcUtxoEntry)(nil), // 72: protowire.RpcUtxoEntry + (*GetUtxosByAddressesRequestMessage)(nil), // 73: protowire.GetUtxosByAddressesRequestMessage + (*GetUtxosByAddressesResponseMessage)(nil), // 74: protowire.GetUtxosByAddressesResponseMessage + (*GetVirtualSelectedParentBlueScoreRequestMessage)(nil), // 75: protowire.GetVirtualSelectedParentBlueScoreRequestMessage + (*GetVirtualSelectedParentBlueScoreResponseMessage)(nil), // 76: protowire.GetVirtualSelectedParentBlueScoreResponseMessage + (*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage)(nil), // 77: protowire.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + (*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage)(nil), // 78: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage + (*VirtualSelectedParentBlueScoreChangedNotificationMessage)(nil), // 79: protowire.VirtualSelectedParentBlueScoreChangedNotificationMessage + (*BanRequestMessage)(nil), // 80: protowire.BanRequestMessage + (*BanResponseMessage)(nil), // 81: protowire.BanResponseMessage + (*UnbanRequestMessage)(nil), // 82: protowire.UnbanRequestMessage + (*UnbanResponseMessage)(nil), // 83: protowire.UnbanResponseMessage + (*GetInfoRequestMessage)(nil), // 84: protowire.GetInfoRequestMessage + (*GetInfoResponseMessage)(nil), // 85: protowire.GetInfoResponseMessage + (*BlockMessage)(nil), // 86: protowire.BlockMessage } var file_rpc_proto_depIdxs = []int32{ 1, // 0: protowire.GetCurrentNetworkResponseMessage.error:type_name -> protowire.RPCError - 84, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage + 86, // 1: protowire.SubmitBlockRequestMessage.block:type_name -> protowire.BlockMessage 0, // 2: protowire.SubmitBlockResponseMessage.rejectReason:type_name -> protowire.SubmitBlockResponseMessage.RejectReason 1, // 3: protowire.SubmitBlockResponseMessage.error:type_name -> protowire.RPCError - 84, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage + 86, // 4: protowire.GetBlockTemplateResponseMessage.blockMessage:type_name -> protowire.BlockMessage 1, // 5: protowire.GetBlockTemplateResponseMessage.error:type_name -> protowire.RPCError 1, // 6: protowire.NotifyBlockAddedResponseMessage.error:type_name -> protowire.RPCError - 84, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage + 86, // 7: protowire.BlockAddedNotificationMessage.block:type_name -> protowire.BlockMessage 35, // 8: protowire.BlockAddedNotificationMessage.blockVerboseData:type_name -> protowire.BlockVerboseData 13, // 9: protowire.GetPeerAddressesResponseMessage.addresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage 13, // 10: protowire.GetPeerAddressesResponseMessage.bannedAddresses:type_name -> protowire.GetPeerAddressesKnownAddressMessage @@ -5549,7 +5661,7 @@ var file_rpc_proto_depIdxs = []int32{ 23, // 18: protowire.GetConnectedPeerInfoResponseMessage.infos:type_name -> protowire.GetConnectedPeerInfoMessage 1, // 19: protowire.GetConnectedPeerInfoResponseMessage.error:type_name -> protowire.RPCError 1, // 20: protowire.AddPeerResponseMessage.error:type_name -> protowire.RPCError - 65, // 21: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction + 67, // 21: protowire.SubmitTransactionRequestMessage.transaction:type_name -> protowire.RpcTransaction 1, // 22: protowire.SubmitTransactionResponseMessage.error:type_name -> protowire.RPCError 1, // 23: protowire.NotifyVirtualSelectedParentChainChangedResponseMessage.error:type_name -> protowire.RPCError 31, // 24: protowire.VirtualSelectedParentChainChangedNotificationMessage.addedChainBlocks:type_name -> protowire.ChainBlock @@ -5575,25 +5687,26 @@ var file_rpc_proto_depIdxs = []int32{ 1, // 44: protowire.NotifyUtxosChangedResponseMessage.error:type_name -> protowire.RPCError 64, // 45: protowire.UtxosChangedNotificationMessage.added:type_name -> protowire.UtxosByAddressesEntry 64, // 46: protowire.UtxosChangedNotificationMessage.removed:type_name -> protowire.UtxosByAddressesEntry - 69, // 47: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint - 70, // 48: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry - 66, // 49: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput - 68, // 50: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput - 69, // 51: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint - 67, // 52: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 67, // 53: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey - 64, // 54: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry - 1, // 55: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError - 1, // 56: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError - 1, // 57: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError - 1, // 58: protowire.BanResponseMessage.error:type_name -> protowire.RPCError - 1, // 59: protowire.UnbanResponseMessage.error:type_name -> protowire.RPCError - 1, // 60: protowire.GetInfoResponseMessage.error:type_name -> protowire.RPCError - 61, // [61:61] is the sub-list for method output_type - 61, // [61:61] is the sub-list for method input_type - 61, // [61:61] is the sub-list for extension type_name - 61, // [61:61] is the sub-list for extension extendee - 0, // [0:61] is the sub-list for field type_name + 71, // 47: protowire.UtxosByAddressesEntry.outpoint:type_name -> protowire.RpcOutpoint + 72, // 48: protowire.UtxosByAddressesEntry.utxoEntry:type_name -> protowire.RpcUtxoEntry + 1, // 49: protowire.StopNotifyingUtxosChangedResponseMessage.error:type_name -> protowire.RPCError + 68, // 50: protowire.RpcTransaction.inputs:type_name -> protowire.RpcTransactionInput + 70, // 51: protowire.RpcTransaction.outputs:type_name -> protowire.RpcTransactionOutput + 71, // 52: protowire.RpcTransactionInput.previousOutpoint:type_name -> protowire.RpcOutpoint + 69, // 53: protowire.RpcTransactionOutput.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 69, // 54: protowire.RpcUtxoEntry.scriptPublicKey:type_name -> protowire.RpcScriptPublicKey + 64, // 55: protowire.GetUtxosByAddressesResponseMessage.entries:type_name -> protowire.UtxosByAddressesEntry + 1, // 56: protowire.GetUtxosByAddressesResponseMessage.error:type_name -> protowire.RPCError + 1, // 57: protowire.GetVirtualSelectedParentBlueScoreResponseMessage.error:type_name -> protowire.RPCError + 1, // 58: protowire.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.error:type_name -> protowire.RPCError + 1, // 59: protowire.BanResponseMessage.error:type_name -> protowire.RPCError + 1, // 60: protowire.UnbanResponseMessage.error:type_name -> protowire.RPCError + 1, // 61: protowire.GetInfoResponseMessage.error:type_name -> protowire.RPCError + 62, // [62:62] is the sub-list for method output_type + 62, // [62:62] is the sub-list for method input_type + 62, // [62:62] is the sub-list for extension type_name + 62, // [62:62] is the sub-list for extension extendee + 0, // [0:62] is the sub-list for field type_name } func init() { file_rpc_proto_init() } @@ -6372,7 +6485,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransaction); i { + switch v := v.(*StopNotifyingUtxosChangedRequestMessage); i { case 0: return &v.state case 1: @@ -6384,7 +6497,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionInput); i { + switch v := v.(*StopNotifyingUtxosChangedResponseMessage); i { case 0: return &v.state case 1: @@ -6396,7 +6509,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcScriptPublicKey); i { + switch v := v.(*RpcTransaction); i { case 0: return &v.state case 1: @@ -6408,7 +6521,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcTransactionOutput); i { + switch v := v.(*RpcTransactionInput); i { case 0: return &v.state case 1: @@ -6420,7 +6533,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcOutpoint); i { + switch v := v.(*RpcScriptPublicKey); i { case 0: return &v.state case 1: @@ -6432,7 +6545,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RpcUtxoEntry); i { + switch v := v.(*RpcTransactionOutput); i { case 0: return &v.state case 1: @@ -6444,7 +6557,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesRequestMessage); i { + switch v := v.(*RpcOutpoint); i { case 0: return &v.state case 1: @@ -6456,7 +6569,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUtxosByAddressesResponseMessage); i { + switch v := v.(*RpcUtxoEntry); i { case 0: return &v.state case 1: @@ -6468,7 +6581,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { + switch v := v.(*GetUtxosByAddressesRequestMessage); i { case 0: return &v.state case 1: @@ -6480,7 +6593,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { + switch v := v.(*GetUtxosByAddressesResponseMessage); i { case 0: return &v.state case 1: @@ -6492,7 +6605,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreRequestMessage); i { case 0: return &v.state case 1: @@ -6504,7 +6617,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { + switch v := v.(*GetVirtualSelectedParentBlueScoreResponseMessage); i { case 0: return &v.state case 1: @@ -6516,7 +6629,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); i { case 0: return &v.state case 1: @@ -6528,7 +6641,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BanRequestMessage); i { + switch v := v.(*NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); i { case 0: return &v.state case 1: @@ -6540,7 +6653,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BanResponseMessage); i { + switch v := v.(*VirtualSelectedParentBlueScoreChangedNotificationMessage); i { case 0: return &v.state case 1: @@ -6552,7 +6665,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnbanRequestMessage); i { + switch v := v.(*BanRequestMessage); i { case 0: return &v.state case 1: @@ -6564,7 +6677,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnbanResponseMessage); i { + switch v := v.(*BanResponseMessage); i { case 0: return &v.state case 1: @@ -6576,7 +6689,7 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetInfoRequestMessage); i { + switch v := v.(*UnbanRequestMessage); i { case 0: return &v.state case 1: @@ -6588,6 +6701,30 @@ func file_rpc_proto_init() { } } file_rpc_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnbanResponseMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetInfoRequestMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetInfoResponseMessage); i { case 0: return &v.state @@ -6606,7 +6743,7 @@ func file_rpc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_proto_rawDesc, NumEnums: 1, - NumMessages: 83, + NumMessages: 85, NumExtensions: 0, NumServices: 0, }, diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto index 8e074ddeb..8ff4add42 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto @@ -450,6 +450,20 @@ message UtxosByAddressesEntry { RpcUtxoEntry utxoEntry = 3; } +// StopNotifyingUtxosChangedRequestMessage unregisters this connection for utxoChanged notifications +// for the given addresses. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: UtxosChangedNotificationMessage +message StopNotifyingUtxosChangedRequestMessage { + repeated string addresses = 1; +} + +message StopNotifyingUtxosChangedResponseMessage { + RPCError error = 1000; +} + message RpcTransaction { uint32 version = 1; repeated RpcTransactionInput inputs = 2; diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_stop_notifying_utxos_changed.go b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_stop_notifying_utxos_changed.go new file mode 100644 index 000000000..9717e920d --- /dev/null +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/rpc_stop_notifying_utxos_changed.go @@ -0,0 +1,39 @@ +package protowire + +import ( + "github.com/kaspanet/kaspad/app/appmessage" +) + +func (x *KaspadMessage_StopNotifyingUtxosChangedRequest) toAppMessage() (appmessage.Message, error) { + return &appmessage.StopNotifyingUTXOsChangedRequestMessage{ + Addresses: x.StopNotifyingUtxosChangedRequest.Addresses, + }, nil +} + +func (x *KaspadMessage_StopNotifyingUtxosChangedRequest) fromAppMessage(message *appmessage.StopNotifyingUTXOsChangedRequestMessage) error { + x.StopNotifyingUtxosChangedRequest = &StopNotifyingUtxosChangedRequestMessage{ + Addresses: message.Addresses, + } + return nil +} + +func (x *KaspadMessage_StopNotifyingUtxosChangedResponse) toAppMessage() (appmessage.Message, error) { + var err *appmessage.RPCError + if x.StopNotifyingUtxosChangedResponse.Error != nil { + err = &appmessage.RPCError{Message: x.StopNotifyingUtxosChangedResponse.Error.Message} + } + return &appmessage.StopNotifyingUTXOsChangedResponseMessage{ + Error: err, + }, nil +} + +func (x *KaspadMessage_StopNotifyingUtxosChangedResponse) fromAppMessage(message *appmessage.StopNotifyingUTXOsChangedResponseMessage) error { + var err *RPCError + if message.Error != nil { + err = &RPCError{Message: message.Error.Message} + } + x.StopNotifyingUtxosChangedResponse = &StopNotifyingUtxosChangedResponseMessage{ + Error: err, + } + return nil +} diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go index 89fad67ae..0bee7335e 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/wire.go @@ -643,6 +643,20 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) { return nil, err } return payload, nil + case *appmessage.StopNotifyingUTXOsChangedRequestMessage: + payload := new(KaspadMessage_StopNotifyingUtxosChangedRequest) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil + case *appmessage.StopNotifyingUTXOsChangedResponseMessage: + payload := new(KaspadMessage_StopNotifyingUtxosChangedResponse) + err := payload.fromAppMessage(message) + if err != nil { + return nil, err + } + return payload, nil case *appmessage.GetUTXOsByAddressesRequestMessage: payload := new(KaspadMessage_GetUtxosByAddressesRequest) err := payload.fromAppMessage(message) From a581dea1271075615d031a61a13fec92f822b2db Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 14 Feb 2021 18:13:20 +0200 Subject: [PATCH 334/351] Remove unused utils and structures (#1526) * Remove unused utils * Remove unneeded randomness from tests * Remove more unused functions * Remove unused protobuf structures * Fix small errors --- app/appmessage/p2p_msgblockheader_test.go | 6 +- app/appmessage/p2p_msgping_test.go | 7 +- app/appmessage/p2p_msgpong_test.go | 7 +- app/rpc/rpccontext/verbosedata.go | 3 +- .../database/serialization/dbobjects.pb.go | 220 ++++-------------- .../database/serialization/dbobjects.proto | 8 - .../database/serialization/header_tips.go | 17 -- .../pruningstore/pruningstore.go | 14 -- domain/consensus/utils/hashes/to_big.go | 21 -- .../consensus/utils/txscript/standard_test.go | 2 +- .../grpcserver/protowire/messages_grpc.pb.go | 28 ++- infrastructure/os/limits/limits_unix.go | 2 - util/bech32/internal_test.go | 2 +- util/certgen.go | 143 ------------ util/certgen_test.go | 123 ---------- util/fs/fs.go | 13 -- util/locks/prioritymutex.go | 79 ------- util/locks/prioritymutex_test.go | 80 ------- util/locks/waitgroup.go | 108 --------- util/locks/waitgroup_test.go | 213 ----------------- util/net.go | 18 -- util/net_noop.go | 19 -- util/pointers/copytopointer.go | 73 ------ util/pointers/copytopointer_test.go | 113 --------- util/random/random.go | 22 +- util/random/random_test.go | 7 +- util/strings.go | 69 ------ util/strings_test.go | 61 ----- util/testtools/testtools.go | 23 -- util/util.go | 18 -- 30 files changed, 85 insertions(+), 1434 deletions(-) delete mode 100644 domain/consensus/database/serialization/header_tips.go delete mode 100644 domain/consensus/utils/hashes/to_big.go delete mode 100644 util/certgen.go delete mode 100644 util/certgen_test.go delete mode 100644 util/fs/fs.go delete mode 100644 util/locks/prioritymutex.go delete mode 100644 util/locks/prioritymutex_test.go delete mode 100644 util/locks/waitgroup.go delete mode 100644 util/locks/waitgroup_test.go delete mode 100644 util/net.go delete mode 100644 util/net_noop.go delete mode 100644 util/pointers/copytopointer.go delete mode 100644 util/pointers/copytopointer_test.go delete mode 100644 util/strings.go delete mode 100644 util/strings_test.go delete mode 100644 util/testtools/testtools.go delete mode 100644 util/util.go diff --git a/app/appmessage/p2p_msgblockheader_test.go b/app/appmessage/p2p_msgblockheader_test.go index ebc4bc973..7a3d049ef 100644 --- a/app/appmessage/p2p_msgblockheader_test.go +++ b/app/appmessage/p2p_msgblockheader_test.go @@ -11,15 +11,11 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/util/mstime" - "github.com/kaspanet/kaspad/util/random" ) // TestBlockHeader tests the MsgBlockHeader API. func TestBlockHeader(t *testing.T) { - nonce, err := random.Uint64() - if err != nil { - t.Errorf("random.Uint64: Error generating nonce: %v", err) - } + nonce := uint64(0xba4d87a69924a93d) hashes := []*externalapi.DomainHash{mainnetGenesisHash, simnetGenesisHash} diff --git a/app/appmessage/p2p_msgping_test.go b/app/appmessage/p2p_msgping_test.go index 05459169a..c3a8bd3b3 100644 --- a/app/appmessage/p2p_msgping_test.go +++ b/app/appmessage/p2p_msgping_test.go @@ -6,17 +6,12 @@ package appmessage import ( "testing" - - "github.com/kaspanet/kaspad/util/random" ) // TestPing tests the MsgPing API against the latest protocol version. func TestPing(t *testing.T) { // Ensure we get the same nonce back out. - nonce, err := random.Uint64() - if err != nil { - t.Errorf("random.Uint64: Error generating nonce: %v", err) - } + nonce := uint64(0x61c2c5535902862) msg := NewMsgPing(nonce) if msg.Nonce != nonce { t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", diff --git a/app/appmessage/p2p_msgpong_test.go b/app/appmessage/p2p_msgpong_test.go index 47400c139..1fa00104e 100644 --- a/app/appmessage/p2p_msgpong_test.go +++ b/app/appmessage/p2p_msgpong_test.go @@ -6,16 +6,11 @@ package appmessage import ( "testing" - - "github.com/kaspanet/kaspad/util/random" ) // TestPongLatest tests the MsgPong API against the latest protocol version. func TestPongLatest(t *testing.T) { - nonce, err := random.Uint64() - if err != nil { - t.Errorf("random.Uint64: error generating nonce: %v", err) - } + nonce := uint64(0x1a05b581a5182c) msg := NewMsgPong(nonce) if msg.Nonce != nonce { t.Errorf("NewMsgPong: wrong nonce - got %v, want %v", diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index b6dbd8944..181ef47e4 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -21,7 +21,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/dagconfig" - "github.com/kaspanet/kaspad/util/pointers" ) // BuildBlockVerboseData builds a BlockVerboseData from the given blockHeader. @@ -179,7 +178,7 @@ func (ctx *Context) buildTransactionVerboseOutputs(tx *externalapi.DomainTransac passesFilter := len(filterAddrMap) == 0 var encodedAddr string if addr != nil { - encodedAddr = *pointers.String(addr.EncodeAddress()) + encodedAddr = addr.EncodeAddress() // If the filter doesn't already pass, make it pass if // the address exists in the filter. diff --git a/domain/consensus/database/serialization/dbobjects.pb.go b/domain/consensus/database/serialization/dbobjects.pb.go index 2f5cfc592..2fa9f88dc 100644 --- a/domain/consensus/database/serialization/dbobjects.pb.go +++ b/domain/consensus/database/serialization/dbobjects.pb.go @@ -1473,100 +1473,6 @@ func (x *DbUtxoDiff) GetToRemove() []*DbUtxoCollectionItem { return nil } -type DbPruningPointUTXOSetBytes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Bytes []byte `protobuf:"bytes,1,opt,name=bytes,proto3" json:"bytes,omitempty"` -} - -func (x *DbPruningPointUTXOSetBytes) Reset() { - *x = DbPruningPointUTXOSetBytes{} - if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DbPruningPointUTXOSetBytes) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DbPruningPointUTXOSetBytes) ProtoMessage() {} - -func (x *DbPruningPointUTXOSetBytes) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DbPruningPointUTXOSetBytes.ProtoReflect.Descriptor instead. -func (*DbPruningPointUTXOSetBytes) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{24} -} - -func (x *DbPruningPointUTXOSetBytes) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -type DbHeaderTips struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Tips []*DbHash `protobuf:"bytes,1,rep,name=tips,proto3" json:"tips,omitempty"` -} - -func (x *DbHeaderTips) Reset() { - *x = DbHeaderTips{} - if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DbHeaderTips) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DbHeaderTips) ProtoMessage() {} - -func (x *DbHeaderTips) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DbHeaderTips.ProtoReflect.Descriptor instead. -func (*DbHeaderTips) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{25} -} - -func (x *DbHeaderTips) GetTips() []*DbHash { - if x != nil { - return x.Tips - } - return nil -} - type DbTips struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1578,7 +1484,7 @@ type DbTips struct { func (x *DbTips) Reset() { *x = DbTips{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[26] + mi := &file_dbobjects_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1591,7 +1497,7 @@ func (x *DbTips) String() string { func (*DbTips) ProtoMessage() {} func (x *DbTips) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[26] + mi := &file_dbobjects_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1604,7 +1510,7 @@ func (x *DbTips) ProtoReflect() protoreflect.Message { // Deprecated: Use DbTips.ProtoReflect.Descriptor instead. func (*DbTips) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{26} + return file_dbobjects_proto_rawDescGZIP(), []int{24} } func (x *DbTips) GetTips() []*DbHash { @@ -1625,7 +1531,7 @@ type DbVirtualDiffParents struct { func (x *DbVirtualDiffParents) Reset() { *x = DbVirtualDiffParents{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[27] + mi := &file_dbobjects_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1638,7 +1544,7 @@ func (x *DbVirtualDiffParents) String() string { func (*DbVirtualDiffParents) ProtoMessage() {} func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[27] + mi := &file_dbobjects_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1651,7 +1557,7 @@ func (x *DbVirtualDiffParents) ProtoReflect() protoreflect.Message { // Deprecated: Use DbVirtualDiffParents.ProtoReflect.Descriptor instead. func (*DbVirtualDiffParents) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{27} + return file_dbobjects_proto_rawDescGZIP(), []int{25} } func (x *DbVirtualDiffParents) GetVirtualDiffParents() []*DbHash { @@ -1672,7 +1578,7 @@ type DbBlockCount struct { func (x *DbBlockCount) Reset() { *x = DbBlockCount{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[28] + mi := &file_dbobjects_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1685,7 +1591,7 @@ func (x *DbBlockCount) String() string { func (*DbBlockCount) ProtoMessage() {} func (x *DbBlockCount) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[28] + mi := &file_dbobjects_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1698,7 +1604,7 @@ func (x *DbBlockCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DbBlockCount.ProtoReflect.Descriptor instead. func (*DbBlockCount) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{28} + return file_dbobjects_proto_rawDescGZIP(), []int{26} } func (x *DbBlockCount) GetCount() uint64 { @@ -1719,7 +1625,7 @@ type DbBlockHeaderCount struct { func (x *DbBlockHeaderCount) Reset() { *x = DbBlockHeaderCount{} if protoimpl.UnsafeEnabled { - mi := &file_dbobjects_proto_msgTypes[29] + mi := &file_dbobjects_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1732,7 +1638,7 @@ func (x *DbBlockHeaderCount) String() string { func (*DbBlockHeaderCount) ProtoMessage() {} func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { - mi := &file_dbobjects_proto_msgTypes[29] + mi := &file_dbobjects_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1745,7 +1651,7 @@ func (x *DbBlockHeaderCount) ProtoReflect() protoreflect.Message { // Deprecated: Use DbBlockHeaderCount.ProtoReflect.Descriptor instead. func (*DbBlockHeaderCount) Descriptor() ([]byte, []int) { - return file_dbobjects_proto_rawDescGZIP(), []int{29} + return file_dbobjects_proto_rawDescGZIP(), []int{27} } func (x *DbBlockHeaderCount) GetCount() uint64 { @@ -1981,32 +1887,25 @@ var file_dbobjects_proto_rawDesc = []byte{ 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x55, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, - 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x44, - 0x62, 0x50, 0x72, 0x75, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x54, 0x58, - 0x4f, 0x53, 0x65, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, - 0x39, 0x0a, 0x0c, 0x44, 0x62, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x54, 0x69, 0x70, 0x73, 0x12, - 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, - 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, 0x33, 0x0a, 0x06, 0x44, 0x62, - 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, 0x22, - 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, - 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x6d, 0x52, 0x08, 0x74, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x33, 0x0a, 0x06, 0x44, + 0x62, 0x54, 0x69, 0x70, 0x73, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x24, - 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x42, 0x2a, 0x5a, 0x28, 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, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x04, 0x74, 0x69, 0x70, 0x73, + 0x22, 0x5d, 0x0a, 0x14, 0x44, 0x62, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, + 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x45, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x62, 0x48, 0x61, 0x73, 0x68, 0x52, 0x12, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, + 0x24, 0x0a, 0x0c, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2a, 0x0a, 0x12, 0x44, 0x62, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x42, 0x2a, 0x5a, 0x28, 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, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2021,7 +1920,7 @@ func file_dbobjects_proto_rawDescGZIP() []byte { return file_dbobjects_proto_rawDescData } -var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_dbobjects_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_dbobjects_proto_goTypes = []interface{}{ (*DbBlock)(nil), // 0: serialization.DbBlock (*DbBlockHeader)(nil), // 1: serialization.DbBlockHeader @@ -2047,12 +1946,10 @@ var file_dbobjects_proto_goTypes = []interface{}{ (*DbReachabilityData)(nil), // 21: serialization.DbReachabilityData (*DbReachabilityInterval)(nil), // 22: serialization.DbReachabilityInterval (*DbUtxoDiff)(nil), // 23: serialization.DbUtxoDiff - (*DbPruningPointUTXOSetBytes)(nil), // 24: serialization.DbPruningPointUTXOSetBytes - (*DbHeaderTips)(nil), // 25: serialization.DbHeaderTips - (*DbTips)(nil), // 26: serialization.DbTips - (*DbVirtualDiffParents)(nil), // 27: serialization.DbVirtualDiffParents - (*DbBlockCount)(nil), // 28: serialization.DbBlockCount - (*DbBlockHeaderCount)(nil), // 29: serialization.DbBlockHeaderCount + (*DbTips)(nil), // 24: serialization.DbTips + (*DbVirtualDiffParents)(nil), // 25: serialization.DbVirtualDiffParents + (*DbBlockCount)(nil), // 26: serialization.DbBlockCount + (*DbBlockHeaderCount)(nil), // 27: serialization.DbBlockHeaderCount } var file_dbobjects_proto_depIdxs = []int32{ 1, // 0: serialization.DbBlock.header:type_name -> serialization.DbBlockHeader @@ -2090,14 +1987,13 @@ var file_dbobjects_proto_depIdxs = []int32{ 2, // 32: serialization.DbReachabilityData.futureCoveringSet:type_name -> serialization.DbHash 18, // 33: serialization.DbUtxoDiff.toAdd:type_name -> serialization.DbUtxoCollectionItem 18, // 34: serialization.DbUtxoDiff.toRemove:type_name -> serialization.DbUtxoCollectionItem - 2, // 35: serialization.DbHeaderTips.tips:type_name -> serialization.DbHash - 2, // 36: serialization.DbTips.tips:type_name -> serialization.DbHash - 2, // 37: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash - 38, // [38:38] is the sub-list for method output_type - 38, // [38:38] is the sub-list for method input_type - 38, // [38:38] is the sub-list for extension type_name - 38, // [38:38] is the sub-list for extension extendee - 0, // [0:38] is the sub-list for field type_name + 2, // 35: serialization.DbTips.tips:type_name -> serialization.DbHash + 2, // 36: serialization.DbVirtualDiffParents.virtualDiffParents:type_name -> serialization.DbHash + 37, // [37:37] is the sub-list for method output_type + 37, // [37:37] is the sub-list for method input_type + 37, // [37:37] is the sub-list for extension type_name + 37, // [37:37] is the sub-list for extension extendee + 0, // [0:37] is the sub-list for field type_name } func init() { file_dbobjects_proto_init() } @@ -2395,30 +2291,6 @@ func file_dbobjects_proto_init() { } } file_dbobjects_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbPruningPointUTXOSetBytes); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_dbobjects_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DbHeaderTips); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_dbobjects_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbTips); i { case 0: return &v.state @@ -2430,7 +2302,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbVirtualDiffParents); i { case 0: return &v.state @@ -2442,7 +2314,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbBlockCount); i { case 0: return &v.state @@ -2454,7 +2326,7 @@ func file_dbobjects_proto_init() { return nil } } - file_dbobjects_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_dbobjects_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DbBlockHeaderCount); i { case 0: return &v.state @@ -2473,7 +2345,7 @@ func file_dbobjects_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_dbobjects_proto_rawDesc, NumEnums: 0, - NumMessages: 30, + NumMessages: 28, NumExtensions: 0, NumServices: 0, }, diff --git a/domain/consensus/database/serialization/dbobjects.proto b/domain/consensus/database/serialization/dbobjects.proto index 4f85e453c..f338e83c5 100644 --- a/domain/consensus/database/serialization/dbobjects.proto +++ b/domain/consensus/database/serialization/dbobjects.proto @@ -139,14 +139,6 @@ message DbUtxoDiff { repeated DbUtxoCollectionItem toRemove = 2; } -message DbPruningPointUTXOSetBytes { - bytes bytes = 1; -} - -message DbHeaderTips { - repeated DbHash tips = 1; -} - message DbTips { repeated DbHash tips = 1; } diff --git a/domain/consensus/database/serialization/header_tips.go b/domain/consensus/database/serialization/header_tips.go deleted file mode 100644 index 8855fba19..000000000 --- a/domain/consensus/database/serialization/header_tips.go +++ /dev/null @@ -1,17 +0,0 @@ -package serialization - -import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// HeaderTipsToDBHeaderTips converts a slice of hashes to DbHeaderTips -func HeaderTipsToDBHeaderTips(tips []*externalapi.DomainHash) *DbHeaderTips { - return &DbHeaderTips{ - Tips: DomainHashesToDbHashes(tips), - } -} - -// DBHeaderTipsToHeaderTips converts DbHeaderTips to a slice of hashes -func DBHeaderTipsToHeaderTips(dbHeaderTips *DbHeaderTips) ([]*externalapi.DomainHash, error) { - return DbHashesToDomainHashes(dbHeaderTips.Tips) -} diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index e2b9088e2..2031cc724 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -196,20 +196,6 @@ func (ps *pruningStore) deserializePruningPoint(pruningPointBytes []byte) (*exte return serialization.DbHashToDomainHash(dbHash) } -func (ps *pruningStore) serializeUTXOSetBytes(pruningPointUTXOSetBytes []byte) ([]byte, error) { - return proto.Marshal(&serialization.DbPruningPointUTXOSetBytes{Bytes: pruningPointUTXOSetBytes}) -} - -func (ps *pruningStore) deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes []byte) ([]byte, error) { - dbPruningPointUTXOSet := &serialization.DbPruningPointUTXOSetBytes{} - err := proto.Unmarshal(dbPruningPointUTXOSetBytes, dbPruningPointUTXOSet) - if err != nil { - return nil, err - } - - return dbPruningPointUTXOSet.Bytes, nil -} - func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader) (bool, error) { if ps.pruningPointStaging != nil { return true, nil diff --git a/domain/consensus/utils/hashes/to_big.go b/domain/consensus/utils/hashes/to_big.go deleted file mode 100644 index 6eedafed6..000000000 --- a/domain/consensus/utils/hashes/to_big.go +++ /dev/null @@ -1,21 +0,0 @@ -package hashes - -import ( - "math/big" - - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" -) - -// ToBig converts a externalapi.DomainHash into a big.Int that can be used to -// perform math comparisons. -func ToBig(hash *externalapi.DomainHash) *big.Int { - // A Hash is in little-endian, but the big package wants the bytes in - // big-endian, so reverse them. - buf := hash.ByteArray() - blen := len(buf) - for i := 0; i < blen/2; i++ { - buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] - } - - return new(big.Int).SetBytes(buf[:]) -} diff --git a/domain/consensus/utils/txscript/standard_test.go b/domain/consensus/utils/txscript/standard_test.go index a8a7f56e2..fe981b36a 100644 --- a/domain/consensus/utils/txscript/standard_test.go +++ b/domain/consensus/utils/txscript/standard_test.go @@ -312,7 +312,7 @@ func TestPayToAddrScript(t *testing.T) { // Taken from transaction: // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d - p2shMain, _ := util.NewAddressScriptHashFromHash(hexToBytes("e8c300"+ + p2shMain, err := util.NewAddressScriptHashFromHash(hexToBytes("e8c300"+ "c87986efa84c37c0519929019ef86eb5b4"), util.Bech32PrefixKaspa) if err != nil { t.Fatalf("Unable to create script hash address: %v", err) diff --git a/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go b/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go index 102e61cfd..3e0081ab8 100644 --- a/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go +++ b/infrastructure/network/netadapter/server/grpcserver/protowire/messages_grpc.pb.go @@ -11,7 +11,7 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 +const _ = grpc.SupportPackageIsVersion7 // P2PClient is the client API for P2P service. // @@ -71,12 +71,19 @@ type P2PServer interface { type UnimplementedP2PServer struct { } -func (*UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error { +func (UnimplementedP2PServer) MessageStream(P2P_MessageStreamServer) error { return status.Errorf(codes.Unimplemented, "method MessageStream not implemented") } -func (*UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {} +func (UnimplementedP2PServer) mustEmbedUnimplementedP2PServer() {} -func RegisterP2PServer(s *grpc.Server, srv P2PServer) { +// UnsafeP2PServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to P2PServer will +// result in compilation errors. +type UnsafeP2PServer interface { + mustEmbedUnimplementedP2PServer() +} + +func RegisterP2PServer(s grpc.ServiceRegistrar, srv P2PServer) { s.RegisterService(&_P2P_serviceDesc, srv) } @@ -179,12 +186,19 @@ type RPCServer interface { type UnimplementedRPCServer struct { } -func (*UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error { +func (UnimplementedRPCServer) MessageStream(RPC_MessageStreamServer) error { return status.Errorf(codes.Unimplemented, "method MessageStream not implemented") } -func (*UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {} +func (UnimplementedRPCServer) mustEmbedUnimplementedRPCServer() {} -func RegisterRPCServer(s *grpc.Server, srv RPCServer) { +// UnsafeRPCServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to RPCServer will +// result in compilation errors. +type UnsafeRPCServer interface { + mustEmbedUnimplementedRPCServer() +} + +func RegisterRPCServer(s grpc.ServiceRegistrar, srv RPCServer) { s.RegisterService(&_RPC_serviceDesc, srv) } diff --git a/infrastructure/os/limits/limits_unix.go b/infrastructure/os/limits/limits_unix.go index fc6ccbbd9..d993db9b9 100644 --- a/infrastructure/os/limits/limits_unix.go +++ b/infrastructure/os/limits/limits_unix.go @@ -12,8 +12,6 @@ import ( "github.com/pkg/errors" ) -const () - // SetLimits raises some process limits to values which allow kaspad and // associated utilities to run. func SetLimits(desiredLimits *DesiredLimits) error { diff --git a/util/bech32/internal_test.go b/util/bech32/internal_test.go index 8ee3a003b..898ed09b1 100644 --- a/util/bech32/internal_test.go +++ b/util/bech32/internal_test.go @@ -40,7 +40,7 @@ func TestBech32(t *testing.T) { if !test.valid { // Invalid string decoding should result in error. if err == nil { - t.Error("expected decoding to fail for "+ + t.Errorf("expected decoding to fail for "+ "invalid string %v", test.str) } continue diff --git a/util/certgen.go b/util/certgen.go deleted file mode 100644 index 5e03d1b5a..000000000 --- a/util/certgen.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package util - -import ( - "bytes" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - _ "crypto/sha512" // Needed for RegisterHash in init - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "github.com/pkg/errors" - "math/big" - "net" - "os" - "time" -) - -// NewTLSCertPair returns a new PEM-encoded x.509 certificate pair -// based on a 521-bit ECDSA private key. The machine's local interface -// addresses and all variants of IPv4 and IPv6 localhost are included as -// valid IP addresses. -func NewTLSCertPair(organization string, validUntil time.Time, extraHosts []string) (cert, key []byte, err error) { - now := time.Now() - if validUntil.Before(now) { - return nil, nil, errors.New("validUntil would create an already-expired certificate") - } - - priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) - if err != nil { - return nil, nil, err - } - - // end of ASN.1 time - endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) - if validUntil.After(endOfTime) { - validUntil = endOfTime - } - - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - return nil, nil, errors.Errorf("failed to generate serial number: %s", err) - } - - host, err := os.Hostname() - if err != nil { - return nil, nil, err - } - - ipAddresses := []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")} - dnsNames := []string{host} - if host != "localhost" { - dnsNames = append(dnsNames, "localhost") - } - - addIP := func(ipAddr net.IP) { - for _, ip := range ipAddresses { - if ip.Equal(ipAddr) { - return - } - } - ipAddresses = append(ipAddresses, ipAddr) - } - addHost := func(host string) { - for _, dnsName := range dnsNames { - if host == dnsName { - return - } - } - dnsNames = append(dnsNames, host) - } - - addrs, err := interfaceAddrs() - if err != nil { - return nil, nil, err - } - for _, a := range addrs { - ipAddr, _, err := net.ParseCIDR(a.String()) - if err == nil { - addIP(ipAddr) - } - } - - for _, hostStr := range extraHosts { - host, _, err := net.SplitHostPort(hostStr) - if err != nil { - host = hostStr - } - if ip := net.ParseIP(host); ip != nil { - addIP(ip) - } else { - addHost(host) - } - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{organization}, - CommonName: host, - }, - NotBefore: now.Add(-time.Hour * 24), - NotAfter: validUntil, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | - x509.KeyUsageCertSign, - IsCA: true, // so can sign self. - BasicConstraintsValid: true, - - DNSNames: dnsNames, - IPAddresses: ipAddresses, - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, - &template, &priv.PublicKey, priv) - if err != nil { - return nil, nil, errors.Errorf("failed to create certificate: %s", err) - } - - certBuf := &bytes.Buffer{} - err = pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - if err != nil { - return nil, nil, errors.Errorf("failed to encode certificate: %s", err) - } - - keybytes, err := x509.MarshalECPrivateKey(priv) - if err != nil { - return nil, nil, errors.Errorf("failed to marshal private key: %s", err) - } - - keyBuf := &bytes.Buffer{} - err = pem.Encode(keyBuf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keybytes}) - if err != nil { - return nil, nil, errors.Errorf("failed to encode private key: %s", err) - } - - return certBuf.Bytes(), keyBuf.Bytes(), nil -} diff --git a/util/certgen_test.go b/util/certgen_test.go deleted file mode 100644 index e90c75ac6..000000000 --- a/util/certgen_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package util_test - -import ( - "crypto/x509" - "encoding/pem" - "net" - "testing" - "time" - - "github.com/kaspanet/kaspad/util" - //"github.com/davecgh/go-spew/spew" -) - -// TestNewTLSCertPair ensures the NewTLSCertPair function works as expected. -func TestNewTLSCertPair(t *testing.T) { - // Certs don't support sub-second precision, so truncate it now to - // ensure the checks later don't fail due to nanosecond precision - // differences. - validUntil := time.Unix(time.Now().Add(10*365*24*time.Hour).Unix(), 0) - org := "test autogenerated cert" - extraHosts := []string{"testtlscert.bogus", "localhost", "127.0.0.1"} - cert, key, err := util.NewTLSCertPair(org, validUntil, extraHosts) - if err != nil { - t.Fatalf("failed with unexpected error: %v", err) - } - - // Ensure the PEM-encoded cert that is returned can be decoded. - pemCert, _ := pem.Decode(cert) - if pemCert == nil { - t.Fatalf("pem.Decode was unable to decode the certificate") - } - - // Ensure the PEM-encoded key that is returned can be decoded. - pemKey, _ := pem.Decode(key) - if pemCert == nil { - t.Fatalf("pem.Decode was unable to decode the key") - } - - // Ensure the DER-encoded key bytes can be successfully parsed. - _, err = x509.ParseECPrivateKey(pemKey.Bytes) - if err != nil { - t.Fatalf("failed with unexpected error: %v", err) - } - - // Ensure the DER-encoded cert bytes can be successfully into an X.509 - // certificate. - x509Cert, err := x509.ParseCertificate(pemCert.Bytes) - if err != nil { - t.Fatalf("failed with unexpected error: %v", err) - } - - // Ensure the specified organization is correct. - x509Orgs := x509Cert.Subject.Organization - if len(x509Orgs) == 0 || x509Orgs[0] != org { - x509Org := "" - if len(x509Orgs) > 0 { - x509Org = x509Orgs[0] - } - t.Fatalf("generated cert organization field mismatch, got "+ - "'%v', want '%v'", x509Org, org) - } - - // Ensure the specified valid until value is correct. - if !x509Cert.NotAfter.Equal(validUntil) { - t.Fatalf("generated cert valid until field mismatch, got %v, "+ - "want %v", x509Cert.NotAfter, validUntil) - } - - // Ensure the specified extra hosts are present. - for _, host := range extraHosts { - if err := x509Cert.VerifyHostname(host); err != nil { - t.Fatalf("failed to verify extra host '%s'", host) - } - } - - // Ensure that the Common Name is also the first SAN DNS name. - cn := x509Cert.Subject.CommonName - san0 := x509Cert.DNSNames[0] - if cn != san0 { - t.Errorf("common name %s does not match first SAN %s", cn, san0) - } - - // Ensure there are no duplicate hosts or IPs. - hostCounts := make(map[string]int) - for _, host := range x509Cert.DNSNames { - hostCounts[host]++ - } - ipCounts := make(map[string]int) - for _, ip := range x509Cert.IPAddresses { - ipCounts[string(ip)]++ - } - for host, count := range hostCounts { - if count != 1 { - t.Errorf("host %s appears %d times in certificate", host, count) - } - } - for ipStr, count := range ipCounts { - if count != 1 { - t.Errorf("ip %s appears %d times in certificate", net.IP(ipStr), count) - } - } - - // Ensure the cert can be use for the intended purposes. - if !x509Cert.IsCA { - t.Fatal("generated cert is not a certificate authority") - } - if x509Cert.KeyUsage&x509.KeyUsageKeyEncipherment == 0 { - t.Fatal("generated cert can't be used for key encipherment") - } - if x509Cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 { - t.Fatal("generated cert can't be used for digital signatures") - } - if x509Cert.KeyUsage&x509.KeyUsageCertSign == 0 { - t.Fatal("generated cert can't be used for signing other certs") - } - if !x509Cert.BasicConstraintsValid { - t.Fatal("generated cert does not have valid basic constraints") - } -} diff --git a/util/fs/fs.go b/util/fs/fs.go deleted file mode 100644 index 63aab315f..000000000 --- a/util/fs/fs.go +++ /dev/null @@ -1,13 +0,0 @@ -package fs - -import "os" - -// FileExists reports whether the named file or directory exists. -func FileExists(name string) bool { - if _, err := os.Stat(name); err != nil { - if os.IsNotExist(err) { - return false - } - } - return true -} diff --git a/util/locks/prioritymutex.go b/util/locks/prioritymutex.go deleted file mode 100644 index 458094d5f..000000000 --- a/util/locks/prioritymutex.go +++ /dev/null @@ -1,79 +0,0 @@ -package locks - -import ( - "sync" -) - -// PriorityMutex is a read-write mutex with an additional low -// priority lock. It's implemented with the following -// components: -// * Data mutex: The actual lock on the data structure. Its -// type is sync.RWMutex for its high priority read lock. -// * High priority waiting group: A waiting group that is being -// incremented every time a high priority lock (read or write) -// is acquired, and decremented every time a high priority lock is -// unlocked. Low priority locks can start being held only -// when the waiting group is empty. -// * Low priority mutex: This mutex ensures that when the -// waiting group is empty, only one low priority lock -// will be able to lock the data mutex. - -// PriorityMutex implements a lock with three priorities: -// * High priority write lock - locks the mutex with the highest priority. -// * High priority read lock - locks the mutex with lower priority than -// the high priority write lock. Can be held concurrently with other -// with other read locks. -// * Low priority write lock - locks the mutex with lower priority then -// the read lock. -type PriorityMutex struct { - dataMutex sync.RWMutex - highPriorityWaiting *waitGroup - lowPriorityMutex sync.Mutex -} - -// NewPriorityMutex returns a new priority mutex -func NewPriorityMutex() *PriorityMutex { - lock := PriorityMutex{ - highPriorityWaiting: newWaitGroup(), - } - return &lock -} - -// LowPriorityWriteLock acquires a low-priority write lock. -func (mtx *PriorityMutex) LowPriorityWriteLock() { - mtx.lowPriorityMutex.Lock() - mtx.highPriorityWaiting.wait() - mtx.dataMutex.Lock() -} - -// LowPriorityWriteUnlock unlocks the low-priority write lock -func (mtx *PriorityMutex) LowPriorityWriteUnlock() { - mtx.dataMutex.Unlock() - mtx.lowPriorityMutex.Unlock() -} - -// HighPriorityWriteLock acquires a high-priority write lock. -func (mtx *PriorityMutex) HighPriorityWriteLock() { - mtx.highPriorityWaiting.add(1) - mtx.dataMutex.Lock() -} - -// HighPriorityWriteUnlock unlocks the high-priority write lock -func (mtx *PriorityMutex) HighPriorityWriteUnlock() { - mtx.dataMutex.Unlock() - mtx.highPriorityWaiting.done() -} - -// HighPriorityReadLock acquires a high-priority read -// lock. -func (mtx *PriorityMutex) HighPriorityReadLock() { - mtx.highPriorityWaiting.add(1) - mtx.dataMutex.RLock() -} - -// HighPriorityReadUnlock unlocks the high-priority read -// lock -func (mtx *PriorityMutex) HighPriorityReadUnlock() { - mtx.highPriorityWaiting.done() - mtx.dataMutex.RUnlock() -} diff --git a/util/locks/prioritymutex_test.go b/util/locks/prioritymutex_test.go deleted file mode 100644 index 2f161a14f..000000000 --- a/util/locks/prioritymutex_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package locks - -import ( - "reflect" - "sync" - "testing" - "time" -) - -func TestPriorityMutex(t *testing.T) { - mtx := NewPriorityMutex() - sharedSlice := []int{} - lowPriorityLockAcquired := false - wg := sync.WaitGroup{} - wg.Add(3) - - mtx.HighPriorityWriteLock() - go func() { - mtx.LowPriorityWriteLock() - defer mtx.LowPriorityWriteUnlock() - sharedSlice = append(sharedSlice, 2) - lowPriorityLockAcquired = true - wg.Done() - }() - go func() { - mtx.HighPriorityReadLock() - defer mtx.HighPriorityReadUnlock() - if lowPriorityLockAcquired { - t.Errorf("LowPriorityWriteLock unexpectedly released") - } - wg.Done() - }() - go func() { - mtx.HighPriorityWriteLock() - defer mtx.HighPriorityWriteUnlock() - sharedSlice = append(sharedSlice, 1) - if lowPriorityLockAcquired { - t.Errorf("LowPriorityWriteLock unexpectedly released") - } - wg.Done() - }() - time.Sleep(time.Second) - mtx.HighPriorityWriteUnlock() - wg.Wait() - expectedSlice := []int{1, 2} - if !reflect.DeepEqual(sharedSlice, expectedSlice) { - t.Errorf("Expected the shared slice to be %d but got %d", expectedSlice, sharedSlice) - } -} - -func TestHighPriorityReadLock(t *testing.T) { - mtx := NewPriorityMutex() - wg := sync.WaitGroup{} - wg.Add(2) - mtx.LowPriorityWriteLock() - isReadLockHeld := false - ch := make(chan struct{}) - go func() { - mtx.HighPriorityReadLock() - defer mtx.HighPriorityReadUnlock() - isReadLockHeld = true - ch <- struct{}{} - <-ch - isReadLockHeld = false - wg.Done() - }() - go func() { - mtx.HighPriorityReadLock() - defer mtx.HighPriorityReadUnlock() - <-ch - if !isReadLockHeld { - t.Errorf("expected another read lock to be held concurrently") - } - ch <- struct{}{} - wg.Done() - }() - time.Sleep(time.Second) - mtx.LowPriorityWriteUnlock() - wg.Wait() -} diff --git a/util/locks/waitgroup.go b/util/locks/waitgroup.go deleted file mode 100644 index 239d89eb5..000000000 --- a/util/locks/waitgroup.go +++ /dev/null @@ -1,108 +0,0 @@ -package locks - -import ( - "sync" - "sync/atomic" -) - -// waitGroup is a type that implements the same API -// as sync.WaitGroup but allows concurrent calls to -// add() and wait(). -// -// The wait group maintains a counter that can be -// increased by delta by using the waitGroup.add -// method, and decreased by 1 by using the -// waitGroup.done method. -// The general idea of the waitGroup.wait method -// is to block the current goroutine until the -// counter is set to 0. This is how it's implemented: -// -// 1) The waitGroup.wait method is checking if waitGroup.counter -// is 0. If it's the case the function returns. otherwise, -// it sets the flag waitGroup.isReleaseWaitWaiting to 1 so -// that there's a pending wait function, and waits for a signal -// from the channel waitGroup.releaseWait (waitGroup.isReleaseWaitWaiting -// is set to 1 wrapped with waitGroup.isReleaseWaitWaitingLock to -// synchronize with the reader from waitGroup.done). -// -// 2) When waitGroup.done is called, it checks if waitGroup.counter -// is 0. -// -// 3) If waitGroup.counter is 0, it also checks if there's any pending -// wait function by checking if wg.isReleaseWaitWaiting is 1, and if -// this is the case, it sends a signal to release the pending wait -// function, and then waits for a signal from waitGroup.releaseDone, -// and when the signal is received, the function returns. -// This step is wrapped with isReleaseWaitWaitingLock for two reasons: -// a) Prevent a situation where waitGroup.wait goroutine yields just -// before it sets wg.isReleaseWaitWaiting to 1, and then -// waitGroup.done will exit the function without sending the signal -// to waitGroup.wait. -// b) Prevent two waitGroup.done send concurrently a signal to the -// channel wg.releaseWait and making one of them hang forever. -// -// 4) After the waitGroup.wait is released, it sets -// waitGroup.isReleaseWaitWaiting to 0, and sends -// a signal to wg.releaseDone and go back to step 1. -// -// The waitGroup.wait is wrapped with waitGroup.mainWaitLock. It -// is used to enable multiple waits pending for the counter to be -// set to zero. This will cause a situation when one wait function -// will return, the other waits that are pending to waitGroup.mainWaitLock -// will immediately return as well. Without that lock, any call -// to waitGroup.wait will wait to its own signal from waitGroup.releaseWait -// which means that for n waits to be unblocked, the counter has to be set -// to 0 n times. -type waitGroup struct { - counter, isReleaseWaitWaiting int64 - mainWaitLock, isReleaseWaitWaitingLock sync.Mutex - releaseWait, releaseDone chan struct{} -} - -func newWaitGroup() *waitGroup { - return &waitGroup{ - releaseWait: make(chan struct{}), - releaseDone: make(chan struct{}), - } -} - -func (wg *waitGroup) add(delta int64) { - atomic.AddInt64(&wg.counter, delta) -} - -func (wg *waitGroup) done() { - counter := atomic.AddInt64(&wg.counter, -1) - if counter < 0 { - panic("negative values for wg.counter are not allowed. This was likely caused by calling done() before add()") - } - - // To avoid a situation where a struct is - // being sent to wg.releaseWait while there - // are no listeners to the channel (which will - // cause the goroutine to hang for eternity), - // we check wg.isReleaseWaitWaiting to see - // if there is a listener to wg.releaseWait. - if atomic.LoadInt64(&wg.counter) == 0 { - wg.isReleaseWaitWaitingLock.Lock() - defer wg.isReleaseWaitWaitingLock.Unlock() - if atomic.LoadInt64(&wg.isReleaseWaitWaiting) == 1 { - wg.releaseWait <- struct{}{} - <-wg.releaseDone - } - } -} - -func (wg *waitGroup) wait() { - wg.mainWaitLock.Lock() - defer wg.mainWaitLock.Unlock() - wg.isReleaseWaitWaitingLock.Lock() - defer wg.isReleaseWaitWaitingLock.Unlock() - for atomic.LoadInt64(&wg.counter) != 0 { - atomic.StoreInt64(&wg.isReleaseWaitWaiting, 1) - wg.isReleaseWaitWaitingLock.Unlock() - <-wg.releaseWait - atomic.StoreInt64(&wg.isReleaseWaitWaiting, 0) - wg.releaseDone <- struct{}{} - wg.isReleaseWaitWaitingLock.Lock() - } -} diff --git a/util/locks/waitgroup_test.go b/util/locks/waitgroup_test.go deleted file mode 100644 index b476b66e5..000000000 --- a/util/locks/waitgroup_test.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package locks - -import ( - "sync/atomic" - "testing" -) - -// All of the tests, except TestAddAfterWait and -// TestWaitAfterAddDoneCounterHasReset, are copied -// from the native sync/waitgroup_test.go (with some -// minor changes), to check that the new waitGroup -// behaves the same, except enabling the use of add() -// concurrently with wait() - -func testWaitGroup(t *testing.T, wg1 *waitGroup, wg2 *waitGroup) { - n := int64(16) - wg1.add(n) - wg2.add(n) - exited := make(chan struct{}, n) - for i := int64(0); i != n; i++ { - go func(i int64) { - wg1.done() - wg2.wait() - exited <- struct{}{} - }(i) - } - wg1.wait() - for i := int64(0); i != n; i++ { - select { - case <-exited: - t.Fatal("waitGroup released group too soon") - default: - } - wg2.done() - } - for i := int64(0); i != n; i++ { - <-exited // Will block if barrier fails to unlock someone. - } -} - -func TestWaitGroup(t *testing.T) { - wg1 := newWaitGroup() - wg2 := newWaitGroup() - - // Run the same test a few times to ensure barrier is in a proper state. - for i := 0; i != 1000; i++ { - testWaitGroup(t, wg1, wg2) - } - -} - -func TestWaitGroupMisuse(t *testing.T) { - defer func() { - err := recover() - if err != "negative values for wg.counter are not allowed. This was likely caused by calling done() before add()" { - t.Fatalf("Unexpected panic: %#v", err) - } - }() - wg := newWaitGroup() - wg.add(1) - wg.done() - wg.done() - t.Fatal("Should panic, because wg.counter should be negative (-1), which is not allowed") -} - -func TestAddAfterWait(t *testing.T) { - wg := newWaitGroup() - wg.add(1) - syncChan := make(chan struct{}) - go func() { - syncChan <- struct{}{} - wg.wait() - syncChan <- struct{}{} - }() - <-syncChan - wg.add(1) - wg.done() - wg.done() - <-syncChan - -} - -func TestWaitGroupRace(t *testing.T) { - // Run this test for about 1ms. - for i := 0; i < 1000; i++ { - wg := newWaitGroup() - n := new(int32) - // spawn goroutine 1 - wg.add(1) - go func() { - atomic.AddInt32(n, 1) - wg.done() - }() - // spawn goroutine 2 - wg.add(1) - go func() { - atomic.AddInt32(n, 1) - wg.done() - }() - // Wait for goroutine 1 and 2 - wg.wait() - if atomic.LoadInt32(n) != 2 { - t.Fatal("Spurious wakeup from Wait") - } - } - -} - -func TestWaitGroupAlign(t *testing.T) { - type X struct { - x byte - wg *waitGroup - } - x := X{wg: newWaitGroup()} - x.wg.add(1) - go func(x *X) { - x.wg.done() - }(&x) - x.wg.wait() - -} - -func TestWaitAfterAddDoneCounterHasReset(t *testing.T) { - wg := newWaitGroup() - wg.add(1) - wg.done() - wg.add(1) - wg.done() - wg.wait() - -} - -func BenchmarkWaitGroupUncontended(b *testing.B) { - type PaddedWaitGroup struct { - *waitGroup - pad [128]uint8 - } - b.RunParallel(func(pb *testing.PB) { - wg := PaddedWaitGroup{ - waitGroup: newWaitGroup(), - } - for pb.Next() { - wg.add(1) - wg.done() - wg.wait() - } - }) -} - -func benchmarkWaitGroupAdddone(b *testing.B, localWork int) { - wg := newWaitGroup() - b.RunParallel(func(pb *testing.PB) { - foo := 0 - for pb.Next() { - wg.add(1) - for i := 0; i < localWork; i++ { - foo *= 2 - foo /= 2 - } - wg.done() - } - _ = foo - }) -} - -func BenchmarkWaitGroupAdddone(b *testing.B) { - benchmarkWaitGroupAdddone(b, 0) -} - -func BenchmarkWaitGroupAddDoneWork(b *testing.B) { - benchmarkWaitGroupAdddone(b, 100) -} - -func benchmarkWaitGroupwait(b *testing.B, localWork int) { - wg := newWaitGroup() - b.RunParallel(func(pb *testing.PB) { - foo := 0 - for pb.Next() { - wg.wait() - for i := 0; i < localWork; i++ { - foo *= 2 - foo /= 2 - } - } - _ = foo - }) -} - -func BenchmarkWaitGroupwait(b *testing.B) { - benchmarkWaitGroupwait(b, 0) -} - -func BenchmarkWaitGroupWaitWork(b *testing.B) { - benchmarkWaitGroupwait(b, 100) -} - -func BenchmarkWaitGroupActuallywait(b *testing.B) { - b.ReportAllocs() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - wg := newWaitGroup() - wg.add(1) - go func() { - wg.done() - }() - wg.wait() - } - }) -} diff --git a/util/net.go b/util/net.go deleted file mode 100644 index 3a19fd8b8..000000000 --- a/util/net.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2013-2014 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -// +build !appengine - -package util - -import ( - "net" -) - -// interfaceAddrs returns a list of the system's network interface addresses. -// It is wrapped here so that we can substitute it for other functions when -// building for systems that do not allow access to net.InterfaceAddrs(). -func interfaceAddrs() ([]net.Addr, error) { - return net.InterfaceAddrs() -} diff --git a/util/net_noop.go b/util/net_noop.go deleted file mode 100644 index 92f894f80..000000000 --- a/util/net_noop.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013-2014 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -// +build appengine - -package util - -import ( - "net" -) - -// interfaceAddrs returns a list of the system's network interface addresses. -// It is wrapped here so that we can substitute it for a no-op function that -// returns an empty slice of net.Addr when building for systems that do not -// allow access to net.InterfaceAddrs(). -func interfaceAddrs() ([]net.Addr, error) { - return []net.Addr{}, nil -} diff --git a/util/pointers/copytopointer.go b/util/pointers/copytopointer.go deleted file mode 100644 index b86cae427..000000000 --- a/util/pointers/copytopointer.go +++ /dev/null @@ -1,73 +0,0 @@ -package pointers - -// Bool is a helper routine that allocates a new bool value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Bool(v bool) *bool { - p := new(bool) - *p = v - return p -} - -// Int is a helper routine that allocates a new int value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Int(v int) *int { - p := new(int) - *p = v - return p -} - -// Uint is a helper routine that allocates a new uint value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Uint(v uint) *uint { - p := new(uint) - *p = v - return p -} - -// Int32 is a helper routine that allocates a new int32 value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Int32(v int32) *int32 { - p := new(int32) - *p = v - return p -} - -// Uint32 is a helper routine that allocates a new uint32 value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Uint32(v uint32) *uint32 { - p := new(uint32) - *p = v - return p -} - -// Int64 is a helper routine that allocates a new int64 value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Int64(v int64) *int64 { - p := new(int64) - *p = v - return p -} - -// Uint64 is a helper routine that allocates a new uint64 value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Uint64(v uint64) *uint64 { - p := new(uint64) - *p = v - return p -} - -// Float64 is a helper routine that allocates a new float64 value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func Float64(v float64) *float64 { - p := new(float64) - *p = v - return p -} - -// String is a helper routine that allocates a new string value to store v and -// returns a pointer to it. This is useful when assigning optional parameters. -func String(v string) *string { - p := new(string) - *p = v - return p -} diff --git a/util/pointers/copytopointer_test.go b/util/pointers/copytopointer_test.go deleted file mode 100644 index 31b9087db..000000000 --- a/util/pointers/copytopointer_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2014 The btcsuite developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package pointers - -import ( - "reflect" - "testing" -) - -// TestCopyToPointer tests the various helper functions which create pointers to -// primitive types. -func TestCopyToPointer(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - f func() interface{} - expected interface{} - }{ - { - name: "bool", - f: func() interface{} { - return Bool(true) - }, - expected: func() interface{} { - val := true - return &val - }(), - }, - { - name: "int", - f: func() interface{} { - return Int(5) - }, - expected: func() interface{} { - val := int(5) - return &val - }(), - }, - { - name: "uint", - f: func() interface{} { - return Uint(5) - }, - expected: func() interface{} { - val := uint(5) - return &val - }(), - }, - { - name: "int32", - f: func() interface{} { - return Int32(5) - }, - expected: func() interface{} { - val := int32(5) - return &val - }(), - }, - { - name: "uint32", - f: func() interface{} { - return Uint32(5) - }, - expected: func() interface{} { - val := uint32(5) - return &val - }(), - }, - { - name: "int64", - f: func() interface{} { - return Int64(5) - }, - expected: func() interface{} { - val := int64(5) - return &val - }(), - }, - { - name: "uint64", - f: func() interface{} { - return Uint64(5) - }, - expected: func() interface{} { - val := uint64(5) - return &val - }(), - }, - { - name: "string", - f: func() interface{} { - return String("abc") - }, - expected: func() interface{} { - val := "abc" - return &val - }(), - }, - } - - t.Logf("Running %d tests", len(tests)) - for i, test := range tests { - result := test.f() - if !reflect.DeepEqual(result, test.expected) { - t.Errorf("Test #%d (%s) unexpected value - got %v, "+ - "want %v", i, test.name, result, test.expected) - continue - } - } -} diff --git a/util/random/random.go b/util/random/random.go index cd027d25d..78d3cf9e5 100644 --- a/util/random/random.go +++ b/util/random/random.go @@ -2,23 +2,15 @@ package random import ( "crypto/rand" - "io" - - "github.com/kaspanet/kaspad/util/binaryserializer" + "encoding/binary" ) -// randomUint64 returns a cryptographically random uint64 value. This -// unexported version takes a reader primarily to ensure the error paths -// can be properly tested by passing a fake reader in the tests. -func randomUint64(r io.Reader) (uint64, error) { - rv, err := binaryserializer.Uint64(r) - if err != nil { - return 0, err - } - return rv, nil -} - // Uint64 returns a cryptographically random uint64 value. func Uint64() (uint64, error) { - return randomUint64(rand.Reader) + var buf [8]byte + _, err := rand.Read(buf[:]) + if err != nil { + return 0, err + } + return binary.LittleEndian.Uint64(buf[:]), nil } diff --git a/util/random/random_test.go b/util/random/random_test.go index bf9b41b54..db1d6cdf3 100644 --- a/util/random/random_test.go +++ b/util/random/random_test.go @@ -1,6 +1,7 @@ package random import ( + "crypto/rand" "fmt" "github.com/pkg/errors" "io" @@ -61,8 +62,9 @@ func TestRandomUint64(t *testing.T) { // and checks the results accordingly. func TestRandomUint64Errors(t *testing.T) { // Test short reads. - fr := &fakeRandReader{n: 2, err: io.EOF} - nonce, err := randomUint64(fr) + reader := rand.Reader + rand.Reader = &fakeRandReader{n: 2, err: io.EOF} + nonce, err := Uint64() if !errors.Is(err, io.ErrUnexpectedEOF) { t.Errorf("Error not expected value of %v [%v]", io.ErrUnexpectedEOF, err) @@ -70,4 +72,5 @@ func TestRandomUint64Errors(t *testing.T) { if nonce != 0 { t.Errorf("Nonce is not 0 [%v]", nonce) } + rand.Reader = reader } diff --git a/util/strings.go b/util/strings.go deleted file mode 100644 index e2ca30804..000000000 --- a/util/strings.go +++ /dev/null @@ -1,69 +0,0 @@ -package util - -import ( - "strings" - "unicode" -) - -// ToCamelCase converts a camelCase-ish string into a typical JSON camelCase string. -// Example conversion: MyJSONVariable -> myJsonVariable -func ToCamelCase(str string) string { - if len(str) == 0 { - return "" - } - - // Split the string into words - words := make([]string, 0) - wordStartIndex := 0 - wordEndIndex := -1 - var previousCharacter rune - for i, character := range str { - if i > 0 { - if unicode.IsLower(previousCharacter) && unicode.IsUpper(character) { - // previousCharacter is definitely the end of a word - wordEndIndex = i - 1 - - word := str[wordStartIndex:i] - words = append(words, word) - } else if unicode.IsUpper(previousCharacter) && unicode.IsLower(character) { - // previousCharacter is definitely the start of a word - wordStartIndex = i - 1 - - if wordStartIndex-wordEndIndex > 1 { - // This handles consequent uppercase words, such as acronyms. - // Example: getBlockDAGInfo - // ^^^ - word := str[wordEndIndex+1 : wordStartIndex] - words = append(words, word) - } - } - } - previousCharacter = character - } - if unicode.IsUpper(previousCharacter) { - // This handles consequent uppercase words, such as acronyms, at the end of the string - // Example: TxID - // ^^ - for i := len(str) - 1; i >= 0; i-- { - if unicode.IsLower(rune(str[i])) { - break - } - - wordStartIndex = i - } - } - lastWord := str[wordStartIndex:] - words = append(words, lastWord) - - // Build a PascalCase string out of the words - var camelCaseBuilder strings.Builder - for _, word := range words { - lowercaseWord := strings.ToLower(word) - capitalizedWord := strings.ToUpper(string(lowercaseWord[0])) + lowercaseWord[1:] - camelCaseBuilder.WriteString(capitalizedWord) - } - camelCaseString := camelCaseBuilder.String() - - // Un-capitalize the first character to covert PascalCase into camelCase - return strings.ToLower(string(camelCaseString[0])) + camelCaseString[1:] -} diff --git a/util/strings_test.go b/util/strings_test.go deleted file mode 100644 index 6efdef796..000000000 --- a/util/strings_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package util - -import "testing" - -// TestToCamelCase tests whether ToCamelCase correctly converts camelCase-ish strings to camelCase. -func TestToCamelCase(t *testing.T) { - tests := []struct { - name string - input string - expectedResult string - }{ - { - name: "single word that's already in camelCase", - input: "abc", - expectedResult: "abc", - }, - { - name: "single word in PascalCase", - input: "Abc", - expectedResult: "abc", - }, - { - name: "single word in all caps", - input: "ABC", - expectedResult: "abc", - }, - { - name: "multiple words that are already in camelCase", - input: "aaaBbbCcc", - expectedResult: "aaaBbbCcc", - }, - { - name: "multiple words in PascalCase", - input: "AaaBbbCcc", - expectedResult: "aaaBbbCcc", - }, - { - name: "acronym in start position", - input: "AAABbbCcc", - expectedResult: "aaaBbbCcc", - }, - { - name: "acronym in middle position", - input: "aaaBBBCcc", - expectedResult: "aaaBbbCcc", - }, - { - name: "acronym in end position", - input: "aaaBbbCCC", - expectedResult: "aaaBbbCcc", - }, - } - - for _, test := range tests { - result := ToCamelCase(test.input) - if result != test.expectedResult { - t.Errorf("ToCamelCase for test \"%s\" returned an unexpected result. "+ - "Expected: \"%s\", got: \"%s\"", test.name, test.expectedResult, result) - } - } -} diff --git a/util/testtools/testtools.go b/util/testtools/testtools.go deleted file mode 100644 index ad92e551a..000000000 --- a/util/testtools/testtools.go +++ /dev/null @@ -1,23 +0,0 @@ -package testtools - -import ( - "time" -) - -// WaitTillAllCompleteOrTimeout waits until all the provided channels has been written to, -// or until a timeout period has passed. -// Returns true iff all channels returned in the allotted time. -func WaitTillAllCompleteOrTimeout(timeoutDuration time.Duration, chans ...chan struct{}) (ok bool) { - timeout := time.After(timeoutDuration) - - for _, c := range chans { - select { - case <-c: - continue - case <-timeout: - return false - } - } - - return true -} diff --git a/util/util.go b/util/util.go deleted file mode 100644 index 7921ca0a5..000000000 --- a/util/util.go +++ /dev/null @@ -1,18 +0,0 @@ -package util - -import "sort" - -// SearchSlice uses binary search to find and return the smallest index i -// in [0, n) at which f(i) is true, assuming that on the range [0, n), -// f(i) == true implies f(i+1) == true. That is, SearchSlice requires that -// f is false for some (possibly empty) prefix of the input range [0, n) -// and then true for the (possibly empty) remainder; SearchSlice returns -// the first true index. -// SearchSlice calls f(i) only for i in the range [0, n). -func SearchSlice(sliceLength int, searchFunc func(int) bool) (foundIndex int, ok bool) { - result := sort.Search(sliceLength, searchFunc) - if result == sliceLength { - return -1, false - } - return result, true -} From d835f72e74af66629874f2522fbb5110685fc845 Mon Sep 17 00:00:00 2001 From: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> Date: Sun, 14 Feb 2021 19:08:06 +0200 Subject: [PATCH 335/351] Make AddressManager persistent (#1525) * Move existing address/bannedAddress functionality to a new addressStore object. * Implement TestAddressManager. * Implement serializeAddressKey and deserializeAddressKey. * Implement serializeNetAddress and deserializeNetAddress. * Store addresses and banned addresses to disk. * Implement restoreNotBannedAddresses. * Fix bannedDatabaseKey. * Implement restoreBannedAddresses. * Implement TestRestoreAddressManager. * Defer closing the database in TestRestoreAddressManager. * Defer closing the database in TestRestoreAddressManager. * Add a log. * Return errors where appropriate. Co-authored-by: Elichai Turkel --- app/component_manager.go | 2 +- .../flows/addressexchange/receiveaddresses.go | 3 +- app/protocol/flows/handshake/handshake.go | 5 +- .../network/addressmanager/addressmanager.go | 114 +++++---- .../addressmanager/addressmanager_test.go | 210 +++++++++++++++- .../network/addressmanager/network_test.go | 4 +- .../network/addressmanager/store.go | 225 ++++++++++++++++++ .../network/addressmanager/store_test.go | 45 ++++ .../network/addressmanager/test_utils.go | 3 +- .../network/connmanager/connmanager.go | 6 +- 10 files changed, 538 insertions(+), 79 deletions(-) create mode 100644 infrastructure/network/addressmanager/store.go create mode 100644 infrastructure/network/addressmanager/store_test.go diff --git a/app/component_manager.go b/app/component_manager.go index e2f20beae..f8481dd05 100644 --- a/app/component_manager.go +++ b/app/component_manager.go @@ -90,7 +90,7 @@ func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, return nil, err } - addressManager, err := addressmanager.New(addressmanager.NewConfig(cfg)) + addressManager, err := addressmanager.New(addressmanager.NewConfig(cfg), db) if err != nil { return nil, err } diff --git a/app/protocol/flows/addressexchange/receiveaddresses.go b/app/protocol/flows/addressexchange/receiveaddresses.go index 366f350b0..654c823ff 100644 --- a/app/protocol/flows/addressexchange/receiveaddresses.go +++ b/app/protocol/flows/addressexchange/receiveaddresses.go @@ -35,6 +35,5 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou return protocolerrors.Errorf(true, "address count exceeded %d", addressmanager.GetAddressesMax) } - context.AddressManager().AddAddresses(msgAddresses.AddressList...) - return nil + return context.AddressManager().AddAddresses(msgAddresses.AddressList...) } diff --git a/app/protocol/flows/handshake/handshake.go b/app/protocol/flows/handshake/handshake.go index aa6c5f686..b3a332961 100644 --- a/app/protocol/flows/handshake/handshake.go +++ b/app/protocol/flows/handshake/handshake.go @@ -89,7 +89,10 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N } if peerAddress != nil { - context.AddressManager().AddAddresses(peerAddress) + err := context.AddressManager().AddAddresses(peerAddress) + if err != nil { + return nil, err + } } return peer, nil } diff --git a/infrastructure/network/addressmanager/addressmanager.go b/infrastructure/network/addressmanager/addressmanager.go index df01497b4..1bd13a075 100644 --- a/infrastructure/network/addressmanager/addressmanager.go +++ b/infrastructure/network/addressmanager/addressmanager.go @@ -5,6 +5,7 @@ package addressmanager import ( + "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/kaspanet/kaspad/util/mstime" "net" "sync" @@ -58,67 +59,70 @@ func netAddressesKeys(netAddresses []*appmessage.NetAddress) map[addressKey]bool // AddressManager provides a concurrency safe address manager for caching potential // peers on the Kaspa network. type AddressManager struct { - addresses map[addressKey]*appmessage.NetAddress - bannedAddresses map[ipv6]*appmessage.NetAddress - localAddresses *localAddressManager - mutex sync.Mutex - cfg *Config - random addressRandomizer + store *addressStore + localAddresses *localAddressManager + mutex sync.Mutex + cfg *Config + random addressRandomizer } // New returns a new Kaspa address manager. -func New(cfg *Config) (*AddressManager, error) { +func New(cfg *Config, database database.Database) (*AddressManager, error) { + addressStore, err := newAddressStore(database) + if err != nil { + return nil, err + } localAddresses, err := newLocalAddressManager(cfg) if err != nil { return nil, err } return &AddressManager{ - addresses: map[addressKey]*appmessage.NetAddress{}, - bannedAddresses: map[ipv6]*appmessage.NetAddress{}, - localAddresses: localAddresses, - random: NewAddressRandomize(), - cfg: cfg, + store: addressStore, + localAddresses: localAddresses, + random: NewAddressRandomize(), + cfg: cfg, }, nil } -func (am *AddressManager) addAddressNoLock(address *appmessage.NetAddress) { +func (am *AddressManager) addAddressNoLock(address *appmessage.NetAddress) error { if !IsRoutable(address, am.cfg.AcceptUnroutable) { - return + return nil } key := netAddressKey(address) - _, ok := am.addresses[key] - if !ok { - am.addresses[key] = address - } + return am.store.add(key, address) } // AddAddress adds address to the address manager -func (am *AddressManager) AddAddress(address *appmessage.NetAddress) { +func (am *AddressManager) AddAddress(address *appmessage.NetAddress) error { am.mutex.Lock() defer am.mutex.Unlock() - am.addAddressNoLock(address) + return am.addAddressNoLock(address) } // AddAddresses adds addresses to the address manager -func (am *AddressManager) AddAddresses(addresses ...*appmessage.NetAddress) { +func (am *AddressManager) AddAddresses(addresses ...*appmessage.NetAddress) error { am.mutex.Lock() defer am.mutex.Unlock() for _, address := range addresses { - am.addAddressNoLock(address) + err := am.addAddressNoLock(address) + if err != nil { + return err + } } + return nil } // RemoveAddress removes addresses from the address manager -func (am *AddressManager) RemoveAddress(address *appmessage.NetAddress) { +func (am *AddressManager) RemoveAddress(address *appmessage.NetAddress) error { am.mutex.Lock() defer am.mutex.Unlock() key := netAddressKey(address) - delete(am.addresses, key) + return am.store.remove(key) } // Addresses returns all addresses @@ -126,12 +130,7 @@ func (am *AddressManager) Addresses() []*appmessage.NetAddress { am.mutex.Lock() defer am.mutex.Unlock() - result := make([]*appmessage.NetAddress, 0, len(am.addresses)) - for _, address := range am.addresses { - result = append(result, address) - } - - return result + return am.store.getAllNotBanned() } // BannedAddresses returns all banned addresses @@ -139,28 +138,15 @@ func (am *AddressManager) BannedAddresses() []*appmessage.NetAddress { am.mutex.Lock() defer am.mutex.Unlock() - result := make([]*appmessage.NetAddress, 0, len(am.bannedAddresses)) - for _, address := range am.bannedAddresses { - result = append(result, address) - } - - return result + return am.store.getAllBanned() } // notBannedAddressesWithException returns all not banned addresses with excpetion func (am *AddressManager) notBannedAddressesWithException(exceptions []*appmessage.NetAddress) []*appmessage.NetAddress { - exceptionsKeys := netAddressesKeys(exceptions) am.mutex.Lock() defer am.mutex.Unlock() - result := make([]*appmessage.NetAddress, 0, len(am.addresses)) - for key, address := range am.addresses { - if !exceptionsKeys[key] { - result = append(result, address) - } - } - - return result + return am.store.getAllNotBannedWithout(exceptions) } // RandomAddress returns a random address that isn't banned and isn't in exceptions @@ -182,23 +168,26 @@ func (am *AddressManager) BestLocalAddress(remoteAddress *appmessage.NetAddress) } // Ban marks the given address as banned -func (am *AddressManager) Ban(addressToBan *appmessage.NetAddress) { +func (am *AddressManager) Ban(addressToBan *appmessage.NetAddress) error { am.mutex.Lock() defer am.mutex.Unlock() keyToBan := netAddressKey(addressToBan) keysToDelete := make([]addressKey, 0) - for _, address := range am.addresses { + for _, address := range am.store.getAllNotBanned() { key := netAddressKey(address) if key.address.equal(keyToBan.address) { keysToDelete = append(keysToDelete, key) } } for _, key := range keysToDelete { - delete(am.addresses, key) + err := am.store.remove(key) + if err != nil { + return err + } } - am.bannedAddresses[keyToBan.address] = addressToBan + return am.store.addBanned(keyToBan, addressToBan) } // Unban unmarks the given address as banned @@ -207,14 +196,12 @@ func (am *AddressManager) Unban(address *appmessage.NetAddress) error { defer am.mutex.Unlock() key := netAddressKey(address) - _, ok := am.bannedAddresses[key.address] - if !ok { + if !am.store.isBanned(key) { return errors.Wrapf(ErrAddressNotFound, "address %s "+ "is not registered with the address manager as banned", address.TCPAddress()) } - delete(am.bannedAddresses, key.address) - return nil + return am.store.removeBanned(key) } // IsBanned returns true if the given address is marked as banned @@ -223,9 +210,12 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) defer am.mutex.Unlock() key := netAddressKey(address) - am.unbanIfOldEnough(key.address) - if _, ok := am.bannedAddresses[key.address]; !ok { - if _, ok = am.addresses[key]; !ok { + err := am.unbanIfOldEnough(key) + if err != nil { + return false, err + } + if !am.store.isBanned(key) { + if !am.store.isNotBanned(key) { return false, errors.Wrapf(ErrAddressNotFound, "address %s "+ "is not registered with the address manager", address.TCPAddress()) } @@ -236,14 +226,18 @@ func (am *AddressManager) IsBanned(address *appmessage.NetAddress) (bool, error) } -func (am *AddressManager) unbanIfOldEnough(ipv6Address ipv6) { - address, ok := am.bannedAddresses[ipv6Address] +func (am *AddressManager) unbanIfOldEnough(key addressKey) error { + address, ok := am.store.getBanned(key) if !ok { - return + return nil } const maxBanTime = 24 * time.Hour if mstime.Since(address.Timestamp) > maxBanTime { - delete(am.bannedAddresses, ipv6Address) + err := am.store.removeBanned(key) + if err != nil { + return err + } } + return nil } diff --git a/infrastructure/network/addressmanager/addressmanager_test.go b/infrastructure/network/addressmanager/addressmanager_test.go index 1a5564a5f..14bb6f1fc 100644 --- a/infrastructure/network/addressmanager/addressmanager_test.go +++ b/infrastructure/network/addressmanager/addressmanager_test.go @@ -5,23 +5,32 @@ package addressmanager import ( - "net" - "testing" - "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" + "github.com/kaspanet/kaspad/util/mstime" + "net" + "reflect" + "testing" "github.com/kaspanet/kaspad/infrastructure/config" ) -func newAddrManagerForTest(t *testing.T, testName string) (addressManager *AddressManager, teardown func()) { +func newAddressManagerForTest(t *testing.T, testName string) (addressManager *AddressManager, teardown func()) { cfg := config.DefaultConfig() - addressManager, err := New(NewConfig(cfg)) + datadir := t.TempDir() + database, err := ldb.NewLevelDB(datadir, 8) if err != nil { - t.Fatalf("error creating address manager: %s", err) + t.Fatalf("%s: could not create a database: %s", testName, err) + } + + addressManager, err = New(NewConfig(cfg), database) + if err != nil { + t.Fatalf("%s: error creating address manager: %s", testName, err) } return addressManager, func() { + database.Close() } } @@ -66,7 +75,7 @@ func TestBestLocalAddress(t *testing.T) { }, } - amgr, teardown := newAddrManagerForTest(t, "TestGetBestLocalAddress") + amgr, teardown := newAddressManagerForTest(t, "TestGetBestLocalAddress") defer teardown() // Test against default when there's no address @@ -107,3 +116,190 @@ func TestBestLocalAddress(t *testing.T) { } } } + +func TestAddressManager(t *testing.T) { + addressManager, teardown := newAddressManagerForTest(t, "TestAddressManager") + defer teardown() + + testAddress1 := &appmessage.NetAddress{IP: net.ParseIP("1.2.3.4"), Timestamp: mstime.Now()} + testAddress2 := &appmessage.NetAddress{IP: net.ParseIP("5.6.8.8"), Timestamp: mstime.Now()} + testAddress3 := &appmessage.NetAddress{IP: net.ParseIP("9.0.1.2"), Timestamp: mstime.Now()} + testAddresses := []*appmessage.NetAddress{testAddress1, testAddress2, testAddress3} + + // Add a few addresses + err := addressManager.AddAddresses(testAddresses...) + if err != nil { + t.Fatalf("AddAddresses() failed: %s", err) + } + + // Make sure that all the addresses are returned + addresses := addressManager.Addresses() + if len(testAddresses) != len(addresses) { + t.Fatalf("Unexpected amount of addresses returned from Addresses. "+ + "Want: %d, got: %d", len(testAddresses), len(addresses)) + } + for _, testAddress := range testAddresses { + found := false + for _, address := range addresses { + if reflect.DeepEqual(testAddress, address) { + found = true + break + } + } + if !found { + t.Fatalf("Address %s not returned from Addresses().", testAddress.IP) + } + } + + // Remove an address + addressToRemove := testAddress2 + err = addressManager.RemoveAddress(addressToRemove) + if err != nil { + t.Fatalf("RemoveAddress() failed: %s", err) + } + + // Make sure that the removed address is not returned + addresses = addressManager.Addresses() + if len(addresses) != len(testAddresses)-1 { + t.Fatalf("Unexpected amount of addresses returned from Addresses(). "+ + "Want: %d, got: %d", len(addresses), len(testAddresses)-1) + } + for _, address := range addresses { + if reflect.DeepEqual(addressToRemove, address) { + t.Fatalf("Removed addresses %s returned from Addresses()", addressToRemove.IP) + } + } + + // Add that address back + err = addressManager.AddAddress(addressToRemove) + if err != nil { + t.Fatalf("AddAddress() failed: %s", err) + } + + // Ban a different address + addressToBan := testAddress3 + err = addressManager.Ban(addressToBan) + if err != nil { + t.Fatalf("Ban() failed: %s", err) + } + + // Make sure that the banned address is not returned + addresses = addressManager.Addresses() + if len(addresses) != len(testAddresses)-1 { + t.Fatalf("Unexpected amount of addresses returned from Addresses(). "+ + "Want: %d, got: %d", len(addresses), len(testAddresses)-1) + } + for _, address := range addresses { + if reflect.DeepEqual(addressToBan, address) { + t.Fatalf("Banned addresses %s returned from Addresses()", addressToBan.IP) + } + } + + // Check that the address is banned + isBanned, err := addressManager.IsBanned(addressToBan) + if err != nil { + t.Fatalf("IsBanned() failed: %s", err) + } + if !isBanned { + t.Fatalf("Adderss %s is unexpectedly not banned", addressToBan.IP) + } + + // Check that BannedAddresses() returns the banned address + bannedAddresses := addressManager.BannedAddresses() + if len(bannedAddresses) != 1 { + t.Fatalf("Unexpected amount of addresses returned from BannedAddresses(). "+ + "Want: %d, got: %d", 1, len(bannedAddresses)) + } + if !reflect.DeepEqual(addressToBan, bannedAddresses[0]) { + t.Fatalf("Banned address %s not returned from BannedAddresses()", addressToBan.IP) + } + + // Unban the address + err = addressManager.Unban(addressToBan) + if err != nil { + t.Fatalf("Unban() failed: %s", err) + } + + // Check that BannedAddresses() not longer returns the banned address + bannedAddresses = addressManager.BannedAddresses() + if len(bannedAddresses) != 0 { + t.Fatalf("Unexpected amount of addresses returned from BannedAddresses(). "+ + "Want: %d, got: %d", 0, len(bannedAddresses)) + } +} + +func TestRestoreAddressManager(t *testing.T) { + cfg := config.DefaultConfig() + + // Create an empty database + datadir := t.TempDir() + database, err := ldb.NewLevelDB(datadir, 8) + if err != nil { + t.Fatalf("Could not create a database: %s", err) + } + defer database.Close() + + // Create an addressManager with the empty database + addressManager, err := New(NewConfig(cfg), database) + if err != nil { + t.Fatalf("Error creating address manager: %s", err) + } + + testAddress1 := &appmessage.NetAddress{IP: net.ParseIP("1.2.3.4"), Timestamp: mstime.Now()} + testAddress2 := &appmessage.NetAddress{IP: net.ParseIP("5.6.8.8"), Timestamp: mstime.Now()} + testAddress3 := &appmessage.NetAddress{IP: net.ParseIP("9.0.1.2"), Timestamp: mstime.Now()} + testAddresses := []*appmessage.NetAddress{testAddress1, testAddress2, testAddress3} + + // Add some addresses + err = addressManager.AddAddresses(testAddresses...) + if err != nil { + t.Fatalf("AddAddresses() failed: %s", err) + } + + // Ban one of the addresses + addressToBan := testAddress1 + err = addressManager.Ban(addressToBan) + if err != nil { + t.Fatalf("Ban() failed: %s", err) + } + + // Close the database + err = database.Close() + if err != nil { + t.Fatalf("Close() failed: %s", err) + } + + // Reopen the database + database, err = ldb.NewLevelDB(datadir, 8) + if err != nil { + t.Fatalf("Could not create a database: %s", err) + } + + // Recreate an addressManager with a the previous database + addressManager, err = New(NewConfig(cfg), database) + if err != nil { + t.Fatalf("Error creating address manager: %s", err) + } + + // Make sure that Addresses() returns the correct addresses + addresses := addressManager.Addresses() + if len(addresses) != len(testAddresses)-1 { + t.Fatalf("Unexpected amount of addresses returned from Addresses(). "+ + "Want: %d, got: %d", len(addresses), len(testAddresses)-1) + } + for _, address := range addresses { + if reflect.DeepEqual(addressToBan, address) { + t.Fatalf("Banned addresses %s returned from Addresses()", addressToBan.IP) + } + } + + // Make sure that BannedAddresses() returns the correct addresses + bannedAddresses := addressManager.BannedAddresses() + if len(bannedAddresses) != 1 { + t.Fatalf("Unexpected amount of addresses returned from BannedAddresses(). "+ + "Want: %d, got: %d", 1, len(bannedAddresses)) + } + if !reflect.DeepEqual(addressToBan, bannedAddresses[0]) { + t.Fatalf("Banned address %s not returned from BannedAddresses()", addressToBan.IP) + } +} diff --git a/infrastructure/network/addressmanager/network_test.go b/infrastructure/network/addressmanager/network_test.go index 6d47062ff..9904db233 100644 --- a/infrastructure/network/addressmanager/network_test.go +++ b/infrastructure/network/addressmanager/network_test.go @@ -14,7 +14,7 @@ import ( // TestIPTypes ensures the various functions which determine the type of an IP // address based on RFCs work as intended. func TestIPTypes(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP") + amgr, teardown := newAddressManagerForTest(t, "TestAddAddressByIP") defer teardown() type ipTest struct { in appmessage.NetAddress @@ -146,7 +146,7 @@ func TestIPTypes(t *testing.T) { // TestGroupKey tests the GroupKey function to ensure it properly groups various // IP addresses. func TestGroupKey(t *testing.T) { - amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP") + amgr, teardown := newAddressManagerForTest(t, "TestAddAddressByIP") defer teardown() tests := []struct { diff --git a/infrastructure/network/addressmanager/store.go b/infrastructure/network/addressmanager/store.go new file mode 100644 index 000000000..49c3cd606 --- /dev/null +++ b/infrastructure/network/addressmanager/store.go @@ -0,0 +1,225 @@ +package addressmanager + +import ( + "encoding/binary" + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/infrastructure/db/database" + "github.com/kaspanet/kaspad/util/mstime" + "net" +) + +var notBannedAddressBucket = database.MakeBucket([]byte("not-banned-addresses")) +var bannedAddressBucket = database.MakeBucket([]byte("banned-addresses")) + +type addressStore struct { + database database.Database + notBannedAddresses map[addressKey]*appmessage.NetAddress + bannedAddresses map[ipv6]*appmessage.NetAddress +} + +func newAddressStore(database database.Database) (*addressStore, error) { + addressStore := &addressStore{ + database: database, + notBannedAddresses: map[addressKey]*appmessage.NetAddress{}, + bannedAddresses: map[ipv6]*appmessage.NetAddress{}, + } + err := addressStore.restoreNotBannedAddresses() + if err != nil { + return nil, err + } + err = addressStore.restoreBannedAddresses() + if err != nil { + return nil, err + } + + log.Infof("Loaded %d addresses and %d banned addresses", + len(addressStore.notBannedAddresses), len(addressStore.bannedAddresses)) + + return addressStore, nil +} + +func (as *addressStore) restoreNotBannedAddresses() error { + cursor, err := as.database.Cursor(notBannedAddressBucket) + if err != nil { + return err + } + for ok := cursor.First(); ok; ok = cursor.Next() { + databaseKey, err := cursor.Key() + if err != nil { + return err + } + serializedKey := databaseKey.Suffix() + key := as.deserializeAddressKey(serializedKey) + + serializedNetAddress, err := cursor.Value() + if err != nil { + return err + } + netAddress := as.deserializeNetAddress(serializedNetAddress) + as.notBannedAddresses[key] = netAddress + } + return nil +} + +func (as *addressStore) restoreBannedAddresses() error { + cursor, err := as.database.Cursor(bannedAddressBucket) + if err != nil { + return err + } + for ok := cursor.First(); ok; ok = cursor.Next() { + databaseKey, err := cursor.Key() + if err != nil { + return err + } + var ipv6 ipv6 + copy(ipv6[:], databaseKey.Suffix()) + + serializedNetAddress, err := cursor.Value() + if err != nil { + return err + } + netAddress := as.deserializeNetAddress(serializedNetAddress) + as.bannedAddresses[ipv6] = netAddress + } + return nil +} + +func (as *addressStore) add(key addressKey, address *appmessage.NetAddress) error { + if _, ok := as.notBannedAddresses[key]; ok { + return nil + } + + as.notBannedAddresses[key] = address + + databaseKey := as.notBannedDatabaseKey(key) + serializedAddress := as.serializeNetAddress(address) + return as.database.Put(databaseKey, serializedAddress) +} + +func (as *addressStore) remove(key addressKey) error { + delete(as.notBannedAddresses, key) + + databaseKey := as.notBannedDatabaseKey(key) + return as.database.Delete(databaseKey) +} + +func (as *addressStore) getAllNotBanned() []*appmessage.NetAddress { + addresses := make([]*appmessage.NetAddress, 0, len(as.notBannedAddresses)) + for _, address := range as.notBannedAddresses { + addresses = append(addresses, address) + } + return addresses +} + +func (as *addressStore) getAllNotBannedWithout(ignoredAddresses []*appmessage.NetAddress) []*appmessage.NetAddress { + ignoredKeys := netAddressesKeys(ignoredAddresses) + + addresses := make([]*appmessage.NetAddress, 0, len(as.notBannedAddresses)) + for key, address := range as.notBannedAddresses { + if !ignoredKeys[key] { + addresses = append(addresses, address) + } + } + return addresses +} + +func (as *addressStore) isNotBanned(key addressKey) bool { + _, ok := as.notBannedAddresses[key] + return ok +} + +func (as *addressStore) addBanned(key addressKey, address *appmessage.NetAddress) error { + if _, ok := as.bannedAddresses[key.address]; ok { + return nil + } + + as.bannedAddresses[key.address] = address + + databaseKey := as.bannedDatabaseKey(key) + serializedAddress := as.serializeNetAddress(address) + return as.database.Put(databaseKey, serializedAddress) +} + +func (as *addressStore) removeBanned(key addressKey) error { + delete(as.bannedAddresses, key.address) + + databaseKey := as.bannedDatabaseKey(key) + return as.database.Delete(databaseKey) +} + +func (as *addressStore) getAllBanned() []*appmessage.NetAddress { + bannedAddresses := make([]*appmessage.NetAddress, 0, len(as.bannedAddresses)) + for _, bannedAddress := range as.bannedAddresses { + bannedAddresses = append(bannedAddresses, bannedAddress) + } + return bannedAddresses +} + +func (as *addressStore) isBanned(key addressKey) bool { + _, ok := as.bannedAddresses[key.address] + return ok +} + +func (as *addressStore) getBanned(key addressKey) (*appmessage.NetAddress, bool) { + bannedAddress, ok := as.bannedAddresses[key.address] + return bannedAddress, ok +} + +func (as *addressStore) notBannedDatabaseKey(key addressKey) *database.Key { + serializedKey := as.serializeAddressKey(key) + return notBannedAddressBucket.Key(serializedKey) +} + +func (as *addressStore) bannedDatabaseKey(key addressKey) *database.Key { + return bannedAddressBucket.Key(key.address[:]) +} + +func (as *addressStore) serializeAddressKey(key addressKey) []byte { + serializedSize := 16 + 2 // ipv6 + port + serializedKey := make([]byte, serializedSize) + + copy(serializedKey[:], key.address[:]) + binary.LittleEndian.PutUint16(serializedKey[16:], key.port) + + return serializedKey +} + +func (as *addressStore) deserializeAddressKey(serializedKey []byte) addressKey { + var ip ipv6 + copy(ip[:], serializedKey[:]) + + port := binary.LittleEndian.Uint16(serializedKey[16:]) + + return addressKey{ + port: port, + address: ip, + } +} + +func (as *addressStore) serializeNetAddress(netAddress *appmessage.NetAddress) []byte { + serializedSize := 16 + 2 + 8 + 8 // ipv6 + port + timestamp + services + serializedNetAddress := make([]byte, serializedSize) + + copy(serializedNetAddress[:], netAddress.IP[:]) + binary.LittleEndian.PutUint16(serializedNetAddress[16:], netAddress.Port) + binary.LittleEndian.PutUint64(serializedNetAddress[18:], uint64(netAddress.Timestamp.UnixMilliseconds())) + binary.LittleEndian.PutUint64(serializedNetAddress[26:], uint64(netAddress.Services)) + + return serializedNetAddress +} + +func (as *addressStore) deserializeNetAddress(serializedNetAddress []byte) *appmessage.NetAddress { + ip := make(net.IP, 16) + copy(ip[:], serializedNetAddress[:]) + + port := binary.LittleEndian.Uint16(serializedNetAddress[16:]) + timestamp := mstime.UnixMilliseconds(int64(binary.LittleEndian.Uint64(serializedNetAddress[18:]))) + services := appmessage.ServiceFlag(binary.LittleEndian.Uint64(serializedNetAddress[26:])) + + return &appmessage.NetAddress{ + IP: ip, + Port: port, + Timestamp: timestamp, + Services: services, + } +} diff --git a/infrastructure/network/addressmanager/store_test.go b/infrastructure/network/addressmanager/store_test.go new file mode 100644 index 000000000..5ea35ebc8 --- /dev/null +++ b/infrastructure/network/addressmanager/store_test.go @@ -0,0 +1,45 @@ +package addressmanager + +import ( + "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/util/mstime" + "net" + "reflect" + "testing" +) + +func TestAddressKeySerialization(t *testing.T) { + addressManager, teardown := newAddressManagerForTest(t, "TestAddressKeySerialization") + defer teardown() + addressStore := addressManager.store + + testAddress := &appmessage.NetAddress{IP: net.ParseIP("2602:100:abcd::102"), Port: 12345} + testAddressKey := netAddressKey(testAddress) + + serializedTestAddressKey := addressStore.serializeAddressKey(testAddressKey) + deserializedTestAddressKey := addressStore.deserializeAddressKey(serializedTestAddressKey) + if !reflect.DeepEqual(testAddressKey, deserializedTestAddressKey) { + t.Fatalf("testAddressKey and deserializedTestAddressKey are not equal\n"+ + "testAddressKey:%+v\ndeserializedTestAddressKey:%+v", testAddressKey, deserializedTestAddressKey) + } +} + +func TestNetAddressSerialization(t *testing.T) { + addressManager, teardown := newAddressManagerForTest(t, "TestNetAddressSerialization") + defer teardown() + addressStore := addressManager.store + + testAddress := &appmessage.NetAddress{ + IP: net.ParseIP("2602:100:abcd::102"), + Port: 12345, + Timestamp: mstime.Now(), + Services: appmessage.ServiceFlag(6789), + } + + serializedTestNetAddress := addressStore.serializeNetAddress(testAddress) + deserializedTestNetAddress := addressStore.deserializeNetAddress(serializedTestNetAddress) + if !reflect.DeepEqual(testAddress, deserializedTestNetAddress) { + t.Fatalf("testAddress and deserializedTestNetAddress are not equal\n"+ + "testAddress:%+v\ndeserializedTestNetAddress:%+v", testAddress, deserializedTestNetAddress) + } +} diff --git a/infrastructure/network/addressmanager/test_utils.go b/infrastructure/network/addressmanager/test_utils.go index e86713997..e7301bde1 100644 --- a/infrastructure/network/addressmanager/test_utils.go +++ b/infrastructure/network/addressmanager/test_utils.go @@ -27,6 +27,5 @@ func AddAddressByIP(am *AddressManager, addressIP string, subnetworkID *external return errors.Errorf("invalid port %s: %s", portString, err) } netAddress := appmessage.NewNetAddressIPPort(ip, uint16(port), 0) - am.AddAddresses(netAddress) - return nil + return am.AddAddresses(netAddress) } diff --git a/infrastructure/network/connmanager/connmanager.go b/infrastructure/network/connmanager/connmanager.go index 7b3a91e81..4fa458754 100644 --- a/infrastructure/network/connmanager/connmanager.go +++ b/infrastructure/network/connmanager/connmanager.go @@ -137,8 +137,7 @@ func (c *ConnectionManager) Ban(netConnection *netadapter.NetConnection) error { return errors.Wrapf(ErrCannotBanPermanent, "Cannot ban %s because it's a permanent connection", netConnection.Address()) } - c.addressManager.Ban(netConnection.NetAddress()) - return nil + return c.addressManager.Ban(netConnection.NetAddress()) } // BanByIP bans the given IP and disconnects from all the connection with that IP. @@ -159,8 +158,7 @@ func (c *ConnectionManager) BanByIP(ip net.IP) error { } } - c.addressManager.Ban(appmessage.NewNetAddressIPPort(ip, 0, 0)) - return nil + return c.addressManager.Ban(appmessage.NewNetAddressIPPort(ip, 0, 0)) } // IsBanned returns whether the given netConnection is banned From 2a31074fc4f132c06911433647132edad66387ef Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 15 Feb 2021 14:39:25 +0200 Subject: [PATCH 336/351] Make getBlock return an error for invalid blocks (#1528) --- app/rpc/rpccontext/verbosedata.go | 10 ++++++++++ app/rpc/rpchandlers/get_block.go | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/app/rpc/rpccontext/verbosedata.go b/app/rpc/rpccontext/verbosedata.go index 181ef47e4..f0e0c5ca3 100644 --- a/app/rpc/rpccontext/verbosedata.go +++ b/app/rpc/rpccontext/verbosedata.go @@ -6,6 +6,7 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/utils/constants" "github.com/kaspanet/kaspad/infrastructure/logger" "github.com/kaspanet/kaspad/util/difficulty" + "github.com/pkg/errors" "math" "math/big" "strconv" @@ -23,6 +24,9 @@ import ( "github.com/kaspanet/kaspad/domain/dagconfig" ) +// ErrBuildBlockVerboseDataInvalidBlock indicates that a block that was given to BuildBlockVerboseData is invalid. +var ErrBuildBlockVerboseDataInvalidBlock = errors.New("ErrBuildBlockVerboseDataInvalidBlock") + // BuildBlockVerboseData builds a BlockVerboseData from the given blockHeader. // A block may optionally also be given if it's available in the calling context. func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, block *externalapi.DomainBlock, @@ -37,6 +41,12 @@ func (ctx *Context) BuildBlockVerboseData(blockHeader externalapi.BlockHeader, b if err != nil { return nil, err } + + if blockInfo.BlockStatus == externalapi.StatusInvalid { + return nil, errors.Wrap(ErrBuildBlockVerboseDataInvalidBlock, "cannot build verbose data for "+ + "invalid block") + } + result := &appmessage.BlockVerboseData{ Hash: hash.String(), Version: blockHeader.Version(), diff --git a/app/rpc/rpchandlers/get_block.go b/app/rpc/rpchandlers/get_block.go index bb340c91e..bf18bacd3 100644 --- a/app/rpc/rpchandlers/get_block.go +++ b/app/rpc/rpchandlers/get_block.go @@ -5,6 +5,7 @@ import ( "github.com/kaspanet/kaspad/app/rpc/rpccontext" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router" + "github.com/pkg/errors" ) // HandleGetBlock handles the respectively named RPC command @@ -30,8 +31,14 @@ func HandleGetBlock(context *rpccontext.Context, _ *router.Router, request appme blockVerboseData, err := context.BuildBlockVerboseData(header, nil, getBlockRequest.IncludeTransactionVerboseData) if err != nil { + if errors.Is(err, rpccontext.ErrBuildBlockVerboseDataInvalidBlock) { + errorMessage := &appmessage.GetBlockResponseMessage{} + errorMessage.Error = appmessage.RPCErrorf("Block %s is invalid", hash) + return errorMessage, nil + } return nil, err } + response.BlockVerboseData = blockVerboseData return response, nil From e78cdff3d0e47a612faab5a1b2b3061ae63376c1 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 15 Feb 2021 15:34:21 +0200 Subject: [PATCH 337/351] Don't mark block that got rejected because of ruleerrors.ErrPrunedBlock as invalid (#1529) * Don't mark block that got rejected because of ruleerrors.ErrPrunedBlock as invalid * Update comment --- .../processes/blockprocessor/validateblock.go | 19 +++++++++++++------ .../block_body_in_context_test.go | 12 ++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/validateblock.go b/domain/consensus/processes/blockprocessor/validateblock.go index 11ce29a80..9d1d6ff52 100644 --- a/domain/consensus/processes/blockprocessor/validateblock.go +++ b/domain/consensus/processes/blockprocessor/validateblock.go @@ -53,12 +53,19 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, isPrunin err = bp.validatePostProofOfWork(block, isPruningPoint) if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { - // If we got ErrMissingParents the block shouldn't be considered as invalid - // because it could be added later on when its parents are present, and if - // we get ErrBadMerkleRoot we shouldn't mark the block as invalid because - // later on we can get the block with transactions that fits the merkle - // root. - if !errors.As(err, &ruleerrors.ErrMissingParents{}) && !errors.Is(err, ruleerrors.ErrBadMerkleRoot) { + // We mark invalid blocks with status externalapi.StatusInvalid except in the + // case of the following errors: + // ErrMissingParents - If we got ErrMissingParents the block shouldn't be + // considered as invalid because it could be added later on when its + // parents are present. + // ErrBadMerkleRoot - if we get ErrBadMerkleRoot we shouldn't mark the + // block as invalid because later on we can get the block with + // transactions that fits the merkle root. + // ErrPrunedBlock - ErrPrunedBlock is an error that rejects a block body and + // not the block as a whole, so we shouldn't mark it as invalid. + if !errors.As(err, &ruleerrors.ErrMissingParents{}) && + !errors.Is(err, ruleerrors.ErrBadMerkleRoot) && + !errors.Is(err, ruleerrors.ErrPrunedBlock) { // Discard all changes so we save only the block status bp.discardAllChanges() hash := consensushashing.BlockHash(block) diff --git a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go index f25339966..c6ac81de2 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_context_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_context_test.go @@ -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/constants" "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" "github.com/kaspanet/kaspad/domain/dagconfig" @@ -58,6 +59,17 @@ func TestCheckBlockIsNotPruned(t *testing.T) { if !errors.Is(err, ruleerrors.ErrPrunedBlock) { t.Fatalf("Unexpected error: %+v", err) } + + beforePruningBlockBlockStatus, err := tc.BlockStatusStore().Get(tc.DatabaseContext(), + consensushashing.BlockHash(beforePruningBlock)) + if err != nil { + t.Fatalf("BlockStatusStore().Get: %+v", err) + } + + // Check that the block still has header only status although it got rejected. + if beforePruningBlockBlockStatus != externalapi.StatusHeaderOnly { + t.Fatalf("Unexpected status %s", beforePruningBlockBlockStatus) + } }) } From 2908a46441901c295202d43248f6be739b202edc Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 15 Feb 2021 16:43:35 +0200 Subject: [PATCH 338/351] Don't ban when sending pruned blocks (#1530) --- app/protocol/flows/blockrelay/handle_relay_invs.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 95e445a82..9ac480c70 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -107,6 +107,11 @@ func (flow *handleRelayInvsFlow) start() error { log.Debugf("Processing block %s", inv.Hash) missingParents, blockInsertionResult, err := flow.processBlock(block) if err != nil { + if errors.Is(err, ruleerrors.ErrPrunedBlock) { + log.Infof("Ignoring pruned block %s", inv.Hash) + continue + } + if errors.Is(err, ruleerrors.ErrDuplicateBlock) { log.Infof("Ignoring duplicate block %s", inv.Hash) continue From 00a023620d95e4d6ecb52c4b9ae2d775a1421a61 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 17 Feb 2021 17:05:25 +0200 Subject: [PATCH 339/351] Fix a data race in the block logger (#1533) --- .../blockprocessor/blocklogger/blocklogger.go | 41 ++++++++++++------- .../blockprocessor/blockprocessor.go | 4 ++ .../blockprocessor/validateandinsertblock.go | 3 +- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go b/domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go index c012f82ba..24d9418e1 100644 --- a/domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go +++ b/domain/consensus/processes/blockprocessor/blocklogger/blocklogger.go @@ -11,27 +11,38 @@ import ( "github.com/kaspanet/kaspad/util/mstime" ) -var ( +// BlockLogger is a type tracking the amount of blocks/headers/transactions to log the time it took to receive them +type BlockLogger struct { receivedLogBlocks int64 receivedLogHeaders int64 receivedLogTransactions int64 lastBlockLogTime time.Time -) +} + +// NewBlockLogger creates a new instance with zeroed blocks/headers/transactions/time counters. +func NewBlockLogger() *BlockLogger { + return &BlockLogger{ + receivedLogBlocks: 0, + receivedLogHeaders: 0, + receivedLogTransactions: 0, + lastBlockLogTime: time.Now(), + } +} // LogBlock logs a new block blue score as an information message // to show progress to the user. In order to prevent spam, it limits logging to // one message every 10 seconds with duration and totals included. -func LogBlock(block *externalapi.DomainBlock) { +func (bl *BlockLogger) LogBlock(block *externalapi.DomainBlock) { if len(block.Transactions) == 0 { - receivedLogHeaders++ + bl.receivedLogHeaders++ } else { - receivedLogBlocks++ + bl.receivedLogBlocks++ } - receivedLogTransactions += int64(len(block.Transactions)) + bl.receivedLogTransactions += int64(len(block.Transactions)) now := time.Now() - duration := now.Sub(lastBlockLogTime) + duration := now.Sub(bl.lastBlockLogTime) if duration < time.Second*10 { return } @@ -41,26 +52,26 @@ func LogBlock(block *externalapi.DomainBlock) { // Log information about new block blue score. blockStr := "blocks" - if receivedLogBlocks == 1 { + if bl.receivedLogBlocks == 1 { blockStr = "block" } txStr := "transactions" - if receivedLogTransactions == 1 { + if bl.receivedLogTransactions == 1 { txStr = "transaction" } headerStr := "headers" - if receivedLogBlocks == 1 { + if bl.receivedLogBlocks == 1 { headerStr = "header" } log.Infof("Processed %d %s and %d %s in the last %s (%d %s, %s)", - receivedLogBlocks, blockStr, receivedLogHeaders, headerStr, truncatedDuration, receivedLogTransactions, + bl.receivedLogBlocks, blockStr, bl.receivedLogHeaders, headerStr, truncatedDuration, bl.receivedLogTransactions, txStr, mstime.UnixMilliseconds(block.Header.TimeInMilliseconds())) - receivedLogBlocks = 0 - receivedLogHeaders = 0 - receivedLogTransactions = 0 - lastBlockLogTime = now + bl.receivedLogBlocks = 0 + bl.receivedLogHeaders = 0 + bl.receivedLogTransactions = 0 + bl.lastBlockLogTime = now } diff --git a/domain/consensus/processes/blockprocessor/blockprocessor.go b/domain/consensus/processes/blockprocessor/blockprocessor.go index 100874ce3..1d67188ac 100644 --- a/domain/consensus/processes/blockprocessor/blockprocessor.go +++ b/domain/consensus/processes/blockprocessor/blockprocessor.go @@ -3,6 +3,7 @@ package blockprocessor import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/processes/blockprocessor/blocklogger" "github.com/kaspanet/kaspad/infrastructure/logger" "time" ) @@ -13,6 +14,7 @@ type blockProcessor struct { genesisHash *externalapi.DomainHash targetTimePerBlock time.Duration databaseContext model.DBManager + blockLogger *blocklogger.BlockLogger consensusStateManager model.ConsensusStateManager pruningManager model.PruningManager @@ -49,6 +51,7 @@ func New( genesisHash *externalapi.DomainHash, targetTimePerBlock time.Duration, databaseContext model.DBManager, + consensusStateManager model.ConsensusStateManager, pruningManager model.PruningManager, blockValidator model.BlockValidator, @@ -81,6 +84,7 @@ func New( genesisHash: genesisHash, targetTimePerBlock: targetTimePerBlock, databaseContext: databaseContext, + blockLogger: blocklogger.NewBlockLogger(), pruningManager: pruningManager, blockValidator: blockValidator, dagTopologyManager: dagTopologyManager, diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index c7a051f2a..7a4b5a055 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -2,7 +2,6 @@ package blockprocessor import ( "fmt" - "github.com/kaspanet/kaspad/domain/consensus/processes/blockprocessor/blocklogger" "github.com/kaspanet/kaspad/util/difficulty" "github.com/kaspanet/kaspad/domain/consensus/model" @@ -144,7 +143,7 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, return nil, logClosureErr } - blocklogger.LogBlock(block) + bp.blockLogger.LogBlock(block) return &externalapi.BlockInsertionResult{ VirtualSelectedParentChainChanges: selectedParentChainChanges, From 995e526dae63b5461e2b3c021e6af84f838f4510 Mon Sep 17 00:00:00 2001 From: Svarog Date: Wed, 17 Feb 2021 18:22:08 +0200 Subject: [PATCH 340/351] Make antiPastHashesBetween return blocks sorted in ghostdag-order (#1536) * Make antiPastHashesBetween return blocks sorted in ghostdag-order * Return sortedMergeSet instead of blueMergeSet * Invert the order of parameters of IsAncestorOf * Add RenderDAGToDot to TestConsensus * Add HighHash explicitly, unless lowHash == highHash * Use Equal instead of == when comparing hashes * Fixed TestSyncManager_GetHashesBetween * Fix tests * findHighHashAccordingToMaxBlueScoreDifference: don't start looking if the whole thing fits * Handle a missed error * Remove redundant call to RenderToDot * Fix bug in findHighHashAccordingToMaxBlueScoreDifference --- app/rpc/rpchandlers/get_blocks_test.go | 80 ++++---- domain/consensus/log.go | 2 + .../consensus/model/testapi/test_consensus.go | 5 +- .../processes/syncmanager/antipast.go | 184 +++++++++++------- .../processes/syncmanager/syncmanager_test.go | 54 +++-- domain/consensus/test_consensus.go | 3 +- .../consensus/test_consensus_render_to_dot.go | 79 ++++++++ 7 files changed, 285 insertions(+), 122 deletions(-) create mode 100644 domain/consensus/test_consensus_render_to_dot.go diff --git a/app/rpc/rpchandlers/get_blocks_test.go b/app/rpc/rpchandlers/get_blocks_test.go index b01320b22..0a4dd46d5 100644 --- a/app/rpc/rpchandlers/get_blocks_test.go +++ b/app/rpc/rpchandlers/get_blocks_test.go @@ -1,6 +1,10 @@ package rpchandlers_test import ( + "reflect" + "sort" + "testing" + "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/app/rpc/rpccontext" "github.com/kaspanet/kaspad/app/rpc/rpchandlers" @@ -12,9 +16,6 @@ import ( "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/domain/miningmanager" "github.com/kaspanet/kaspad/infrastructure/config" - "reflect" - "sort" - "testing" ) type fakeDomain struct { @@ -65,66 +66,79 @@ func TestHandleGetBlocks(t *testing.T) { return antipast } - upBfsOrder := make([]*externalapi.DomainHash, 0, 30) - selectedParent := params.GenesisHash - upBfsOrder = append(upBfsOrder, selectedParent) + // Create a DAG with the following structure: + // merging block + // / | \ + // split1 split2 split3 + // \ | / + // merging block + // / | \ + // split1 split2 split3 + // \ | / + // etc. + expectedOrder := make([]*externalapi.DomainHash, 0, 40) + mergingBlock := params.GenesisHash for i := 0; i < 10; i++ { - parents := make([]*externalapi.DomainHash, 0, 3) - for j := 0; j < 4; j++ { - blockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{selectedParent}, nil, nil) + splitBlocks := make([]*externalapi.DomainHash, 0, 3) + for j := 0; j < 3; j++ { + blockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{mergingBlock}, nil, nil) if err != nil { t.Fatalf("Failed adding block: %v", err) } - parents = append(parents, blockHash) - upBfsOrder = append(upBfsOrder, blockHash) + splitBlocks = append(splitBlocks, blockHash) } - selectedParent, _, err = tc.AddBlock(parents, nil, nil) + sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(splitBlocks, tc, t))) + restOfSplitBlocks, selectedParent := splitBlocks[:len(splitBlocks)-1], splitBlocks[len(splitBlocks)-1] + expectedOrder = append(expectedOrder, selectedParent) + expectedOrder = append(expectedOrder, restOfSplitBlocks...) + + mergingBlock, _, err = tc.AddBlock(splitBlocks, nil, nil) if err != nil { t.Fatalf("Failed adding block: %v", err) } - upBfsOrder = append(upBfsOrder, selectedParent) + expectedOrder = append(expectedOrder, mergingBlock) } virtualSelectedParent, err := tc.GetVirtualSelectedParent() if err != nil { t.Fatalf("Failed getting SelectedParent: %v", err) } - if !virtualSelectedParent.Equal(upBfsOrder[len(upBfsOrder)-1]) { - t.Fatalf("Expected %s to be selectedParent, instead found: %s", upBfsOrder[len(upBfsOrder)-1], virtualSelectedParent) + if !virtualSelectedParent.Equal(expectedOrder[len(expectedOrder)-1]) { + t.Fatalf("Expected %s to be selectedParent, instead found: %s", expectedOrder[len(expectedOrder)-1], virtualSelectedParent) } requestSelectedParent := getBlocks(virtualSelectedParent) if !reflect.DeepEqual(requestSelectedParent.BlockHashes, hashes.ToStrings([]*externalapi.DomainHash{virtualSelectedParent})) { - t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", requestSelectedParent.BlockHashes, virtualSelectedParent) + t.Fatalf("TestHandleGetBlocks expected:\n%v\nactual:\n%v", virtualSelectedParent, requestSelectedParent.BlockHashes) } - for i, blockHash := range upBfsOrder { - expectedBlocks := filterAntiPast(blockHash, upBfsOrder) - // sort the slice in the order GetBlocks is returning them - sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(expectedBlocks, tc, t))) + for i, blockHash := range expectedOrder { + expectedBlocks := filterAntiPast(blockHash, expectedOrder) expectedBlocks = append([]*externalapi.DomainHash{blockHash}, expectedBlocks...) - blocks := getBlocks(blockHash) - if !reflect.DeepEqual(blocks.BlockHashes, hashes.ToStrings(expectedBlocks)) { - t.Fatalf("TestSyncManager_GetHashesBetween %d expected %s\n == \n%s", i, blocks.BlockHashes, hashes.ToStrings(expectedBlocks)) + actualBlocks := getBlocks(blockHash) + if !reflect.DeepEqual(actualBlocks.BlockHashes, hashes.ToStrings(expectedBlocks)) { + t.Fatalf("TestHandleGetBlocks %d \nexpected: \n%v\nactual:\n%v", i, + hashes.ToStrings(expectedBlocks), actualBlocks.BlockHashes) } } - // Make explitly sure that if lowHash==highHash we get a slice with a single hash. - blocks := getBlocks(virtualSelectedParent) - if !reflect.DeepEqual(blocks.BlockHashes, []string{virtualSelectedParent.String()}) { - t.Fatalf("TestSyncManager_GetHashesBetween expected blocks to contain just '%s', instead got: \n%s", virtualSelectedParent, blocks.BlockHashes) + // Make explicitly sure that if lowHash==highHash we get a slice with a single hash. + actualBlocks := getBlocks(virtualSelectedParent) + if !reflect.DeepEqual(actualBlocks.BlockHashes, []string{virtualSelectedParent.String()}) { + t.Fatalf("TestHandleGetBlocks expected blocks to contain just '%s', instead got: \n%v", + virtualSelectedParent, actualBlocks.BlockHashes) } - sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(upBfsOrder, tc, t))) - requestAllViaNil := getBlocks(nil) - if !reflect.DeepEqual(requestAllViaNil.BlockHashes, hashes.ToStrings(upBfsOrder)) { - t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", requestAllViaNil.BlockHashes, upBfsOrder) + expectedOrder = append([]*externalapi.DomainHash{params.GenesisHash}, expectedOrder...) + actualOrder := getBlocks(nil) + if !reflect.DeepEqual(actualOrder.BlockHashes, hashes.ToStrings(expectedOrder)) { + t.Fatalf("TestHandleGetBlocks \nexpected: %v \nactual:\n%v", expectedOrder, actualOrder.BlockHashes) } requestAllExplictly := getBlocks(params.GenesisHash) - if !reflect.DeepEqual(requestAllExplictly.BlockHashes, hashes.ToStrings(upBfsOrder)) { - t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", requestAllExplictly.BlockHashes, upBfsOrder) + if !reflect.DeepEqual(requestAllExplictly.BlockHashes, hashes.ToStrings(expectedOrder)) { + t.Fatalf("TestHandleGetBlocks \nexpected: \n%v\n. actual:\n%v", expectedOrder, requestAllExplictly.BlockHashes) } }) } diff --git a/domain/consensus/log.go b/domain/consensus/log.go index 520dcce8d..19fbdc9ac 100644 --- a/domain/consensus/log.go +++ b/domain/consensus/log.go @@ -2,6 +2,8 @@ package consensus import ( "github.com/kaspanet/kaspad/infrastructure/logger" + "github.com/kaspanet/kaspad/util/panics" ) var log, _ = logger.Get(logger.SubsystemTags.BDAG) +var spawn = panics.GoroutineWrapperFunc(log) diff --git a/domain/consensus/model/testapi/test_consensus.go b/domain/consensus/model/testapi/test_consensus.go index a51991455..dd14b5322 100644 --- a/domain/consensus/model/testapi/test_consensus.go +++ b/domain/consensus/model/testapi/test_consensus.go @@ -1,11 +1,12 @@ package testapi import ( + "io" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/db/database" - "io" ) // MineJSONBlockType indicates which type of blocks MineJSON mines @@ -50,6 +51,8 @@ type TestConsensus interface { MineJSON(r io.Reader, blockType MineJSONBlockType) (tips []*externalapi.DomainHash, err error) DiscardAllStores() + RenderDAGToDot(filename string) error + AcceptanceDataStore() model.AcceptanceDataStore BlockHeaderStore() model.BlockHeaderStore BlockRelationStore() model.BlockRelationStore diff --git a/domain/consensus/processes/syncmanager/antipast.go b/domain/consensus/processes/syncmanager/antipast.go index e6cce28e3..75ee8fcdd 100644 --- a/domain/consensus/processes/syncmanager/antipast.go +++ b/domain/consensus/processes/syncmanager/antipast.go @@ -1,14 +1,15 @@ package syncmanager import ( + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashset" "github.com/pkg/errors" ) // antiPastHashesBetween returns the hashes of the blocks between the // lowHash's antiPast and highHash's antiPast, or up to // `maxBlueScoreDifference`, if non-zero. +// The result excludes lowHash and includes highHash. If lowHash == highHash, returns nothing. func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.DomainHash, maxBlueScoreDifference uint64) ([]*externalapi.DomainHash, error) { @@ -17,19 +18,10 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma // highHash's selectedParentChain. // We keep originalLowHash to filter out blocks in it's past later down the road originalLowHash := lowHash - for { - isInSelectedParentChain, err := sm.dagTopologyManager.IsInSelectedParentChainOf(lowHash, highHash) - if err != nil { - return nil, err - } - if isInSelectedParentChain { - break - } - lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) - if err != nil { - return nil, err - } - lowHash = lowBlockGHOSTDAGData.SelectedParent() + var err error + lowHash, err = sm.findLowHashInHighHashSelectedParentChain(lowHash, highHash) + if err != nil { + return nil, err } lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) @@ -55,78 +47,138 @@ 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. - iterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, lowHash) + highHash, err = sm.findHighHashAccordingToMaxBlueScoreDifference(lowHash, highHash, maxBlueScoreDifference, highBlockGHOSTDAGData, lowBlockGHOSTDAGData) if err != nil { return nil, err } - for ok := iterator.First(); ok; ok = iterator.Next() { - highHash, err = iterator.Get() - if err != nil { - return nil, err - } - highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHash) - if err != nil { - return nil, err - } - if highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore()+1 > maxBlueScoreDifference { - break - } - } } - // Collect every node in highHash's past (including itself) but - // NOT in the lowHash's past (excluding itself) into an up-heap - // (a heap sorted by blueScore from lowest to greatest). - visited := hashset.New() - hashesUpHeap := sm.dagTraversalManager.NewUpHeap() - queue := sm.dagTraversalManager.NewDownHeap() - err = queue.Push(highHash) + // Collect all hashes by concatenating the merge-sets of all blocks between highHash and lowHash + blockHashes := []*externalapi.DomainHash{} + iterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, lowHash) if err != nil { return nil, err } - for queue.Len() > 0 { - current := queue.Pop() - if visited.Contains(current) { - continue - } - visited.Add(current) - var isCurrentAncestorOfLowHash bool - if current == lowHash { - isCurrentAncestorOfLowHash = false - } else { - var err error - isCurrentAncestorOfLowHash, err = sm.dagTopologyManager.IsAncestorOf(current, lowHash) - if err != nil { - return nil, err - } - } - if isCurrentAncestorOfLowHash { - continue - } - // Push current to hashesUpHeap if it's not in the past of originalLowHash - isInPastOfOriginalLowHash, err := sm.dagTopologyManager.IsAncestorOf(current, originalLowHash) + for ok := iterator.First(); ok; ok = iterator.Next() { + current, err := iterator.Get() if err != nil { return nil, err } - if !isInPastOfOriginalLowHash { - err = hashesUpHeap.Push(current) - if err != nil { - return nil, err - } - } - parents, err := sm.dagTopologyManager.Parents(current) + // Both blue and red merge sets are topologically sorted, but not the concatenation of the two. + // We require the blocks to be topologically sorted. In addition, for optimal performance, + // we want the selectedParent to be first. + // Since the rest of the merge set is in the anticone of selectedParent, it's position in the list does not + // matter, even though it's blue score is the highest, we can arbitrarily decide it comes first. + // Therefore we first append the selectedParent, then the rest of blocks in ghostdag order. + sortedMergeSet, err := sm.getSortedMergeSet(current) if err != nil { return nil, err } - for _, parent := range parents { - err := queue.Push(parent) + + // append to blockHashes all blocks in sortedMergeSet which are not in the past of originalLowHash + for _, blockHash := range sortedMergeSet { + isInPastOfOriginalLowHash, err := sm.dagTopologyManager.IsAncestorOf(blockHash, originalLowHash) if err != nil { return nil, err } + if isInPastOfOriginalLowHash { + continue + } + blockHashes = append(blockHashes, blockHash) } } - return hashesUpHeap.ToSlice(), nil + // The process above doesn't return highHash, so include it explicitly, unless highHash == lowHash + if !lowHash.Equal(highHash) { + blockHashes = append(blockHashes, highHash) + } + + return blockHashes, nil +} + +func (sm *syncManager) getSortedMergeSet(current *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { + currentGhostdagData, err := sm.ghostdagDataStore.Get(sm.databaseContext, current) + if err != nil { + return nil, err + } + + blueMergeSet := currentGhostdagData.MergeSetBlues() + redMergeSet := currentGhostdagData.MergeSetReds() + sortedMergeSet := make([]*externalapi.DomainHash, 0, len(blueMergeSet)+len(redMergeSet)) + selectedParent, blueMergeSet := blueMergeSet[0], blueMergeSet[1:] + sortedMergeSet = append(sortedMergeSet, selectedParent) + i, j := 0, 0 + for i < len(blueMergeSet) && j < len(redMergeSet) { + currentBlue := blueMergeSet[i] + currentBlueGhostdagData, err := sm.ghostdagDataStore.Get(sm.databaseContext, currentBlue) + if err != nil { + return nil, err + } + currentRed := redMergeSet[j] + currentRedGhostdagData, err := sm.ghostdagDataStore.Get(sm.databaseContext, currentRed) + if err != nil { + return nil, err + } + if sm.ghostdagManager.Less(currentBlue, currentBlueGhostdagData, currentRed, currentRedGhostdagData) { + sortedMergeSet = append(sortedMergeSet, currentBlue) + i++ + } else { + sortedMergeSet = append(sortedMergeSet, currentRed) + j++ + } + } + sortedMergeSet = append(sortedMergeSet, blueMergeSet[i:]...) + sortedMergeSet = append(sortedMergeSet, redMergeSet[j:]...) + + return sortedMergeSet, nil +} + +func (sm *syncManager) findHighHashAccordingToMaxBlueScoreDifference(lowHash *externalapi.DomainHash, + highHash *externalapi.DomainHash, maxBlueScoreDifference uint64, highBlockGHOSTDAGData *model.BlockGHOSTDAGData, + lowBlockGHOSTDAGData *model.BlockGHOSTDAGData) (*externalapi.DomainHash, error) { + + if highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore() <= maxBlueScoreDifference { + return highHash, nil + } + + iterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, lowHash) + if err != nil { + return nil, err + } + for ok := iterator.First(); ok; ok = iterator.Next() { + highHashCandidate, err := iterator.Get() + if err != nil { + return nil, err + } + highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHashCandidate) + if err != nil { + return nil, err + } + if highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore() > maxBlueScoreDifference { + break + } + highHash = highHashCandidate + } + return highHash, nil +} + +func (sm *syncManager) findLowHashInHighHashSelectedParentChain( + lowHash *externalapi.DomainHash, highHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { + for { + isInSelectedParentChain, err := sm.dagTopologyManager.IsInSelectedParentChainOf(lowHash, highHash) + if err != nil { + return nil, err + } + if isInSelectedParentChain { + break + } + lowBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, lowHash) + if err != nil { + return nil, err + } + lowHash = lowBlockGHOSTDAGData.SelectedParent() + } + return lowHash, nil } func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) { diff --git a/domain/consensus/processes/syncmanager/syncmanager_test.go b/domain/consensus/processes/syncmanager/syncmanager_test.go index d01adaa1b..41c6dd032 100644 --- a/domain/consensus/processes/syncmanager/syncmanager_test.go +++ b/domain/consensus/processes/syncmanager/syncmanager_test.go @@ -1,14 +1,15 @@ package syncmanager_test import ( - "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" "math" "reflect" "sort" "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" ) func TestSyncManager_GetHashesBetween(t *testing.T) { @@ -20,27 +21,40 @@ func TestSyncManager_GetHashesBetween(t *testing.T) { } defer teardown(false) - upBfsOrder := make([]*externalapi.DomainHash, 0, 30) - selectedParent := params.GenesisHash - upBfsOrder = append(upBfsOrder, selectedParent) + // Create a DAG with the following structure: + // merging block + // / | \ + // split1 split2 split3 + // \ | / + // merging block + // / | \ + // split1 split2 split3 + // \ | / + // etc. + expectedOrder := make([]*externalapi.DomainHash, 0, 40) + mergingBlock := params.GenesisHash for i := 0; i < 10; i++ { - parents := make([]*externalapi.DomainHash, 0, 3) - for j := 0; j < 4; j++ { - blockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{selectedParent}, nil, nil) + splitBlocks := make([]*externalapi.DomainHash, 0, 3) + for j := 0; j < 3; j++ { + splitBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{mergingBlock}, nil, nil) if err != nil { t.Fatalf("Failed adding block: %v", err) } - parents = append(parents, blockHash) - upBfsOrder = append(upBfsOrder, blockHash) + splitBlocks = append(splitBlocks, splitBlock) } - selectedParent, _, err = tc.AddBlock(parents, nil, nil) + sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(splitBlocks, tc, t))) + restOfSplitBlocks, selectedParent := splitBlocks[:len(splitBlocks)-1], splitBlocks[len(splitBlocks)-1] + expectedOrder = append(expectedOrder, selectedParent) + expectedOrder = append(expectedOrder, restOfSplitBlocks...) + + mergingBlock, _, err = tc.AddBlock(splitBlocks, nil, nil) if err != nil { t.Fatalf("Failed adding block: %v", err) } - upBfsOrder = append(upBfsOrder, selectedParent) + expectedOrder = append(expectedOrder, mergingBlock) } - for i, blockHash := range upBfsOrder { + for i, blockHash := range expectedOrder { empty, err := tc.SyncManager().GetHashesBetween(blockHash, blockHash, math.MaxUint64) if err != nil { t.Fatalf("TestSyncManager_GetHashesBetween failed returning 0 hashes on the %d'th block: %v", i, err) @@ -50,15 +64,13 @@ func TestSyncManager_GetHashesBetween(t *testing.T) { } } - allHashes, err := tc.SyncManager().GetHashesBetween(upBfsOrder[0], upBfsOrder[len(upBfsOrder)-1], math.MaxUint64) + actualOrder, err := tc.SyncManager().GetHashesBetween(params.GenesisHash, expectedOrder[len(expectedOrder)-1], math.MaxUint64) if err != nil { - t.Fatalf("TestSyncManager_GetHashesBetween failed returning allHashes: %v", err) + t.Fatalf("TestSyncManager_GetHashesBetween failed returning actualOrder: %v", err) } - sort.Sort(sort.Reverse(testutils.NewTestGhostDAGSorter(upBfsOrder, tc, t))) - upBfsOrderExcludingGenesis := upBfsOrder[1:] - if !reflect.DeepEqual(allHashes, upBfsOrderExcludingGenesis) { - t.Fatalf("TestSyncManager_GetHashesBetween expected %v\n == \n%v", allHashes, upBfsOrder) + if !reflect.DeepEqual(actualOrder, expectedOrder) { + t.Fatalf("TestSyncManager_GetHashesBetween expected: \n%s\nactual:\n%s\n", expectedOrder, actualOrder) } }) } diff --git a/domain/consensus/test_consensus.go b/domain/consensus/test_consensus.go index c0879e630..91a52b529 100644 --- a/domain/consensus/test_consensus.go +++ b/domain/consensus/test_consensus.go @@ -2,6 +2,8 @@ package consensus import ( "encoding/json" + "io" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/model/testapi" @@ -9,7 +11,6 @@ import ( "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/infrastructure/db/database" "github.com/pkg/errors" - "io" ) type testConsensus struct { diff --git a/domain/consensus/test_consensus_render_to_dot.go b/domain/consensus/test_consensus_render_to_dot.go new file mode 100644 index 000000000..16f078f8d --- /dev/null +++ b/domain/consensus/test_consensus_render_to_dot.go @@ -0,0 +1,79 @@ +package consensus + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os/exec" + "strings" +) + +// RenderDAGToDot is a helper function for debugging tests. +// It requires graphviz installed. +func (tc *testConsensus) RenderDAGToDot(filename string) error { + dotScript, _ := tc.convertToDot() + return renderDotScript(dotScript, filename) +} + +func (tc *testConsensus) convertToDot() (string, error) { + var dotScriptBuilder strings.Builder + dotScriptBuilder.WriteString("digraph {\n\trankdir = TB; \n") + + edges := []string{} + + blocksIterator, err := tc.blockStore.AllBlockHashesIterator(tc.databaseContext) + if err != nil { + return "", err + } + + for ok := blocksIterator.First(); ok; ok = blocksIterator.Next() { + hash, err := blocksIterator.Get() + if err != nil { + return "", err + } + dotScriptBuilder.WriteString(fmt.Sprintf("\t\"%s\";\n", hash)) + + parents, err := tc.dagTopologyManager.Parents(hash) + if err != nil { + return "", err + } + + for _, parentHash := range parents { + edges = append(edges, fmt.Sprintf("\t\"%s\" -> \"%s\";", hash, parentHash)) + } + } + + dotScriptBuilder.WriteString("\n") + + dotScriptBuilder.WriteString(strings.Join(edges, "\n")) + + dotScriptBuilder.WriteString("\n}") + + return dotScriptBuilder.String(), nil +} + +func renderDotScript(dotScript string, filename string) error { + command := exec.Command("dot", "-Tsvg") + stdin, err := command.StdinPipe() + if err != nil { + return fmt.Errorf("Error creating stdin pipe: %s", err) + } + spawn("renderDotScript", func() { + defer stdin.Close() + + _, err = io.WriteString(stdin, dotScript) + if err != nil { + panic(fmt.Errorf("Error writing dotScript into stdin pipe: %s", err)) + } + }) + + var stderr bytes.Buffer + command.Stderr = &stderr + svg, err := command.Output() + if err != nil { + return fmt.Errorf("Error getting output of dot: %s\nstderr:\n%s", err, stderr.String()) + } + + return ioutil.WriteFile(filename, svg, 0600) +} From 6415e525c3986141c71de4bb4662543cf0254213 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 17 Feb 2021 18:59:42 +0200 Subject: [PATCH 341/351] go test race detector in github actions at cron job (#1534) Co-authored-by: Ori Newman --- .github/workflows/go-race.yml | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/go-race.yml diff --git a/.github/workflows/go-race.yml b/.github/workflows/go-race.yml new file mode 100644 index 000000000..6f029b32c --- /dev/null +++ b/.github/workflows/go-race.yml @@ -0,0 +1,48 @@ +name: Go-Race + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + race_test: + runs-on: ubuntu-20.04 + strategy: + matrix: + branch: [ master, latest ] + name: Race detection on ${{ matrix.branch }} + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: 1.15 + + - name: Set scheduled branch name + shell: bash + if: github.event_name == 'schedule' + run: | + if [ "${{ matrix.branch }}" == "master" ]; then + echo "run_on=master" >> $GITHUB_ENV + fi + if [ "${{ matrix.branch }}" == "latest" ]; then + branch=$(git branch -r | grep 'v\([0-9]\+\.\)\([0-9]\+\.\)\([0-9]\+\)-dev' | sort -Vr | head -1 | xargs) + echo "run_on=${branch}" >> $GITHUB_ENV + fi + + - name: Set manual branch name + shell: bash + if: github.event_name == 'workflow_dispatch' + run: echo "run_on=${{ github.ref }}" >> $GITHUB_ENV + + - name: Test with race detector + shell: bash + run: | + git checkout "${{ env.run_on }}" + git status + go test -race ./... From 19878aa062015ace07a99345001ea8e121d54b78 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 18 Feb 2021 00:59:11 +0200 Subject: [PATCH 342/351] Make templateManager hold a DomainBlock and isSynced bool instead of a GetBlockTemplateResponseMessage (#1538) --- cmd/kaspaminer/mineloop.go | 6 +++--- .../templatemanager/templatemanager.go | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 43d62f429..281b019ad 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -159,7 +159,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock { tryCount++ const sleepTime = 500 * time.Millisecond shouldLog := (tryCount-1)%10 == 0 - template := templatemanager.Get() + template, isSynced := templatemanager.Get() if template == nil { if shouldLog { log.Info("Waiting for the initial template") @@ -167,7 +167,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock { time.Sleep(sleepTime) continue } - if !template.IsSynced && !mineWhenNotSynced { + if !isSynced && !mineWhenNotSynced { if shouldLog { log.Warnf("Kaspad is not synced. Skipping current block template") } @@ -175,7 +175,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock { continue } - return appmessage.MsgBlockToDomainBlock(template.MsgBlock) + return template } } diff --git a/cmd/kaspaminer/templatemanager/templatemanager.go b/cmd/kaspaminer/templatemanager/templatemanager.go index 96eddfe67..438050d2a 100644 --- a/cmd/kaspaminer/templatemanager/templatemanager.go +++ b/cmd/kaspaminer/templatemanager/templatemanager.go @@ -2,22 +2,31 @@ package templatemanager import ( "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "sync" ) -var currentTemplate *appmessage.GetBlockTemplateResponseMessage +var currentTemplate *externalapi.DomainBlock +var isSynced bool var lock = &sync.Mutex{} // Get returns the template to work on -func Get() *appmessage.GetBlockTemplateResponseMessage { +func Get() (*externalapi.DomainBlock, bool) { lock.Lock() defer lock.Unlock() - return currentTemplate + // Shallow copy the block so when the user replaces the header it won't affect the template here. + if currentTemplate == nil { + return nil, false + } + block := *currentTemplate + return &block, isSynced } // Set sets the current template to work on func Set(template *appmessage.GetBlockTemplateResponseMessage) { + block := appmessage.MsgBlockToDomainBlock(template.MsgBlock) lock.Lock() defer lock.Unlock() - currentTemplate = template + currentTemplate = block + isSynced = template.IsSynced } From d2f4ed660c9b765e922341bc452f33495e3a4e35 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 18 Feb 2021 10:39:12 +0200 Subject: [PATCH 343/351] Disallow header only blocks on RPC, relay and when requesting IBD full blocks (#1537) --- app/protocol/flowcontext/blocks.go | 5 +++ .../flows/blockrelay/handle_relay_invs.go | 14 +++++++ app/protocol/flows/blockrelay/ibd.go | 5 +++ .../flows/testing/handle_relay_invs_test.go | 42 +++++++++++++++++++ app/rpc/rpchandlers/submit_block.go | 4 +- 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/app/protocol/flowcontext/blocks.go b/app/protocol/flowcontext/blocks.go index 6eacd7dd2..3ddad114e 100644 --- a/app/protocol/flowcontext/blocks.go +++ b/app/protocol/flowcontext/blocks.go @@ -2,6 +2,7 @@ package flowcontext import ( peerpkg "github.com/kaspanet/kaspad/app/protocol/peer" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/pkg/errors" @@ -98,6 +99,10 @@ 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 { + if len(block.Transactions) == 0 { + return protocolerrors.Errorf(false, "cannot add header only block") + } + blockInsertionResult, err := f.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { if errors.As(err, &ruleerrors.RuleError{}) { diff --git a/app/protocol/flows/blockrelay/handle_relay_invs.go b/app/protocol/flows/blockrelay/handle_relay_invs.go index 9ac480c70..ff2bea87b 100644 --- a/app/protocol/flows/blockrelay/handle_relay_invs.go +++ b/app/protocol/flows/blockrelay/handle_relay_invs.go @@ -104,6 +104,11 @@ func (flow *handleRelayInvsFlow) start() error { continue } + err = flow.banIfBlockIsHeaderOnly(block) + if err != nil { + return err + } + log.Debugf("Processing block %s", inv.Hash) missingParents, blockInsertionResult, err := flow.processBlock(block) if err != nil { @@ -140,6 +145,15 @@ func (flow *handleRelayInvsFlow) start() error { } } +func (flow *handleRelayInvsFlow) banIfBlockIsHeaderOnly(block *externalapi.DomainBlock) error { + if len(block.Transactions) == 0 { + return protocolerrors.Errorf(true, "sent header of %s block where expected block with body", + consensushashing.BlockHash(block)) + } + + return nil +} + func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) { if len(flow.invsQueue) > 0 { var inv *appmessage.MsgInvRelayBlock diff --git a/app/protocol/flows/blockrelay/ibd.go b/app/protocol/flows/blockrelay/ibd.go index e4851aed2..43a929796 100644 --- a/app/protocol/flows/blockrelay/ibd.go +++ b/app/protocol/flows/blockrelay/ibd.go @@ -533,6 +533,11 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash) } + err = flow.banIfBlockIsHeaderOnly(block) + if err != nil { + return err + } + blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block) if err != nil { if errors.Is(err, ruleerrors.ErrDuplicateBlock) { diff --git a/app/protocol/flows/testing/handle_relay_invs_test.go b/app/protocol/flows/testing/handle_relay_invs_test.go index 36f28db13..e6fc2add7 100644 --- a/app/protocol/flows/testing/handle_relay_invs_test.go +++ b/app/protocol/flows/testing/handle_relay_invs_test.go @@ -24,6 +24,19 @@ import ( "github.com/pkg/errors" ) +var headerOnlyBlock = &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + &externalapi.DomainHash{}, + 0, + 0, + 0, + ), +} + var orphanBlock = &externalapi.DomainBlock{ Header: blockheader.NewImmutableBlockHeader( constants.MaxBlockVersion, @@ -35,6 +48,7 @@ var orphanBlock = &externalapi.DomainBlock{ 0, 0, ), + Transactions: []*externalapi.DomainTransaction{{}}, } var validPruningPointBlock = &externalapi.DomainBlock{ @@ -48,6 +62,7 @@ var validPruningPointBlock = &externalapi.DomainBlock{ 0, 0, ), + Transactions: []*externalapi.DomainTransaction{{}}, } var invalidPruningPointBlock = &externalapi.DomainBlock{ @@ -61,6 +76,7 @@ var invalidPruningPointBlock = &externalapi.DomainBlock{ 0, 0, ), + Transactions: []*externalapi.DomainTransaction{{}}, } var unexpectedIBDBlock = &externalapi.DomainBlock{ @@ -74,6 +90,7 @@ var unexpectedIBDBlock = &externalapi.DomainBlock{ 0, 0, ), + Transactions: []*externalapi.DomainTransaction{{}}, } var invalidBlock = &externalapi.DomainBlock{ @@ -87,6 +104,7 @@ var invalidBlock = &externalapi.DomainBlock{ 0, 0, ), + Transactions: []*externalapi.DomainTransaction{{}}, } var unknownBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1}) @@ -95,6 +113,7 @@ var validPruningPointHash = consensushashing.BlockHash(validPruningPointBlock) var invalidBlockHash = consensushashing.BlockHash(invalidBlock) var invalidPruningPointHash = consensushashing.BlockHash(invalidPruningPointBlock) var orphanBlockHash = consensushashing.BlockHash(orphanBlock) +var headerOnlyBlockHash = consensushashing.BlockHash(headerOnlyBlock) type fakeRelayInvsContext struct { testName string @@ -450,6 +469,29 @@ func TestHandleRelayInvs(t *testing.T) { expectsBan: true, expectsErrToContain: "got unrequested block", }, + { + name: "sending header only block on relay", + funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { + err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(headerOnlyBlockHash)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + + msg, err := outgoingRoute.DequeueWithTimeout(time.Second) + if err != nil { + t.Fatalf("DequeueWithTimeout: %+v", err) + } + _ = msg.(*appmessage.MsgRequestRelayBlocks) + + err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(headerOnlyBlock)) + if err != nil { + t.Fatalf("Enqueue: %+v", err) + } + }, + expectsProtocolError: true, + expectsBan: true, + expectsErrToContain: "block where expected block with body", + }, { name: "sending invalid block", funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) { diff --git a/app/rpc/rpchandlers/submit_block.go b/app/rpc/rpchandlers/submit_block.go index 475e2c00c..373eeb2f5 100644 --- a/app/rpc/rpchandlers/submit_block.go +++ b/app/rpc/rpchandlers/submit_block.go @@ -2,6 +2,7 @@ package rpchandlers import ( "github.com/kaspanet/kaspad/app/appmessage" + "github.com/kaspanet/kaspad/app/protocol/protocolerrors" "github.com/kaspanet/kaspad/app/rpc/rpccontext" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" @@ -25,9 +26,10 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap err := context.ProtocolManager.AddBlock(domainBlock) if err != nil { - if !errors.As(err, &ruleerrors.RuleError{}) { + if !errors.As(err, &ruleerrors.RuleError{}) || !errors.As(err, &protocolerrors.ProtocolError{}) { return nil, err } + return &appmessage.SubmitBlockResponseMessage{ Error: appmessage.RPCErrorf("Block rejected. Reason: %s", err), RejectReason: appmessage.RejectReasonBlockInvalid, From 06fd6f1b95797b3259d79ebd00af9e4ab6148b4f Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Thu, 18 Feb 2021 11:38:44 +0200 Subject: [PATCH 344/351] Parallelize tests on Dockerfile (#1540) Co-authored-by: Svarog --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 1a00521e1..d67142840 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -18,7 +18,7 @@ COPY go.sum . COPY . . -RUN NO_PARALLEL=1 ./build_and_test.sh +RUN ./build_and_test.sh # --- multistage docker build: stage #2: runtime image FROM alpine From 5fa06fe7d7e4f824473ecf2b9bc3988c25ff0a9c Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 21 Feb 2021 09:17:21 +0200 Subject: [PATCH 345/351] Upgrade everything to go1.16 (#1539) Co-authored-by: Ori Newman --- .github/workflows/go.yml | 4 ++-- README.md | 2 +- cmd/kaspactl/README.md | 2 +- cmd/kaspactl/docker/Dockerfile | 2 +- cmd/kaspaminer/README.md | 2 +- cmd/kaspaminer/docker/Dockerfile | 2 +- cmd/wallet/README.md | 2 +- docker/Dockerfile | 2 +- go.mod | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9ac54e3ba..66a59c9ce 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -34,7 +34,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: 1.15 + go-version: 1.16 # Source: https://github.com/actions/cache/blob/main/examples.md#go---modules @@ -60,7 +60,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: 1.15 + go-version: 1.16 - name: Create coverage file run: go test -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./... diff --git a/README.md b/README.md index be2213baf..fa5628220 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Kaspa is an attempt at a proof-of-work cryptocurrency with instant confirmations ## Requirements -Go 1.15 or later. +Go 1.16 or later. ## Installation diff --git a/cmd/kaspactl/README.md b/cmd/kaspactl/README.md index 01f1e2c2b..cf0fcf7b5 100644 --- a/cmd/kaspactl/README.md +++ b/cmd/kaspactl/README.md @@ -4,7 +4,7 @@ kaspactl is an RPC client for kaspad ## Requirements -Go 1.15 or later. +Go 1.16 or later. ## Installation diff --git a/cmd/kaspactl/docker/Dockerfile b/cmd/kaspactl/docker/Dockerfile index 2dae764d4..ada893150 100644 --- a/cmd/kaspactl/docker/Dockerfile +++ b/cmd/kaspactl/docker/Dockerfile @@ -1,5 +1,5 @@ # -- multistage docker build: stage #1: build stage -FROM golang:1.15-alpine AS build +FROM golang:1.16-alpine AS build RUN mkdir -p /go/src/github.com/kaspanet/kaspad diff --git a/cmd/kaspaminer/README.md b/cmd/kaspaminer/README.md index acdd51b5c..26bdfa61f 100644 --- a/cmd/kaspaminer/README.md +++ b/cmd/kaspaminer/README.md @@ -4,7 +4,7 @@ Kaspaminer is a CPU-based miner for kaspad ## Requirements -Go 1.15 or later. +Go 1.16 or later. ## Installation diff --git a/cmd/kaspaminer/docker/Dockerfile b/cmd/kaspaminer/docker/Dockerfile index 3a7758ae2..63356a7e6 100644 --- a/cmd/kaspaminer/docker/Dockerfile +++ b/cmd/kaspaminer/docker/Dockerfile @@ -1,5 +1,5 @@ # -- multistage docker build: stage #1: build stage -FROM golang:1.15-alpine AS build +FROM golang:1.16-alpine AS build RUN mkdir -p /go/src/github.com/kaspanet/kaspad diff --git a/cmd/wallet/README.md b/cmd/wallet/README.md index 36cd5f580..f0d9ce982 100644 --- a/cmd/wallet/README.md +++ b/cmd/wallet/README.md @@ -10,7 +10,7 @@ It is capable of generating wallet key-pairs, printing a wallet's current balanc ## Requirements -Go 1.15 or later. +Go 1.16 or later. ## Installation diff --git a/docker/Dockerfile b/docker/Dockerfile index d67142840..4f17ddf94 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ # -- multistage docker build: stage #1: build stage -FROM golang:1.15-alpine AS build +FROM golang:1.16-alpine AS build RUN mkdir -p /go/src/github.com/kaspanet/kaspad diff --git a/go.mod b/go.mod index 6c95f6940..8cc86ed03 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/kaspanet/kaspad -go 1.15 +go 1.16 require ( github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd From 8fbea5d23900d9c74b45f4668fba654bee66be7e Mon Sep 17 00:00:00 2001 From: Svarog Date: Sun, 21 Feb 2021 11:46:06 +0200 Subject: [PATCH 346/351] Increase the sleep time in kaspaminer when the node is not synced (#1544) Co-authored-by: stasatdaglabs <39559713+stasatdaglabs@users.noreply.github.com> --- cmd/kaspaminer/mineloop.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 281b019ad..f449f4481 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -2,13 +2,14 @@ package main import ( nativeerrors "errors" - "github.com/kaspanet/kaspad/cmd/kaspaminer/templatemanager" - "github.com/kaspanet/kaspad/domain/consensus/model/pow" - "github.com/kaspanet/kaspad/util/difficulty" "math/rand" "sync/atomic" "time" + "github.com/kaspanet/kaspad/cmd/kaspaminer/templatemanager" + "github.com/kaspanet/kaspad/domain/consensus/model/pow" + "github.com/kaspanet/kaspad/util/difficulty" + "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -155,9 +156,13 @@ func mineNextBlock(mineWhenNotSynced bool) *externalapi.DomainBlock { func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock { tryCount := 0 + + const sleepTime = 500 * time.Millisecond + const sleepTimeWhenNotSynced = 5 * time.Second + for { tryCount++ - const sleepTime = 500 * time.Millisecond + shouldLog := (tryCount-1)%10 == 0 template, isSynced := templatemanager.Get() if template == nil { @@ -171,7 +176,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock { if shouldLog { log.Warnf("Kaspad is not synced. Skipping current block template") } - time.Sleep(sleepTime) + time.Sleep(sleepTimeWhenNotSynced) continue } From f66708b3c68aae1757c1e3df4576bc08c4af6057 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 21 Feb 2021 12:15:32 +0200 Subject: [PATCH 347/351] Make the CI more verbose and cache kaspad dependencies in the dockerfile (#1541) * Make the CI more verbose * Improve the docker caching of kaspad dependencies Co-authored-by: Svarog --- .github/workflows/go.yml | 4 ++-- docker/Dockerfile | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 66a59c9ce..0342468de 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -48,7 +48,7 @@ jobs: - name: Test shell: bash - run: ./build_and_test.sh + run: ./build_and_test.sh -v coverage: runs-on: ubuntu-20.04 @@ -63,7 +63,7 @@ jobs: go-version: 1.16 - name: Create coverage file - run: go test -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./... + run: go test -v -covermode=atomic -coverpkg=./... -coverprofile coverage.txt ./... - name: Upload coverage file run: bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 4f17ddf94..a503009d3 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,6 +16,9 @@ RUN go get -u golang.org/x/lint/golint \ COPY go.mod . COPY go.sum . +# Cache kaspad dependencies +RUN go mod download + COPY . . RUN ./build_and_test.sh From a250f697ee589ef4639c4c5b96f1bb28e9f601e5 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sun, 21 Feb 2021 16:09:19 +0200 Subject: [PATCH 348/351] Prevent fast failing (#1545) --- .github/workflows/go-race.yml | 1 + .github/workflows/go.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/go-race.yml b/.github/workflows/go-race.yml index 6f029b32c..50340d35b 100644 --- a/.github/workflows/go-race.yml +++ b/.github/workflows/go-race.yml @@ -9,6 +9,7 @@ jobs: race_test: runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: branch: [ master, latest ] name: Race detection on ${{ matrix.branch }} diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 0342468de..8e646837f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,6 +11,7 @@ jobs: build: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ ubuntu-16.04, macos-10.15 ] name: Testing on on ${{ matrix.os }} From 35e555e9595380a0653ef3bb3e055c421108d48a Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Sun, 21 Feb 2021 17:00:34 +0200 Subject: [PATCH 349/351] Tests validateDifficulty ( ValidatePruningPointViolationAndProofOfWorkAndDifficulty) (#1532) * Adds tests for validateDifficulty * fixes according to the review notes: adding the test's goal and fix an unmatch test name on the NewTestConsensus. * Fixes according to the review notes:delete the function genesisBits - No usages. * Fix according to review - fix comments. Co-authored-by: tal Co-authored-by: Ori Newman --- domain/consensus/constructors.go | 15 ++++- domain/consensus/factory.go | 20 +++++-- ...ation_proof_of_work_and_difficulty_test.go | 60 ++++++++++++++++++- 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/domain/consensus/constructors.go b/domain/consensus/constructors.go index 29b7a2167..81cab3905 100644 --- a/domain/consensus/constructors.go +++ b/domain/consensus/constructors.go @@ -1,6 +1,17 @@ package consensus -import "github.com/kaspanet/kaspad/domain/consensus/model" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "math/big" + "time" +) // GHOSTDAGManagerConstructor is the function signature for a constructor of a type implementing model.GHOSTDAGManager -type GHOSTDAGManagerConstructor func(model.DBReader, model.DAGTopologyManager, model.GHOSTDAGDataStore, model.BlockHeaderStore, model.KType) model.GHOSTDAGManager +type GHOSTDAGManagerConstructor func(model.DBReader, model.DAGTopologyManager, + model.GHOSTDAGDataStore, model.BlockHeaderStore, model.KType) model.GHOSTDAGManager + +// DifficultyManagerConstructor is the function signature for a constructor of a type implementing model.DifficultyManager +type DifficultyManagerConstructor func(model.DBReader, model.GHOSTDAGManager, model.GHOSTDAGDataStore, + model.BlockHeaderStore, model.DAGTopologyManager, model.DAGTraversalManager, *big.Int, int, bool, time.Duration, + *externalapi.DomainHash) model.DifficultyManager diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 52c999e4c..1836a3bfb 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -63,19 +63,22 @@ type Factory interface { SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) SetTestLevelDBCacheSize(cacheSizeMiB int) SetTestPreAllocateCache(preallocateCaches bool) + SetTestDifficultyManager(difficultyConstructor DifficultyManagerConstructor) } type factory struct { - dataDir string - ghostdagConstructor GHOSTDAGManagerConstructor - cacheSizeMiB *int - preallocateCaches *bool + dataDir string + ghostdagConstructor GHOSTDAGManagerConstructor + difficultyConstructor DifficultyManagerConstructor + cacheSizeMiB *int + preallocateCaches *bool } // NewFactory creates a new Consensus factory func NewFactory() Factory { return &factory{ - ghostdagConstructor: ghostdagmanager.New, + ghostdagConstructor: ghostdagmanager.New, + difficultyConstructor: difficultymanager.New, } } @@ -159,7 +162,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat dbManager, pastMedianTimeManager, ghostdagDataStore) - difficultyManager := difficultymanager.New( + difficultyManager := f.difficultyConstructor( dbManager, ghostdagManager, ghostdagDataStore, @@ -466,6 +469,11 @@ func (f *factory) SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerCons f.ghostdagConstructor = ghostdagConstructor } +// SetTestDifficultyManager is a setter for the difficultyManager field on the factory. +func (f *factory) SetTestDifficultyManager(difficultyConstructor DifficultyManagerConstructor) { + f.difficultyConstructor = difficultyConstructor +} + func (f *factory) SetTestLevelDBCacheSize(cacheSizeMiB int) { f.cacheSizeMiB = &cacheSizeMiB } diff --git a/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go b/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go index a78d355dc..9a785ed8a 100644 --- a/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go +++ b/domain/consensus/processes/blockvalidator/pruning_violation_proof_of_work_and_difficulty_test.go @@ -1,6 +1,7 @@ package blockvalidator_test import ( + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/pow" "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" "github.com/kaspanet/kaspad/domain/consensus/utils/blockheader" @@ -12,8 +13,8 @@ import ( "math" "math/big" "math/rand" - "testing" + "time" "github.com/kaspanet/kaspad/domain/consensus" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" @@ -241,3 +242,60 @@ func TestCheckPruningPointViolation(t *testing.T) { } }) } + +// TestValidateDifficulty verifies that in case of a block with an unexpected difficulty, +// an appropriate error message (ErrUnexpectedDifficulty) will be returned on the +// function ValidatePruningPointViolationAndProofOfWorkAndDifficulty. The required difficulty is +// "calculated" by the function (dm *mocDifficultyManager) RequiredDifficulty , +// where mocDifficultyManager is special implementation of the type DifficultyManager for this test (defined below). +func TestValidateDifficulty(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + mocDifficulty := &mocDifficultyManager{} + factory.SetTestDifficultyManager(func(model.DBReader, model.GHOSTDAGManager, model.GHOSTDAGDataStore, + model.BlockHeaderStore, model.DAGTopologyManager, model.DAGTraversalManager, *big.Int, int, bool, time.Duration, + *externalapi.DomainHash) model.DifficultyManager { + return mocDifficulty + }) + genesisDifficulty := params.GenesisBlock.Header.Bits() + mocDifficulty.testDifficulty = genesisDifficulty + mocDifficulty.testGenesisBits = genesisDifficulty + tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateDifficulty") + if err != nil { + t.Fatalf("Error setting up consensus: %+v", err) + } + defer teardown(false) + + emptyCoinbase := externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } + block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, nil) + if err != nil { + t.Fatalf("TestValidateDifficulty: Failed build block with parents: %v.", err) + } + blockHash := consensushashing.BlockHash(block) + tc.BlockStore().Stage(blockHash, block) + tc.BlockHeaderStore().Stage(blockHash, block.Header) + wrongTestDifficulty := mocDifficulty.testDifficulty + uint32(5) + mocDifficulty.testDifficulty = wrongTestDifficulty + + err = tc.BlockValidator().ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash) + if err == nil || !errors.Is(err, ruleerrors.ErrUnexpectedDifficulty) { + t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrUnexpectedDifficulty, err) + } + }) +} + +type mocDifficultyManager struct { + testDifficulty uint32 + testGenesisBits uint32 +} + +// RequiredDifficulty returns the difficulty required for the test +func (dm *mocDifficultyManager) RequiredDifficulty(*externalapi.DomainHash) (uint32, error) { + return dm.testDifficulty, nil +} From a7bb1853f9cf12c25a233439fc82d9f952e28cb5 Mon Sep 17 00:00:00 2001 From: talelbaz <63008512+talelbaz@users.noreply.github.com> Date: Sun, 21 Feb 2021 17:46:22 +0200 Subject: [PATCH 350/351] Adds tests for transaction validator and block validators (#1531) * [NOD-1453] cover failing block validation * [NOD-1453] Complete covering test for invalid block * [NOD-1453] Fix validator tests after rebase * [NOD-1453] Cover tests for valid blocks * [NOD-1453] Implement unit tests for ValidateTransactionInIsolation * [NOD-1453] Add tests for ValidateTransactionInContextAndPopulateMassAndFee * [NOD-1453] Cover ValidateHeaderInContext test * [NOD-1453] Fix after rebase * not finish * commited for update the branch. * Adds new tests to block_body_in_isolation_test.go according to (and instead of ) blockvalisator_test.go * Adds a comment to type MEDIAN. * Fixes according to the review notes: add notes and change variables name. * Fix comment. * Remove an unused test( all the tests in this file were passed to other test files). * Change a variable name(txWithAnEmptyInvalidScript to txWithInvalidSignature). * adds missing '}'. * Change spaces to tab Co-authored-by: karim1king Co-authored-by: Karim A Co-authored-by: tal --- domain/consensus/constructors.go | 4 + domain/consensus/factory.go | 23 +- .../block_body_in_isolation_test.go | 326 +++++++++++++++++- .../transactionvalidator_test.go | 251 ++++++++++++++ 4 files changed, 589 insertions(+), 15 deletions(-) create mode 100644 domain/consensus/processes/transactionvalidator/transactionvalidator_test.go diff --git a/domain/consensus/constructors.go b/domain/consensus/constructors.go index 81cab3905..38b91ed89 100644 --- a/domain/consensus/constructors.go +++ b/domain/consensus/constructors.go @@ -15,3 +15,7 @@ type GHOSTDAGManagerConstructor func(model.DBReader, model.DAGTopologyManager, type DifficultyManagerConstructor func(model.DBReader, model.GHOSTDAGManager, model.GHOSTDAGDataStore, model.BlockHeaderStore, model.DAGTopologyManager, model.DAGTraversalManager, *big.Int, int, bool, time.Duration, *externalapi.DomainHash) model.DifficultyManager + +// PastMedianTimeManagerConstructor is the function signature for a constructor of a type implementing model.PastMedianTimeManager +type PastMedianTimeManagerConstructor func(int, model.DBReader, model.DAGTraversalManager, model.BlockHeaderStore, + model.GHOSTDAGDataStore) model.PastMedianTimeManager diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 1836a3bfb..c609159e5 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -63,22 +63,25 @@ type Factory interface { SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) SetTestLevelDBCacheSize(cacheSizeMiB int) SetTestPreAllocateCache(preallocateCaches bool) + SetTestPastMedianTimeManager(medianTimeConstructor PastMedianTimeManagerConstructor) SetTestDifficultyManager(difficultyConstructor DifficultyManagerConstructor) } type factory struct { - dataDir string - ghostdagConstructor GHOSTDAGManagerConstructor - difficultyConstructor DifficultyManagerConstructor - cacheSizeMiB *int - preallocateCaches *bool + dataDir string + ghostdagConstructor GHOSTDAGManagerConstructor + pastMedianTimeConsructor PastMedianTimeManagerConstructor + difficultyConstructor DifficultyManagerConstructor + cacheSizeMiB *int + preallocateCaches *bool } // NewFactory creates a new Consensus factory func NewFactory() Factory { return &factory{ - ghostdagConstructor: ghostdagmanager.New, - difficultyConstructor: difficultymanager.New, + ghostdagConstructor: ghostdagmanager.New, + pastMedianTimeConsructor: pastmediantimemanager.New, + difficultyConstructor: difficultymanager.New, } } @@ -147,7 +150,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat reachabilityDataStore, ghostdagManager, consensusStateStore) - pastMedianTimeManager := pastmediantimemanager.New( + pastMedianTimeManager := f.pastMedianTimeConsructor( dagParams.TimestampDeviationTolerance, dbManager, dagTraversalManager, @@ -469,6 +472,10 @@ func (f *factory) SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerCons f.ghostdagConstructor = ghostdagConstructor } +func (f *factory) SetTestPastMedianTimeManager(medianTimeConstructor PastMedianTimeManagerConstructor) { + f.pastMedianTimeConsructor = medianTimeConstructor +} + // SetTestDifficultyManager is a setter for the difficultyManager field on the factory. func (f *factory) SetTestDifficultyManager(difficultyConstructor DifficultyManagerConstructor) { f.difficultyConstructor = difficultyConstructor diff --git a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go index 847ab3a0d..b7e375626 100644 --- a/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go +++ b/domain/consensus/processes/blockvalidator/block_body_in_isolation_test.go @@ -1,6 +1,12 @@ package blockvalidator_test import ( + "bytes" + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/testapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/merkle" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "math" "testing" @@ -84,7 +90,7 @@ func TestChainedTransactions(t *testing.T) { func TestCheckBlockSanity(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { factory := consensus.NewFactory() - consensus, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockSanity") + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockSanity") if err != nil { t.Fatalf("Error setting up consensus: %+v", err) } @@ -94,17 +100,17 @@ func TestCheckBlockSanity(t *testing.T) { t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions)) } - consensus.BlockStore().Stage(blockHash, &exampleValidBlock) + tc.BlockStore().Stage(blockHash, &exampleValidBlock) - err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) if err != nil { t.Fatalf("Failed validating block in isolation: %v", err) } // Test with block with wrong transactions sorting order blockHash = consensushashing.BlockHash(&blockWithWrongTxOrder) - consensus.BlockStore().Stage(blockHash, &blockWithWrongTxOrder) - err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) + tc.BlockStore().Stage(blockHash, &blockWithWrongTxOrder) + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) { t.Errorf("CheckBlockSanity: Expected ErrTransactionsNotSorted error, instead got %v", err) } @@ -112,8 +118,8 @@ func TestCheckBlockSanity(t *testing.T) { // Test a block with invalid parents order // We no longer require blocks to have ordered parents blockHash = consensushashing.BlockHash(&unOrderedParentsBlock) - consensus.BlockStore().Stage(blockHash, &unOrderedParentsBlock) - err = consensus.BlockValidator().ValidateBodyInIsolation(blockHash) + tc.BlockStore().Stage(blockHash, &unOrderedParentsBlock) + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) if err != nil { t.Errorf("CheckBlockSanity: Expected block to be be body in isolation valid, got error instead: %v", err) } @@ -1034,3 +1040,309 @@ func TestCheckBlockHashMerkleRoot(t *testing.T) { } }) } + +func TestBlockSize(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestBlockSize") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + block, _, err := initBlockWithInvalidBlockSize(params, tc) + if err != nil { + t.Fatalf("Error BuildBlockWithParents : %+v", err) + } + blockHash := consensushashing.BlockHash(block) + tc.BlockStore().Stage(blockHash, block) + + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) + if err == nil || !errors.Is(err, ruleerrors.ErrBlockSizeTooHigh) { + t.Fatalf("ValidateBodyInIsolationTest: TestBlockSize:"+ + " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrBlockSizeTooHigh, err) + } + }) +} + +func initBlockWithInvalidBlockSize(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, model.UTXODiff, error) { + emptyCoinbase := externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } + prevOutTxID := &externalapi.DomainTransactionID{} + prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} + bigSignatureScript := bytes.Repeat([]byte("01"), 25000) + txInput := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: bigSignatureScript, + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, + &externalapi.ScriptPublicKey{}, + true, + uint64(5)), + } + tx := &externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + PayloadHash: *externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + Payload: []byte{0x01}, + } + + return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx}) +} + +func TestCheckBlockDuplicateTransactions(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockDuplicateTransactions") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + block, _, err := initBlockWithDuplicateTransaction(params, tc) + if err != nil { + t.Fatalf("Error BuildBlockWithParents : %+v", err) + } + blockHash := consensushashing.BlockHash(block) + tc.BlockStore().Stage(blockHash, block) + + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) + if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateTx) { + t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockDuplicateTransactions:"+ + " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrDuplicateTx, err) + } + }) +} + +func initBlockWithDuplicateTransaction(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, model.UTXODiff, error) { + emptyCoinbase := externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } + prevOutTxID := &externalapi.DomainTransactionID{} + prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} + txInput := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: bytes.Repeat([]byte("01"), 10), + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, + &externalapi.ScriptPublicKey{}, + true, + uint64(5)), + } + tx := &externalapi.DomainTransaction{ + Version: 0, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + SubnetworkID: subnetworks.SubnetworkIDNative, + } + + return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx, tx}) +} + +func TestCheckBlockContainsOnlyOneCoinbase(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockContainsOnlyOneCoinbase") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + block, _, err := initBlockWithMoreThanOneCoinbase(params, tc) + if err != nil { + t.Fatalf("Error BuildBlockWithParents : %+v", err) + } + blockHash := consensushashing.BlockHash(block) + tc.BlockStore().Stage(blockHash, block) + + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) + if err == nil || !errors.Is(err, ruleerrors.ErrMultipleCoinbases) { + t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockContainsOnlyOneCoinbase:"+ + " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrMultipleCoinbases, err) + } + }) +} + +func initBlockWithMoreThanOneCoinbase(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, model.UTXODiff, error) { + emptyCoinbase := externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } + prevOutTxID := &externalapi.DomainTransactionID{} + prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} + txInput := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: bytes.Repeat([]byte("01"), 10), + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, + &externalapi.ScriptPublicKey{}, + true, + uint64(5)), + } + tx := &externalapi.DomainTransaction{ + Version: 0, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + SubnetworkID: subnetworks.SubnetworkIDCoinbase, + } + + return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx}) +} + +func TestCheckBlockDoubleSpends(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockDoubleSpends") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + block, _, err := initBlockWithDoubleSpends(params, tc) + if err != nil { + t.Fatalf("Error BuildBlockWithParents : %+v", err) + } + blockHash := consensushashing.BlockHash(block) + tc.BlockStore().Stage(blockHash, block) + + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) + if err == nil || !errors.Is(err, ruleerrors.ErrDoubleSpendInSameBlock) { + t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockDoubleSpends:"+ + " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrDoubleSpendInSameBlock, err) + } + }) +} + +func initBlockWithDoubleSpends(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, model.UTXODiff, error) { + emptyCoinbase := externalapi.DomainCoinbaseData{ + ScriptPublicKey: &externalapi.ScriptPublicKey{ + Script: nil, + Version: 0, + }, + } + prevOutTxID := &externalapi.DomainTransactionID{} + prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} + txInput := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: bytes.Repeat([]byte("01"), 10), + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, + &externalapi.ScriptPublicKey{}, + true, + uint64(5)), + } + tx := &externalapi.DomainTransaction{ + Version: 0, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + SubnetworkID: subnetworks.SubnetworkIDNative, + } + txInputSameOutpoint := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: bytes.Repeat([]byte("02"), 10), + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, + &externalapi.ScriptPublicKey{}, + true, + uint64(4)), + } + txSameOutpoint := &externalapi.DomainTransaction{ + Version: 0, + Inputs: []*externalapi.DomainTransactionInput{&txInputSameOutpoint}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + SubnetworkID: subnetworks.SubnetworkIDNative, + } + + return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, + &emptyCoinbase, []*externalapi.DomainTransaction{tx, txSameOutpoint}) +} + +func TestCheckFirstBlockTransactionIsCoinbase(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckFirstBlockTransactionIsCoinbase") + if err != nil { + t.Fatalf("Error setting up tc: %+v", err) + } + defer teardown(false) + + block := initBlockWithFirstTransactionDifferentThanCoinbase(params) + blockHash := consensushashing.BlockHash(block) + tc.BlockStore().Stage(blockHash, block) + + err = tc.BlockValidator().ValidateBodyInIsolation(blockHash) + if err == nil || !errors.Is(err, ruleerrors.ErrFirstTxNotCoinbase) { + t.Fatalf("ValidateBodyInIsolationTest: TestCheckFirstBlockTransactionIsCoinbase:"+ + " Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrFirstTxNotCoinbase, err) + } + }) +} + +func initBlockWithFirstTransactionDifferentThanCoinbase(params *dagconfig.Params) *externalapi.DomainBlock { + prevOutTxID := &externalapi.DomainTransactionID{} + prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} + txInput := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: bytes.Repeat([]byte("01"), 10), + Sequence: constants.MaxTxInSequenceNum, + } + tx := &externalapi.DomainTransaction{ + Version: 0, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{{uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 2}, Version: 0}}, {uint64(0xFFFF), + &externalapi.ScriptPublicKey{Script: []byte{1, 3}, Version: 0}}}, + SubnetworkID: subnetworks.SubnetworkIDNative, + } + + return &externalapi.DomainBlock{ + Header: blockheader.NewImmutableBlockHeader( + constants.MaxBlockVersion, + []*externalapi.DomainHash{params.GenesisHash}, + merkle.CalculateHashMerkleRoot([]*externalapi.DomainTransaction{tx}), + &externalapi.DomainHash{}, + externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{ + 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, + 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, + 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, + 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, + }), + 0x5cd18053000, + 0x207fffff, + 0x1), + Transactions: []*externalapi.DomainTransaction{tx}, + } +} diff --git a/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go b/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go new file mode 100644 index 000000000..4b8bf8412 --- /dev/null +++ b/domain/consensus/processes/transactionvalidator/transactionvalidator_test.go @@ -0,0 +1,251 @@ +package transactionvalidator_test + +import ( + "github.com/kaspanet/go-secp256k1" + "github.com/kaspanet/kaspad/domain/consensus" + "github.com/kaspanet/kaspad/domain/consensus/ruleerrors" + "github.com/kaspanet/kaspad/domain/consensus/utils/testutils" + "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" + "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" + "github.com/kaspanet/kaspad/util" + + "math/big" + + "testing" + + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/constants" + "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/pkg/errors" +) + +type mocPastMedianTimeManager struct { + pastMedianTimeForTest int64 +} + +// PastMedianTime returns the past median time for the test. +func (mdf *mocPastMedianTimeManager) PastMedianTime(*externalapi.DomainHash) (int64, error) { + return mdf.pastMedianTimeForTest, nil +} + +func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) { + testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { + + factory := consensus.NewFactory() + pastMedianManager := &mocPastMedianTimeManager{} + factory.SetTestPastMedianTimeManager(func(int, model.DBReader, model.DAGTraversalManager, model.BlockHeaderStore, + model.GHOSTDAGDataStore) model.PastMedianTimeManager { + return pastMedianManager + }) + tc, tearDown, err := factory.NewTestConsensus(params, false, + "TestValidateTransactionInContextAndPopulateMassAndFee") + if err != nil { + t.Fatalf("Failed create a NewTestConsensus: %s", err) + } + defer tearDown(false) + + pastMedianManager.pastMedianTimeForTest = 1 + privateKey, err := secp256k1.GeneratePrivateKey() + if err != nil { + t.Fatalf("Failed to generate a private key: %v", err) + } + publicKey, err := privateKey.SchnorrPublicKey() + if err != nil { + t.Fatalf("Failed to generate a public key: %v", err) + } + publicKeySerialized, err := publicKey.Serialize() + if err != nil { + t.Fatalf("Failed to serialize public key: %v", err) + } + addr, err := util.NewAddressPubKeyHashFromPublicKey(publicKeySerialized[:], params.Prefix) + if err != nil { + t.Fatalf("Failed to generate p2pkh address: %v", err) + } + scriptPublicKey, err := txscript.PayToAddrScript(addr) + if err != nil { + t.Fatalf("PayToAddrScript: unexpected error: %v", err) + } + prevOutTxID := &externalapi.DomainTransactionID{} + prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1} + + txInput := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: []byte{}, + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + 100_000_000, // 1 KAS + scriptPublicKey, + true, + uint64(5)), + } + txInputWithMaxSequence := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: []byte{}, + Sequence: constants.SequenceLockTimeIsSeconds, + UTXOEntry: utxo.NewUTXOEntry( + 100000000, // 1 KAS + scriptPublicKey, + true, + uint64(5)), + } + txInputWithLargeAmount := externalapi.DomainTransactionInput{ + PreviousOutpoint: prevOutPoint, + SignatureScript: []byte{}, + Sequence: constants.MaxTxInSequenceNum, + UTXOEntry: utxo.NewUTXOEntry( + constants.MaxSompi, + scriptPublicKey, + true, + uint64(5)), + } + + txOut := externalapi.DomainTransactionOutput{ + Value: 100000000, // 1 KAS + ScriptPublicKey: scriptPublicKey, + } + txOutBigValue := externalapi.DomainTransactionOutput{ + Value: 200_000_000, // 2 KAS + ScriptPublicKey: scriptPublicKey, + } + + validTx := externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInputWithMaxSequence}, + Outputs: []*externalapi.DomainTransactionOutput{&txOut}, + SubnetworkID: subnetworks.SubnetworkIDRegistry, + Gas: 0, + LockTime: 0} + txWithImmatureCoinbase := externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{&txOut}, + SubnetworkID: subnetworks.SubnetworkIDRegistry, + Gas: 0, + LockTime: 0} + txWithLargeAmount := externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInput, &txInputWithLargeAmount}, + Outputs: []*externalapi.DomainTransactionOutput{&txOut}, + SubnetworkID: subnetworks.SubnetworkIDRegistry, + Gas: 0, + LockTime: 0} + txWithBigValue := externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{&txOutBigValue}, + SubnetworkID: subnetworks.SubnetworkIDRegistry, + Gas: 0, + LockTime: 0} + txWithInvalidSignature := externalapi.DomainTransaction{ + Version: constants.MaxTransactionVersion, + Inputs: []*externalapi.DomainTransactionInput{&txInput}, + Outputs: []*externalapi.DomainTransactionOutput{&txOut}, + SubnetworkID: subnetworks.SubnetworkIDRegistry, + Gas: 0, + LockTime: 0} + + for i, input := range validTx.Inputs { + signatureScript, err := txscript.SignatureScript(&validTx, i, scriptPublicKey, txscript.SigHashAll, privateKey) + if err != nil { + t.Fatalf("Failed to create a sigScript: %v", err) + } + input.SignatureScript = signatureScript + } + + povBlockHash := externalapi.NewDomainHashFromByteArray(&[32]byte{0x01}) + genesisHash := params.GenesisHash + tc.GHOSTDAGDataStore().Stage(model.VirtualBlockHash, model.NewBlockGHOSTDAGData( + params.BlockCoinbaseMaturity+txInput.UTXOEntry.BlockBlueScore(), + new(big.Int), + genesisHash, + make([]*externalapi.DomainHash, 1000), + make([]*externalapi.DomainHash, 1), + nil)) + tc.GHOSTDAGDataStore().Stage(povBlockHash, model.NewBlockGHOSTDAGData( + 10, + new(big.Int), + genesisHash, + make([]*externalapi.DomainHash, 1000), + make([]*externalapi.DomainHash, 1), + nil)) + + tests := []struct { + name string + tx *externalapi.DomainTransaction + povBlockHash *externalapi.DomainHash + selectedParentMedianTime int64 + isValid bool + expectedError error + }{ + { + name: "Valid transaction", + tx: &validTx, + povBlockHash: model.VirtualBlockHash, + selectedParentMedianTime: 1, + isValid: true, + expectedError: nil, + }, + { // The calculated block coinbase maturity is smaller than the minimum expected blockCoinbaseMaturity. + // The povBlockHash blue score is 10 and the UTXO blue score is 5, hence the The subtraction between + // them will yield a smaller result than the required CoinbaseMaturity (currently set to 100). + name: "checkTransactionCoinbaseMaturity", + tx: &txWithImmatureCoinbase, + povBlockHash: povBlockHash, + selectedParentMedianTime: 1, + isValid: false, + expectedError: ruleerrors.ErrImmatureSpend, + }, + { // The total inputs amount is bigger than the allowed maximum (constants.MaxSompi) + name: "checkTransactionInputAmounts", + tx: &txWithLargeAmount, + povBlockHash: model.VirtualBlockHash, + selectedParentMedianTime: 1, + isValid: false, + expectedError: ruleerrors.ErrBadTxOutValue, + }, + { // The total SompiIn (sum of inputs amount) is smaller than the total SompiOut (sum of outputs value) and hence invalid. + name: "checkTransactionOutputAmounts", + tx: &txWithBigValue, + povBlockHash: model.VirtualBlockHash, + selectedParentMedianTime: 1, + isValid: false, + expectedError: ruleerrors.ErrSpendTooHigh, + }, + { // the selectedParentMedianTime is negative and hence invalid. + name: "checkTransactionSequenceLock", + tx: &validTx, + povBlockHash: model.VirtualBlockHash, + selectedParentMedianTime: -1, + isValid: false, + expectedError: ruleerrors.ErrUnfinalizedTx, + }, + { // The SignatureScript (in the txInput) is empty and hence invalid. + name: "checkTransactionScripts", + tx: &txWithInvalidSignature, + povBlockHash: model.VirtualBlockHash, + selectedParentMedianTime: 1, + isValid: false, + expectedError: ruleerrors.ErrScriptValidation, + }, + } + + for _, test := range tests { + err := tc.TransactionValidator().ValidateTransactionInContextAndPopulateMassAndFee(test.tx, + test.povBlockHash, test.selectedParentMedianTime) + + if test.isValid { + if err != nil { + t.Fatalf("Unexpected error on TestValidateTransactionInContextAndPopulateMassAndFee"+ + " on test %v: %v", test.name, err) + } + } else { + if err == nil || !errors.Is(err, test.expectedError) { + t.Fatalf("TestValidateTransactionInContextAndPopulateMassAndFee: test %v:"+ + " Unexpected error: Expected to: %v, but got : %v", test.name, test.expectedError, err) + } + } + } + }) +} From bee0893660e26bd9ee2abc739c146172244fff44 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 22 Feb 2021 11:33:39 +0200 Subject: [PATCH 351/351] Renamed BlueBlockWindow to just BlockWindow (#1547) * Renamed BlueBlockWindow to just BlockWindow * Update comment --- .../interface_processes_dagtraversalmanager.go | 2 +- .../processes/dagtraversalmanager/window.go | 8 ++++---- .../dagtraversalmanager/window_test.go | 8 ++++---- .../processes/difficultymanager/blockwindow.go | 17 +++++++++-------- .../difficultymanager/difficultymanager.go | 5 +++-- .../pastmediantimemanager.go | 2 +- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/domain/consensus/model/interface_processes_dagtraversalmanager.go b/domain/consensus/model/interface_processes_dagtraversalmanager.go index 9f06135d8..9101da297 100644 --- a/domain/consensus/model/interface_processes_dagtraversalmanager.go +++ b/domain/consensus/model/interface_processes_dagtraversalmanager.go @@ -11,7 +11,7 @@ type DAGTraversalManager interface { // from lowHash (exclusive) to highHash (inclusive) over highHash's selected parent chain SelectedChildIterator(highHash, lowHash *externalapi.DomainHash) (BlockIterator, error) Anticone(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) - BlueWindow(highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) + BlockWindow(highHash *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) NewDownHeap() BlockHeap NewUpHeap() BlockHeap CalculateChainPath( diff --git a/domain/consensus/processes/dagtraversalmanager/window.go b/domain/consensus/processes/dagtraversalmanager/window.go index a8d806a78..cff3f6906 100644 --- a/domain/consensus/processes/dagtraversalmanager/window.go +++ b/domain/consensus/processes/dagtraversalmanager/window.go @@ -4,11 +4,11 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) -// blueBlockWindow returns a blockWindow of the given size that contains the -// blues in the past of startindNode, the sorting is unspecified. -// If the number of blues in the past of startingNode is less then windowSize, +// BlockWindow returns a blockWindow of the given size that contains the +// blocks in the past of startindNode, the sorting is unspecified. +// If the number of blocks in the past of startingNode is less then windowSize, // the window will be padded by genesis blocks to achieve a size of windowSize. -func (dtm *dagTraversalManager) BlueWindow(startingBlock *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) { +func (dtm *dagTraversalManager) BlockWindow(startingBlock *externalapi.DomainHash, windowSize int) ([]*externalapi.DomainHash, error) { currentHash := startingBlock currentGHOSTDAGData, err := dtm.ghostdagDataStore.Get(dtm.databaseContext, currentHash) if err != nil { diff --git a/domain/consensus/processes/dagtraversalmanager/window_test.go b/domain/consensus/processes/dagtraversalmanager/window_test.go index 399e434a7..5f4db12c2 100644 --- a/domain/consensus/processes/dagtraversalmanager/window_test.go +++ b/domain/consensus/processes/dagtraversalmanager/window_test.go @@ -13,7 +13,7 @@ import ( "github.com/pkg/errors" ) -func TestBlueBlockWindow(t *testing.T) { +func TestBlockWindow(t *testing.T) { tests := map[string][]*struct { parents []string id string //id is a virtual entity that is used only for tests so we can define relations between blocks without knowing their hash @@ -311,7 +311,7 @@ func TestBlueBlockWindow(t *testing.T) { testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) { params.K = 1 factory := consensus.NewFactory() - tc, tearDown, err := factory.NewTestConsensus(params, false, "TestBlueBlockWindow") + tc, tearDown, err := factory.NewTestConsensus(params, false, "TestBlockWindow") if err != nil { t.Fatalf("NewTestConsensus: %s", err) } @@ -340,9 +340,9 @@ func TestBlueBlockWindow(t *testing.T) { blockByIDMap[blockData.id] = block idByBlockMap[*block] = blockData.id - window, err := tc.DAGTraversalManager().BlueWindow(block, windowSize) + window, err := tc.DAGTraversalManager().BlockWindow(block, windowSize) if err != nil { - t.Fatalf("BlueWindow: %s", err) + t.Fatalf("BlockWindow: %s", err) } sort.Sort(testutils.NewTestGhostDAGSorter(window, tc, t)) if err := checkWindowIDs(window, blockData.expectedWindowWithGenesisPadding, idByBlockMap); err != nil { diff --git a/domain/consensus/processes/difficultymanager/blockwindow.go b/domain/consensus/processes/difficultymanager/blockwindow.go index d6c685c93..f73d4c14e 100644 --- a/domain/consensus/processes/difficultymanager/blockwindow.go +++ b/domain/consensus/processes/difficultymanager/blockwindow.go @@ -1,12 +1,13 @@ package difficultymanager import ( - "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" - "github.com/kaspanet/kaspad/util/difficulty" - "github.com/pkg/errors" "math" "math/big" "sort" + + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/util/difficulty" + "github.com/pkg/errors" ) type difficultyBlock struct { @@ -27,13 +28,13 @@ func (dm *difficultyManager) getDifficultyBlock(blockHash *externalapi.DomainHas }, nil } -// blueBlockWindow returns a blockWindow of the given size that contains the -// blues in the past of startindNode, the sorting is unspecified. -// If the number of blues in the past of startingNode is less then windowSize, +// blockWindow returns a blockWindow of the given size that contains the +// blocks in the past of startindNode, the sorting is unspecified. +// If the number of blocks in the past of startingNode is less then windowSize, // the window will be padded by genesis blocks to achieve a size of windowSize. -func (dm *difficultyManager) blueBlockWindow(startingNode *externalapi.DomainHash, windowSize int) (blockWindow, error) { +func (dm *difficultyManager) blockWindow(startingNode *externalapi.DomainHash, windowSize int) (blockWindow, error) { window := make(blockWindow, 0, windowSize) - windowHashes, err := dm.dagTraversalManager.BlueWindow(startingNode, windowSize) + windowHashes, err := dm.dagTraversalManager.BlockWindow(startingNode, windowSize) if err != nil { return nil, err } diff --git a/domain/consensus/processes/difficultymanager/difficultymanager.go b/domain/consensus/processes/difficultymanager/difficultymanager.go index 15a6c33ca..003c85969 100644 --- a/domain/consensus/processes/difficultymanager/difficultymanager.go +++ b/domain/consensus/processes/difficultymanager/difficultymanager.go @@ -1,10 +1,11 @@ package difficultymanager import ( - "github.com/kaspanet/kaspad/util/difficulty" "math/big" "time" + "github.com/kaspanet/kaspad/util/difficulty" + "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) @@ -88,7 +89,7 @@ func (dm *difficultyManager) RequiredDifficulty(blockHash *externalapi.DomainHas } // Fetch window of dag.difficultyAdjustmentWindowSize + 1 so we can have dag.difficultyAdjustmentWindowSize block intervals - targetsWindow, err := dm.blueBlockWindow(bluestParent, dm.difficultyAdjustmentWindowSize+1) + targetsWindow, err := dm.blockWindow(bluestParent, dm.difficultyAdjustmentWindowSize+1) if err != nil { return 0, err } diff --git a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go index a8b3e94bf..4fdd8ee71 100644 --- a/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go +++ b/domain/consensus/processes/pastmediantimemanager/pastmediantimemanager.go @@ -57,7 +57,7 @@ func (pmtm *pastMedianTimeManager) PastMedianTime(blockHash *externalapi.DomainH return header.TimeInMilliseconds(), nil } - window, err := pmtm.dagTraversalManager.BlueWindow(selectedParentHash, 2*pmtm.timestampDeviationTolerance-1) + window, err := pmtm.dagTraversalManager.BlockWindow(selectedParentHash, 2*pmtm.timestampDeviationTolerance-1) if err != nil { return 0, err }